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