Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : tstream based generic authentication interface
5 :
6 : Copyright (c) 2010 Stefan Metzmacher
7 : Copyright (c) 2010 Andreas Schneider <asn@redhat.com>
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "system/network.h"
25 : #include "auth/gensec/gensec.h"
26 : #include "auth/gensec/gensec_proto.h"
27 : #include "auth/gensec/gensec_tstream.h"
28 : #include "lib/tsocket/tsocket.h"
29 : #include "lib/tsocket/tsocket_internal.h"
30 : #include "auth/gensec/gensec_toplevel_proto.h"
31 :
32 : static const struct tstream_context_ops tstream_gensec_ops;
33 :
34 : struct tstream_gensec {
35 : struct tstream_context *plain_stream;
36 :
37 : struct gensec_security *gensec_security;
38 :
39 : int error;
40 :
41 : struct {
42 : size_t max_unwrapped_size;
43 : size_t max_wrapped_size;
44 : } write;
45 :
46 : struct {
47 : off_t ofs;
48 : size_t left;
49 : DATA_BLOB unwrapped;
50 : } read;
51 : };
52 :
53 51029 : _PUBLIC_ NTSTATUS _gensec_create_tstream(TALLOC_CTX *mem_ctx,
54 : struct gensec_security *gensec_security,
55 : struct tstream_context *plain_stream,
56 : struct tstream_context **_gensec_stream,
57 : const char *location)
58 : {
59 244 : struct tstream_context *gensec_stream;
60 244 : struct tstream_gensec *tgss;
61 :
62 51029 : gensec_stream = tstream_context_create(mem_ctx,
63 : &tstream_gensec_ops,
64 : &tgss,
65 : struct tstream_gensec,
66 : location);
67 51029 : if (gensec_stream == NULL) {
68 0 : return NT_STATUS_NO_MEMORY;
69 : }
70 :
71 51029 : tgss->plain_stream = plain_stream;
72 51029 : tgss->gensec_security = gensec_security;
73 51029 : tgss->error = 0;
74 :
75 51029 : if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN) &&
76 0 : !gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
77 0 : talloc_free(gensec_stream);
78 0 : return NT_STATUS_INVALID_PARAMETER;
79 : }
80 :
81 51029 : tgss->write.max_unwrapped_size = gensec_max_input_size(gensec_security);
82 51029 : tgss->write.max_wrapped_size = gensec_max_wrapped_size(gensec_security);
83 :
84 51029 : ZERO_STRUCT(tgss->read);
85 :
86 51029 : *_gensec_stream = gensec_stream;
87 51029 : return NT_STATUS_OK;
88 : }
89 :
90 104 : static ssize_t tstream_gensec_pending_bytes(struct tstream_context *stream)
91 : {
92 0 : struct tstream_gensec *tgss =
93 104 : tstream_context_data(stream,
94 : struct tstream_gensec);
95 :
96 104 : if (tgss->error != 0) {
97 0 : errno = tgss->error;
98 0 : return -1;
99 : }
100 :
101 104 : return tgss->read.left;
102 : }
103 :
104 : struct tstream_gensec_readv_state {
105 : struct tevent_context *ev;
106 : struct tstream_context *stream;
107 :
108 : struct iovec *vector;
109 : int count;
110 :
111 : struct {
112 : bool asked_for_hdr;
113 : uint8_t hdr[4];
114 : bool asked_for_blob;
115 : DATA_BLOB blob;
116 : } wrapped;
117 :
118 : int ret;
119 : };
120 :
121 : static void tstream_gensec_readv_wrapped_next(struct tevent_req *req);
122 :
123 3587675 : static struct tevent_req *tstream_gensec_readv_send(TALLOC_CTX *mem_ctx,
124 : struct tevent_context *ev,
125 : struct tstream_context *stream,
126 : struct iovec *vector,
127 : size_t count)
128 : {
129 2552 : struct tstream_gensec *tgss =
130 3587675 : tstream_context_data(stream,
131 : struct tstream_gensec);
132 2552 : struct tevent_req *req;
133 2552 : struct tstream_gensec_readv_state *state;
134 :
135 3587675 : req = tevent_req_create(mem_ctx, &state,
136 : struct tstream_gensec_readv_state);
137 3587675 : if (!req) {
138 0 : return NULL;
139 : }
140 :
141 3587675 : if (tgss->error != 0) {
142 0 : tevent_req_error(req, tgss->error);
143 0 : return tevent_req_post(req, ev);
144 : }
145 :
146 3587675 : state->ev = ev;
147 3587675 : state->stream = stream;
148 3587675 : state->ret = 0;
149 :
150 : /*
151 : * we make a copy of the vector so we can change the structure
152 : */
153 3587675 : state->vector = talloc_array(state, struct iovec, count);
154 3587675 : if (tevent_req_nomem(state->vector, req)) {
155 0 : return tevent_req_post(req, ev);
156 : }
157 3587675 : memcpy(state->vector, vector, sizeof(struct iovec) * count);
158 3587675 : state->count = count;
159 :
160 3587675 : tstream_gensec_readv_wrapped_next(req);
161 3587675 : if (!tevent_req_is_in_progress(req)) {
162 2482597 : return tevent_req_post(req, ev);
163 : }
164 :
165 1104026 : return req;
166 : }
167 :
168 : static int tstream_gensec_readv_next_vector(struct tstream_context *unix_stream,
169 : void *private_data,
170 : TALLOC_CTX *mem_ctx,
171 : struct iovec **_vector,
172 : size_t *_count);
173 : static void tstream_gensec_readv_wrapped_done(struct tevent_req *subreq);
174 :
175 4692577 : static void tstream_gensec_readv_wrapped_next(struct tevent_req *req)
176 : {
177 3482 : struct tstream_gensec_readv_state *state =
178 4692577 : tevent_req_data(req,
179 : struct tstream_gensec_readv_state);
180 3482 : struct tstream_gensec *tgss =
181 4692577 : tstream_context_data(state->stream,
182 : struct tstream_gensec);
183 3482 : struct tevent_req *subreq;
184 :
185 : /*
186 : * copy the pending buffer first
187 : */
188 8281550 : while (tgss->read.left > 0 && state->count > 0) {
189 3588973 : uint8_t *base = (uint8_t *)state->vector[0].iov_base;
190 3588973 : size_t len = MIN(tgss->read.left, state->vector[0].iov_len);
191 :
192 3588973 : memcpy(base, tgss->read.unwrapped.data + tgss->read.ofs, len);
193 :
194 3588973 : base += len;
195 3588973 : state->vector[0].iov_base = (char *) base;
196 3588973 : state->vector[0].iov_len -= len;
197 :
198 3588973 : tgss->read.ofs += len;
199 3588973 : tgss->read.left -= len;
200 :
201 3588973 : if (state->vector[0].iov_len == 0) {
202 3561997 : state->vector += 1;
203 3561997 : state->count -= 1;
204 : }
205 :
206 3588973 : state->ret += len;
207 : }
208 :
209 4692577 : if (state->count == 0) {
210 3561997 : tevent_req_done(req);
211 3561997 : return;
212 : }
213 :
214 1130580 : data_blob_free(&tgss->read.unwrapped);
215 1130580 : ZERO_STRUCT(state->wrapped);
216 :
217 1130580 : subreq = tstream_readv_pdu_send(state, state->ev,
218 : tgss->plain_stream,
219 : tstream_gensec_readv_next_vector,
220 : state);
221 1130580 : if (tevent_req_nomem(subreq, req)) {
222 0 : return;
223 : }
224 1130580 : tevent_req_set_callback(subreq, tstream_gensec_readv_wrapped_done, req);
225 : }
226 :
227 3340384 : static int tstream_gensec_readv_next_vector(struct tstream_context *unix_stream,
228 : void *private_data,
229 : TALLOC_CTX *mem_ctx,
230 : struct iovec **_vector,
231 : size_t *_count)
232 : {
233 2912 : struct tstream_gensec_readv_state *state =
234 3340384 : talloc_get_type_abort(private_data,
235 : struct tstream_gensec_readv_state);
236 2912 : struct iovec *vector;
237 3340384 : size_t count = 1;
238 :
239 : /* we need to get a message header */
240 3340384 : vector = talloc_array(mem_ctx, struct iovec, count);
241 3340384 : if (!vector) {
242 0 : return -1;
243 : }
244 :
245 3340384 : if (!state->wrapped.asked_for_hdr) {
246 1130580 : state->wrapped.asked_for_hdr = true;
247 1130580 : vector[0].iov_base = (char *)state->wrapped.hdr;
248 1130580 : vector[0].iov_len = sizeof(state->wrapped.hdr);
249 2209804 : } else if (!state->wrapped.asked_for_blob) {
250 930 : uint32_t msg_len;
251 :
252 1104902 : state->wrapped.asked_for_blob = true;
253 :
254 1104902 : msg_len = RIVAL(state->wrapped.hdr, 0);
255 :
256 : /*
257 : * I got a Windows 2012R2 server responding with
258 : * a message of 0x1b28a33.
259 : */
260 1104902 : if (msg_len > 0x0FFFFFFF) {
261 0 : errno = EMSGSIZE;
262 0 : return -1;
263 : }
264 :
265 1104902 : if (msg_len == 0) {
266 0 : errno = EMSGSIZE;
267 0 : return -1;
268 : }
269 :
270 1104902 : state->wrapped.blob = data_blob_talloc(state, NULL, msg_len);
271 1104902 : if (state->wrapped.blob.data == NULL) {
272 0 : return -1;
273 : }
274 :
275 1104902 : vector[0].iov_base = (char *)state->wrapped.blob.data;
276 1104902 : vector[0].iov_len = state->wrapped.blob.length;
277 : } else {
278 1104902 : *_vector = NULL;
279 1104902 : *_count = 0;
280 1104902 : return 0;
281 : }
282 :
283 2235482 : *_vector = vector;
284 2235482 : *_count = count;
285 2235482 : return 0;
286 : }
287 :
288 1130577 : static void tstream_gensec_readv_wrapped_done(struct tevent_req *subreq)
289 : {
290 1052 : struct tevent_req *req =
291 1130577 : tevent_req_callback_data(subreq,
292 : struct tevent_req);
293 1052 : struct tstream_gensec_readv_state *state =
294 1130577 : tevent_req_data(req,
295 : struct tstream_gensec_readv_state);
296 1052 : struct tstream_gensec *tgss =
297 1130577 : tstream_context_data(state->stream,
298 : struct tstream_gensec);
299 1052 : int ret;
300 1052 : int sys_errno;
301 1052 : NTSTATUS status;
302 :
303 1130577 : ret = tstream_readv_pdu_recv(subreq, &sys_errno);
304 1130577 : TALLOC_FREE(subreq);
305 1130577 : if (ret == -1) {
306 25675 : tgss->error = sys_errno;
307 25675 : tevent_req_error(req, sys_errno);
308 25797 : return;
309 : }
310 :
311 1104902 : status = gensec_unwrap(tgss->gensec_security,
312 : state,
313 1104902 : &state->wrapped.blob,
314 : &tgss->read.unwrapped);
315 1104902 : if (!NT_STATUS_IS_OK(status)) {
316 0 : tgss->error = EIO;
317 0 : tevent_req_error(req, tgss->error);
318 0 : return;
319 : }
320 :
321 1104902 : data_blob_free(&state->wrapped.blob);
322 :
323 1104902 : talloc_steal(tgss, tgss->read.unwrapped.data);
324 1104902 : tgss->read.left = tgss->read.unwrapped.length;
325 1104902 : tgss->read.ofs = 0;
326 :
327 1104902 : tstream_gensec_readv_wrapped_next(req);
328 : }
329 :
330 3587672 : static int tstream_gensec_readv_recv(struct tevent_req *req, int *perrno)
331 : {
332 2552 : struct tstream_gensec_readv_state *state =
333 3587672 : tevent_req_data(req,
334 : struct tstream_gensec_readv_state);
335 2552 : int ret;
336 :
337 3587672 : ret = tsocket_simple_int_recv(req, perrno);
338 3587672 : if (ret == 0) {
339 3561997 : ret = state->ret;
340 : }
341 :
342 3587672 : tevent_req_received(req);
343 3587672 : return ret;
344 : }
345 :
346 : struct tstream_gensec_writev_state {
347 : struct tevent_context *ev;
348 : struct tstream_context *stream;
349 :
350 : struct iovec *vector;
351 : int count;
352 :
353 : struct {
354 : off_t ofs;
355 : size_t left;
356 : DATA_BLOB blob;
357 : } unwrapped;
358 :
359 : struct {
360 : uint8_t hdr[4];
361 : DATA_BLOB blob;
362 : struct iovec iov[2];
363 : } wrapped;
364 :
365 : int ret;
366 : };
367 :
368 : static void tstream_gensec_writev_wrapped_next(struct tevent_req *req);
369 :
370 1077896 : static struct tevent_req *tstream_gensec_writev_send(TALLOC_CTX *mem_ctx,
371 : struct tevent_context *ev,
372 : struct tstream_context *stream,
373 : const struct iovec *vector,
374 : size_t count)
375 : {
376 930 : struct tstream_gensec *tgss =
377 1077896 : tstream_context_data(stream,
378 : struct tstream_gensec);
379 930 : struct tevent_req *req;
380 930 : struct tstream_gensec_writev_state *state;
381 930 : size_t i;
382 930 : int total;
383 930 : int chunk;
384 :
385 1077896 : req = tevent_req_create(mem_ctx, &state,
386 : struct tstream_gensec_writev_state);
387 1077896 : if (req == NULL) {
388 0 : return NULL;
389 : }
390 :
391 1077896 : if (tgss->error != 0) {
392 0 : tevent_req_error(req, tgss->error);
393 0 : return tevent_req_post(req, ev);
394 : }
395 :
396 1077896 : state->ev = ev;
397 1077896 : state->stream = stream;
398 1077896 : state->ret = 0;
399 :
400 : /*
401 : * we make a copy of the vector so we can change the structure
402 : */
403 1077896 : state->vector = talloc_array(state, struct iovec, count);
404 1077896 : if (tevent_req_nomem(state->vector, req)) {
405 0 : return tevent_req_post(req, ev);
406 : }
407 1077896 : memcpy(state->vector, vector, sizeof(struct iovec) * count);
408 1077896 : state->count = count;
409 :
410 1077896 : total = 0;
411 2862798 : for (i = 0; i < count; i++) {
412 : /*
413 : * the generic tstream code makes sure that
414 : * this never wraps.
415 : */
416 1784902 : total += vector[i].iov_len;
417 : }
418 :
419 : /*
420 : * We may need to send data in chunks.
421 : */
422 1077896 : chunk = MIN(total, tgss->write.max_unwrapped_size);
423 :
424 1077896 : state->unwrapped.blob = data_blob_talloc(state, NULL, chunk);
425 1077896 : if (tevent_req_nomem(state->unwrapped.blob.data, req)) {
426 0 : return tevent_req_post(req, ev);
427 : }
428 :
429 1077896 : tstream_gensec_writev_wrapped_next(req);
430 1077896 : if (!tevent_req_is_in_progress(req)) {
431 0 : return tevent_req_post(req, ev);
432 : }
433 :
434 1076966 : return req;
435 : }
436 :
437 : static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq);
438 :
439 2182768 : static void tstream_gensec_writev_wrapped_next(struct tevent_req *req)
440 : {
441 1860 : struct tstream_gensec_writev_state *state =
442 2182768 : tevent_req_data(req,
443 : struct tstream_gensec_writev_state);
444 1860 : struct tstream_gensec *tgss =
445 2182768 : tstream_context_data(state->stream,
446 : struct tstream_gensec);
447 1860 : struct tevent_req *subreq;
448 1860 : NTSTATUS status;
449 :
450 2182768 : data_blob_free(&state->wrapped.blob);
451 :
452 2182768 : state->unwrapped.left = state->unwrapped.blob.length;
453 2182768 : state->unwrapped.ofs = 0;
454 :
455 : /*
456 : * first fill our buffer
457 : */
458 3994646 : while (state->unwrapped.left > 0 && state->count > 0) {
459 1811878 : uint8_t *base = (uint8_t *)state->vector[0].iov_base;
460 1811878 : size_t len = MIN(state->unwrapped.left, state->vector[0].iov_len);
461 :
462 1811878 : memcpy(state->unwrapped.blob.data + state->unwrapped.ofs, base, len);
463 :
464 1811878 : base += len;
465 1811878 : state->vector[0].iov_base = (char *) base;
466 1811878 : state->vector[0].iov_len -= len;
467 :
468 1811878 : state->unwrapped.ofs += len;
469 1811878 : state->unwrapped.left -= len;
470 :
471 1811878 : if (state->vector[0].iov_len == 0) {
472 1784902 : state->vector += 1;
473 1784902 : state->count -= 1;
474 : }
475 :
476 1811878 : state->ret += len;
477 : }
478 :
479 2182768 : if (state->unwrapped.ofs == 0) {
480 1077895 : tevent_req_done(req);
481 1078825 : return;
482 : }
483 :
484 1104873 : state->unwrapped.blob.length = state->unwrapped.ofs;
485 :
486 1104873 : status = gensec_wrap(tgss->gensec_security,
487 : state,
488 1104873 : &state->unwrapped.blob,
489 : &state->wrapped.blob);
490 1104873 : if (!NT_STATUS_IS_OK(status)) {
491 0 : tgss->error = EIO;
492 0 : tevent_req_error(req, tgss->error);
493 0 : return;
494 : }
495 :
496 1104873 : RSIVAL(state->wrapped.hdr, 0, state->wrapped.blob.length);
497 :
498 1104873 : state->wrapped.iov[0].iov_base = (void *)state->wrapped.hdr;
499 1104873 : state->wrapped.iov[0].iov_len = sizeof(state->wrapped.hdr);
500 1104873 : state->wrapped.iov[1].iov_base = (void *)state->wrapped.blob.data;
501 1104873 : state->wrapped.iov[1].iov_len = state->wrapped.blob.length;
502 :
503 1105803 : subreq = tstream_writev_send(state, state->ev,
504 : tgss->plain_stream,
505 1104873 : state->wrapped.iov, 2);
506 1104873 : if (tevent_req_nomem(subreq, req)) {
507 0 : return;
508 : }
509 1104873 : tevent_req_set_callback(subreq,
510 : tstream_gensec_writev_wrapped_done,
511 : req);
512 : }
513 :
514 1104872 : static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq)
515 : {
516 930 : struct tevent_req *req =
517 1104872 : tevent_req_callback_data(subreq,
518 : struct tevent_req);
519 930 : struct tstream_gensec_writev_state *state =
520 1104872 : tevent_req_data(req,
521 : struct tstream_gensec_writev_state);
522 930 : struct tstream_gensec *tgss =
523 1104872 : tstream_context_data(state->stream,
524 : struct tstream_gensec);
525 930 : int sys_errno;
526 930 : int ret;
527 :
528 1104872 : ret = tstream_writev_recv(subreq, &sys_errno);
529 1104872 : TALLOC_FREE(subreq);
530 1104872 : if (ret == -1) {
531 0 : tgss->error = sys_errno;
532 0 : tevent_req_error(req, sys_errno);
533 0 : return;
534 : }
535 :
536 1104872 : tstream_gensec_writev_wrapped_next(req);
537 : }
538 :
539 1077895 : static int tstream_gensec_writev_recv(struct tevent_req *req,
540 : int *perrno)
541 : {
542 930 : struct tstream_gensec_writev_state *state =
543 1077895 : tevent_req_data(req,
544 : struct tstream_gensec_writev_state);
545 930 : int ret;
546 :
547 1077895 : ret = tsocket_simple_int_recv(req, perrno);
548 1077895 : if (ret == 0) {
549 1077895 : ret = state->ret;
550 : }
551 :
552 1077895 : tevent_req_received(req);
553 1077895 : return ret;
554 : }
555 :
556 : struct tstream_gensec_disconnect_state {
557 : uint8_t _dummy;
558 : };
559 :
560 25706 : static struct tevent_req *tstream_gensec_disconnect_send(TALLOC_CTX *mem_ctx,
561 : struct tevent_context *ev,
562 : struct tstream_context *stream)
563 : {
564 122 : struct tstream_gensec *tgss =
565 25706 : tstream_context_data(stream,
566 : struct tstream_gensec);
567 122 : struct tevent_req *req;
568 122 : struct tstream_gensec_disconnect_state *state;
569 :
570 25706 : req = tevent_req_create(mem_ctx, &state,
571 : struct tstream_gensec_disconnect_state);
572 25706 : if (req == NULL) {
573 0 : return NULL;
574 : }
575 :
576 25706 : if (tgss->error != 0) {
577 25675 : tevent_req_error(req, tgss->error);
578 25675 : return tevent_req_post(req, ev);
579 : }
580 :
581 : /*
582 : * The caller is responsible to do the real disconnect
583 : * on the plain stream!
584 : */
585 31 : tgss->plain_stream = NULL;
586 31 : tgss->error = ENOTCONN;
587 :
588 31 : tevent_req_done(req);
589 31 : return tevent_req_post(req, ev);
590 : }
591 :
592 25706 : static int tstream_gensec_disconnect_recv(struct tevent_req *req,
593 : int *perrno)
594 : {
595 122 : int ret;
596 :
597 25706 : ret = tsocket_simple_int_recv(req, perrno);
598 :
599 25706 : tevent_req_received(req);
600 25706 : return ret;
601 : }
602 :
603 : static const struct tstream_context_ops tstream_gensec_ops = {
604 : .name = "gensec",
605 :
606 : .pending_bytes = tstream_gensec_pending_bytes,
607 :
608 : .readv_send = tstream_gensec_readv_send,
609 : .readv_recv = tstream_gensec_readv_recv,
610 :
611 : .writev_send = tstream_gensec_writev_send,
612 : .writev_recv = tstream_gensec_writev_recv,
613 :
614 : .disconnect_send = tstream_gensec_disconnect_send,
615 : .disconnect_recv = tstream_gensec_disconnect_recv,
616 : };
|