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 37625 : _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 : struct tstream_context *gensec_stream;
60 : struct tstream_gensec *tgss;
61 :
62 37625 : gensec_stream = tstream_context_create(mem_ctx,
63 : &tstream_gensec_ops,
64 : &tgss,
65 : struct tstream_gensec,
66 : location);
67 37625 : if (gensec_stream == NULL) {
68 0 : return NT_STATUS_NO_MEMORY;
69 : }
70 :
71 37625 : tgss->plain_stream = plain_stream;
72 37625 : tgss->gensec_security = gensec_security;
73 37625 : tgss->error = 0;
74 :
75 37625 : 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 37625 : tgss->write.max_unwrapped_size = gensec_max_input_size(gensec_security);
82 37625 : tgss->write.max_wrapped_size = gensec_max_wrapped_size(gensec_security);
83 :
84 37625 : ZERO_STRUCT(tgss->read);
85 :
86 37625 : *_gensec_stream = gensec_stream;
87 37625 : return NT_STATUS_OK;
88 : }
89 :
90 0 : static ssize_t tstream_gensec_pending_bytes(struct tstream_context *stream)
91 : {
92 0 : struct tstream_gensec *tgss =
93 0 : tstream_context_data(stream,
94 : struct tstream_gensec);
95 :
96 0 : if (tgss->error != 0) {
97 0 : errno = tgss->error;
98 0 : return -1;
99 : }
100 :
101 0 : 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 2938238 : 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 2359144 : struct tstream_gensec *tgss =
130 2938238 : tstream_context_data(stream,
131 : struct tstream_gensec);
132 : struct tevent_req *req;
133 : struct tstream_gensec_readv_state *state;
134 :
135 2938238 : req = tevent_req_create(mem_ctx, &state,
136 : struct tstream_gensec_readv_state);
137 2938238 : if (!req) {
138 0 : return NULL;
139 : }
140 :
141 2938238 : if (tgss->error != 0) {
142 0 : tevent_req_error(req, tgss->error);
143 0 : return tevent_req_post(req, ev);
144 : }
145 :
146 2938238 : state->ev = ev;
147 2938238 : state->stream = stream;
148 2938238 : state->ret = 0;
149 :
150 : /*
151 : * we make a copy of the vector so we can change the structure
152 : */
153 2938238 : state->vector = talloc_array(state, struct iovec, count);
154 2938238 : if (tevent_req_nomem(state->vector, req)) {
155 0 : return tevent_req_post(req, ev);
156 : }
157 2938238 : memcpy(state->vector, vector, sizeof(struct iovec) * count);
158 2938238 : state->count = count;
159 :
160 2938238 : tstream_gensec_readv_wrapped_next(req);
161 2938238 : if (!tevent_req_is_in_progress(req)) {
162 2069495 : return tevent_req_post(req, ev);
163 : }
164 :
165 868743 : 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 3813706 : static void tstream_gensec_readv_wrapped_next(struct tevent_req *req)
176 : {
177 3036974 : struct tstream_gensec_readv_state *state =
178 3813706 : tevent_req_data(req,
179 : struct tstream_gensec_readv_state);
180 3036974 : struct tstream_gensec *tgss =
181 3813706 : tstream_context_data(state->stream,
182 : struct tstream_gensec);
183 : struct tevent_req *subreq;
184 :
185 : /*
186 : * copy the pending buffer first
187 : */
188 9797115 : while (tgss->read.left > 0 && state->count > 0) {
189 2946435 : uint8_t *base = (uint8_t *)state->vector[0].iov_base;
190 2946435 : size_t len = MIN(tgss->read.left, state->vector[0].iov_len);
191 :
192 2946435 : memcpy(base, tgss->read.unwrapped.data + tgss->read.ofs, len);
193 :
194 2946435 : base += len;
195 2946435 : state->vector[0].iov_base = (char *) base;
196 2946435 : state->vector[0].iov_len -= len;
197 :
198 2946435 : tgss->read.ofs += len;
199 2946435 : tgss->read.left -= len;
200 :
201 2946435 : if (state->vector[0].iov_len == 0) {
202 2919461 : state->vector += 1;
203 2919461 : state->count -= 1;
204 : }
205 :
206 2946435 : state->ret += len;
207 : }
208 :
209 3813706 : if (state->count == 0) {
210 2919461 : tevent_req_done(req);
211 2919461 : return;
212 : }
213 :
214 894245 : data_blob_free(&tgss->read.unwrapped);
215 894245 : ZERO_STRUCT(state->wrapped);
216 :
217 894245 : subreq = tstream_readv_pdu_send(state, state->ev,
218 : tgss->plain_stream,
219 : tstream_gensec_readv_next_vector,
220 : state);
221 894245 : if (tevent_req_nomem(subreq, req)) {
222 0 : return;
223 : }
224 894245 : tevent_req_set_callback(subreq, tstream_gensec_readv_wrapped_done, req);
225 : }
226 :
227 2645181 : 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 2047749 : struct tstream_gensec_readv_state *state =
234 597432 : talloc_get_type_abort(private_data,
235 : struct tstream_gensec_readv_state);
236 : struct iovec *vector;
237 2645181 : size_t count = 1;
238 :
239 : /* we need to get a message header */
240 2645181 : vector = talloc_array(mem_ctx, struct iovec, count);
241 2645181 : if (!vector) {
242 0 : return -1;
243 : }
244 :
245 2645181 : if (!state->wrapped.asked_for_hdr) {
246 894245 : state->wrapped.asked_for_hdr = true;
247 894245 : vector[0].iov_base = (char *)state->wrapped.hdr;
248 894245 : vector[0].iov_len = sizeof(state->wrapped.hdr);
249 1750936 : } else if (!state->wrapped.asked_for_blob) {
250 : uint32_t msg_len;
251 :
252 875468 : state->wrapped.asked_for_blob = true;
253 :
254 875468 : 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 875468 : if (msg_len > 0x0FFFFFFF) {
261 0 : errno = EMSGSIZE;
262 0 : return -1;
263 : }
264 :
265 875468 : if (msg_len == 0) {
266 0 : errno = EMSGSIZE;
267 0 : return -1;
268 : }
269 :
270 875468 : state->wrapped.blob = data_blob_talloc(state, NULL, msg_len);
271 875468 : if (state->wrapped.blob.data == NULL) {
272 0 : return -1;
273 : }
274 :
275 875468 : vector[0].iov_base = (char *)state->wrapped.blob.data;
276 875468 : vector[0].iov_len = state->wrapped.blob.length;
277 : } else {
278 875468 : *_vector = NULL;
279 875468 : *_count = 0;
280 875468 : return 0;
281 : }
282 :
283 1769713 : *_vector = vector;
284 1769713 : *_count = count;
285 1769713 : return 0;
286 : }
287 :
288 894241 : static void tstream_gensec_readv_wrapped_done(struct tevent_req *subreq)
289 : {
290 692085 : struct tevent_req *req =
291 894241 : tevent_req_callback_data(subreq,
292 : struct tevent_req);
293 692085 : struct tstream_gensec_readv_state *state =
294 894241 : tevent_req_data(req,
295 : struct tstream_gensec_readv_state);
296 692085 : struct tstream_gensec *tgss =
297 894241 : tstream_context_data(state->stream,
298 : struct tstream_gensec);
299 : int ret;
300 : int sys_errno;
301 : NTSTATUS status;
302 :
303 894241 : ret = tstream_readv_pdu_recv(subreq, &sys_errno);
304 894241 : TALLOC_FREE(subreq);
305 894241 : if (ret == -1) {
306 18773 : tgss->error = sys_errno;
307 18773 : tevent_req_error(req, sys_errno);
308 18773 : return;
309 : }
310 :
311 1553298 : status = gensec_unwrap(tgss->gensec_security,
312 : state,
313 875468 : &state->wrapped.blob,
314 : &tgss->read.unwrapped);
315 875468 : 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 875468 : data_blob_free(&state->wrapped.blob);
322 :
323 875468 : talloc_steal(tgss, tgss->read.unwrapped.data);
324 875468 : tgss->read.left = tgss->read.unwrapped.length;
325 875468 : tgss->read.ofs = 0;
326 :
327 875468 : tstream_gensec_readv_wrapped_next(req);
328 : }
329 :
330 2938234 : static int tstream_gensec_readv_recv(struct tevent_req *req, int *perrno)
331 : {
332 2359140 : struct tstream_gensec_readv_state *state =
333 2938234 : tevent_req_data(req,
334 : struct tstream_gensec_readv_state);
335 : int ret;
336 :
337 2938234 : ret = tsocket_simple_int_recv(req, perrno);
338 2938234 : if (ret == 0) {
339 2919461 : ret = state->ret;
340 : }
341 :
342 2938234 : tevent_req_received(req);
343 2938234 : 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 848411 : 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 650831 : struct tstream_gensec *tgss =
377 848411 : tstream_context_data(stream,
378 : struct tstream_gensec);
379 : struct tevent_req *req;
380 : struct tstream_gensec_writev_state *state;
381 : int i;
382 : int total;
383 : int chunk;
384 :
385 848411 : req = tevent_req_create(mem_ctx, &state,
386 : struct tstream_gensec_writev_state);
387 848411 : if (req == NULL) {
388 0 : return NULL;
389 : }
390 :
391 848411 : if (tgss->error != 0) {
392 0 : tevent_req_error(req, tgss->error);
393 0 : return tevent_req_post(req, ev);
394 : }
395 :
396 848411 : state->ev = ev;
397 848411 : state->stream = stream;
398 848411 : state->ret = 0;
399 :
400 : /*
401 : * we make a copy of the vector so we can change the structure
402 : */
403 848411 : state->vector = talloc_array(state, struct iovec, count);
404 848411 : if (tevent_req_nomem(state->vector, req)) {
405 0 : return tevent_req_post(req, ev);
406 : }
407 848411 : memcpy(state->vector, vector, sizeof(struct iovec) * count);
408 848411 : state->count = count;
409 :
410 848411 : total = 0;
411 2307623 : for (i = 0; i < count; i++) {
412 : /*
413 : * the generic tstream code makes sure that
414 : * this never wraps.
415 : */
416 1459212 : total += vector[i].iov_len;
417 : }
418 :
419 : /*
420 : * We may need to send data in chunks.
421 : */
422 848411 : chunk = MIN(total, tgss->write.max_unwrapped_size);
423 :
424 848411 : state->unwrapped.blob = data_blob_talloc(state, NULL, chunk);
425 848411 : if (tevent_req_nomem(state->unwrapped.blob.data, req)) {
426 0 : return tevent_req_post(req, ev);
427 : }
428 :
429 848411 : tstream_gensec_writev_wrapped_next(req);
430 848411 : if (!tevent_req_is_in_progress(req)) {
431 0 : return tevent_req_post(req, ev);
432 : }
433 :
434 848411 : return req;
435 : }
436 :
437 : static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq);
438 :
439 1723795 : static void tstream_gensec_writev_wrapped_next(struct tevent_req *req)
440 : {
441 1328615 : struct tstream_gensec_writev_state *state =
442 1723795 : tevent_req_data(req,
443 : struct tstream_gensec_writev_state);
444 1328615 : struct tstream_gensec *tgss =
445 1723795 : tstream_context_data(state->stream,
446 : struct tstream_gensec);
447 : struct tevent_req *subreq;
448 : NTSTATUS status;
449 :
450 1723795 : data_blob_free(&state->wrapped.blob);
451 :
452 1723795 : state->unwrapped.left = state->unwrapped.blob.length;
453 1723795 : state->unwrapped.ofs = 0;
454 :
455 : /*
456 : * first fill our buffer
457 : */
458 4538596 : while (state->unwrapped.left > 0 && state->count > 0) {
459 1486186 : uint8_t *base = (uint8_t *)state->vector[0].iov_base;
460 1486186 : size_t len = MIN(state->unwrapped.left, state->vector[0].iov_len);
461 :
462 1486186 : memcpy(state->unwrapped.blob.data + state->unwrapped.ofs, base, len);
463 :
464 1486186 : base += len;
465 1486186 : state->vector[0].iov_base = (char *) base;
466 1486186 : state->vector[0].iov_len -= len;
467 :
468 1486186 : state->unwrapped.ofs += len;
469 1486186 : state->unwrapped.left -= len;
470 :
471 1486186 : if (state->vector[0].iov_len == 0) {
472 1459212 : state->vector += 1;
473 1459212 : state->count -= 1;
474 : }
475 :
476 1486186 : state->ret += len;
477 : }
478 :
479 1723795 : if (state->unwrapped.ofs == 0) {
480 848410 : tevent_req_done(req);
481 848410 : return;
482 : }
483 :
484 875385 : state->unwrapped.blob.length = state->unwrapped.ofs;
485 :
486 1553170 : status = gensec_wrap(tgss->gensec_security,
487 : state,
488 875385 : &state->unwrapped.blob,
489 : &state->wrapped.blob);
490 875385 : 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 875385 : RSIVAL(state->wrapped.hdr, 0, state->wrapped.blob.length);
497 :
498 875385 : state->wrapped.iov[0].iov_base = (void *)state->wrapped.hdr;
499 875385 : state->wrapped.iov[0].iov_len = sizeof(state->wrapped.hdr);
500 875385 : state->wrapped.iov[1].iov_base = (void *)state->wrapped.blob.data;
501 875385 : state->wrapped.iov[1].iov_len = state->wrapped.blob.length;
502 :
503 875385 : subreq = tstream_writev_send(state, state->ev,
504 : tgss->plain_stream,
505 875385 : state->wrapped.iov, 2);
506 875385 : if (tevent_req_nomem(subreq, req)) {
507 0 : return;
508 : }
509 875385 : tevent_req_set_callback(subreq,
510 : tstream_gensec_writev_wrapped_done,
511 : req);
512 : }
513 :
514 875384 : static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq)
515 : {
516 677784 : struct tevent_req *req =
517 875384 : tevent_req_callback_data(subreq,
518 : struct tevent_req);
519 677784 : struct tstream_gensec_writev_state *state =
520 875384 : tevent_req_data(req,
521 : struct tstream_gensec_writev_state);
522 677784 : struct tstream_gensec *tgss =
523 875384 : tstream_context_data(state->stream,
524 : struct tstream_gensec);
525 : int sys_errno;
526 : int ret;
527 :
528 875384 : ret = tstream_writev_recv(subreq, &sys_errno);
529 875384 : TALLOC_FREE(subreq);
530 875384 : if (ret == -1) {
531 0 : tgss->error = sys_errno;
532 0 : tevent_req_error(req, sys_errno);
533 0 : return;
534 : }
535 :
536 875384 : tstream_gensec_writev_wrapped_next(req);
537 : }
538 :
539 848410 : static int tstream_gensec_writev_recv(struct tevent_req *req,
540 : int *perrno)
541 : {
542 650830 : struct tstream_gensec_writev_state *state =
543 848410 : tevent_req_data(req,
544 : struct tstream_gensec_writev_state);
545 : int ret;
546 :
547 848410 : ret = tsocket_simple_int_recv(req, perrno);
548 848410 : if (ret == 0) {
549 848410 : ret = state->ret;
550 : }
551 :
552 848410 : tevent_req_received(req);
553 848410 : return ret;
554 : }
555 :
556 : struct tstream_gensec_disconnect_state {
557 : uint8_t _dummy;
558 : };
559 :
560 18858 : static struct tevent_req *tstream_gensec_disconnect_send(TALLOC_CTX *mem_ctx,
561 : struct tevent_context *ev,
562 : struct tstream_context *stream)
563 : {
564 14302 : struct tstream_gensec *tgss =
565 18858 : tstream_context_data(stream,
566 : struct tstream_gensec);
567 : struct tevent_req *req;
568 : struct tstream_gensec_disconnect_state *state;
569 :
570 18858 : req = tevent_req_create(mem_ctx, &state,
571 : struct tstream_gensec_disconnect_state);
572 18858 : if (req == NULL) {
573 0 : return NULL;
574 : }
575 :
576 18858 : if (tgss->error != 0) {
577 18773 : tevent_req_error(req, tgss->error);
578 18773 : 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 85 : tgss->plain_stream = NULL;
586 85 : tgss->error = ENOTCONN;
587 :
588 85 : tevent_req_done(req);
589 85 : return tevent_req_post(req, ev);
590 : }
591 :
592 18858 : static int tstream_gensec_disconnect_recv(struct tevent_req *req,
593 : int *perrno)
594 : {
595 : int ret;
596 :
597 18858 : ret = tsocket_simple_int_recv(req, perrno);
598 :
599 18858 : tevent_req_received(req);
600 18858 : 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 : };
|