92f4fa6687cef7921a7e07577a526047842ef774
[samba.git] / source4 / auth / gensec / gensec_tstream.c
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 _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         gensec_stream = tstream_context_create(mem_ctx,
63                                                &tstream_gensec_ops,
64                                                &tgss,
65                                                struct tstream_gensec,
66                                                location);
67         if (gensec_stream == NULL) {
68                 return NT_STATUS_NO_MEMORY;
69         }
70
71         tgss->plain_stream = plain_stream;
72         tgss->gensec_security = gensec_security;
73         tgss->error = 0;
74
75         if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN) &&
76             !gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
77                 talloc_free(gensec_stream);
78                 return NT_STATUS_INVALID_PARAMETER;
79         }
80
81         tgss->write.max_unwrapped_size = gensec_max_input_size(gensec_security);
82         tgss->write.max_wrapped_size = gensec_max_wrapped_size(gensec_security);
83
84         ZERO_STRUCT(tgss->read);
85
86         *_gensec_stream = gensec_stream;
87         return NT_STATUS_OK;
88 }
89
90 static ssize_t tstream_gensec_pending_bytes(struct tstream_context *stream)
91 {
92         struct tstream_gensec *tgss =
93                 tstream_context_data(stream,
94                 struct tstream_gensec);
95
96         if (tgss->error != 0) {
97                 errno = tgss->error;
98                 return -1;
99         }
100
101         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 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         struct tstream_gensec *tgss =
130                 tstream_context_data(stream,
131                 struct tstream_gensec);
132         struct tevent_req *req;
133         struct tstream_gensec_readv_state *state;
134
135         req = tevent_req_create(mem_ctx, &state,
136                                 struct tstream_gensec_readv_state);
137         if (!req) {
138                 return NULL;
139         }
140
141         if (tgss->error != 0) {
142                 tevent_req_error(req, tgss->error);
143                 return tevent_req_post(req, ev);
144         }
145
146         state->ev = ev;
147         state->stream = stream;
148         state->ret = 0;
149
150         /*
151          * we make a copy of the vector so we can change the structure
152          */
153         state->vector = talloc_array(state, struct iovec, count);
154         if (tevent_req_nomem(state->vector, req)) {
155                 return tevent_req_post(req, ev);
156         }
157         memcpy(state->vector, vector, sizeof(struct iovec) * count);
158         state->count = count;
159
160         tstream_gensec_readv_wrapped_next(req);
161         if (!tevent_req_is_in_progress(req)) {
162                 return tevent_req_post(req, ev);
163         }
164
165         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 static void tstream_gensec_readv_wrapped_next(struct tevent_req *req)
176 {
177         struct tstream_gensec_readv_state *state =
178                 tevent_req_data(req,
179                 struct tstream_gensec_readv_state);
180         struct tstream_gensec *tgss =
181                 tstream_context_data(state->stream,
182                 struct tstream_gensec);
183         struct tevent_req *subreq;
184
185         /*
186          * copy the pending buffer first
187          */
188         while (tgss->read.left > 0 && state->count > 0) {
189                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
190                 size_t len = MIN(tgss->read.left, state->vector[0].iov_len);
191
192                 memcpy(base, tgss->read.unwrapped.data + tgss->read.ofs, len);
193
194                 base += len;
195                 state->vector[0].iov_base = (char *) base;
196                 state->vector[0].iov_len -= len;
197
198                 tgss->read.ofs += len;
199                 tgss->read.left -= len;
200
201                 if (state->vector[0].iov_len == 0) {
202                         state->vector += 1;
203                         state->count -= 1;
204                 }
205
206                 state->ret += len;
207         }
208
209         if (state->count == 0) {
210                 tevent_req_done(req);
211                 return;
212         }
213
214         data_blob_free(&tgss->read.unwrapped);
215         ZERO_STRUCT(state->wrapped);
216
217         subreq = tstream_readv_pdu_send(state, state->ev,
218                                         tgss->plain_stream,
219                                         tstream_gensec_readv_next_vector,
220                                         state);
221         if (tevent_req_nomem(subreq, req)) {
222                 return;
223         }
224         tevent_req_set_callback(subreq, tstream_gensec_readv_wrapped_done, req);
225 }
226
227 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         struct tstream_gensec_readv_state *state =
234                 talloc_get_type_abort(private_data,
235                 struct tstream_gensec_readv_state);
236         struct iovec *vector;
237         size_t count = 1;
238
239         /* we need to get a message header */
240         vector = talloc_array(mem_ctx, struct iovec, count);
241         if (!vector) {
242                 return -1;
243         }
244
245         if (!state->wrapped.asked_for_hdr) {
246                 state->wrapped.asked_for_hdr = true;
247                 vector[0].iov_base = (char *)state->wrapped.hdr;
248                 vector[0].iov_len = sizeof(state->wrapped.hdr);
249         } else if (!state->wrapped.asked_for_blob) {
250                 uint32_t msg_len;
251
252                 state->wrapped.asked_for_blob = true;
253
254                 msg_len = RIVAL(state->wrapped.hdr, 0);
255
256                 if (msg_len > 0x00FFFFFF) {
257                         errno = EMSGSIZE;
258                         return -1;
259                 }
260
261                 if (msg_len == 0) {
262                         errno = EMSGSIZE;
263                         return -1;
264                 }
265
266                 state->wrapped.blob = data_blob_talloc(state, NULL, msg_len);
267                 if (state->wrapped.blob.data == NULL) {
268                         return -1;
269                 }
270
271                 vector[0].iov_base = (char *)state->wrapped.blob.data;
272                 vector[0].iov_len = state->wrapped.blob.length;
273         } else {
274                 *_vector = NULL;
275                 *_count = 0;
276                 return 0;
277         }
278
279         *_vector = vector;
280         *_count = count;
281         return 0;
282 }
283
284 static void tstream_gensec_readv_wrapped_done(struct tevent_req *subreq)
285 {
286         struct tevent_req *req =
287                 tevent_req_callback_data(subreq,
288                 struct tevent_req);
289         struct tstream_gensec_readv_state *state =
290                 tevent_req_data(req,
291                 struct tstream_gensec_readv_state);
292         struct tstream_gensec *tgss =
293                 tstream_context_data(state->stream,
294                 struct tstream_gensec);
295         int ret;
296         int sys_errno;
297         NTSTATUS status;
298
299         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
300         TALLOC_FREE(subreq);
301         if (ret == -1) {
302                 tgss->error = sys_errno;
303                 tevent_req_error(req, sys_errno);
304                 return;
305         }
306
307         status = gensec_unwrap(tgss->gensec_security,
308                                state,
309                                &state->wrapped.blob,
310                                &tgss->read.unwrapped);
311         if (!NT_STATUS_IS_OK(status)) {
312                 tgss->error = EIO;
313                 tevent_req_error(req, tgss->error);
314                 return;
315         }
316
317         data_blob_free(&state->wrapped.blob);
318
319         talloc_steal(tgss, tgss->read.unwrapped.data);
320         tgss->read.left = tgss->read.unwrapped.length;
321         tgss->read.ofs = 0;
322
323         tstream_gensec_readv_wrapped_next(req);
324 }
325
326 static int tstream_gensec_readv_recv(struct tevent_req *req, int *perrno)
327 {
328         struct tstream_gensec_readv_state *state =
329                 tevent_req_data(req,
330                 struct tstream_gensec_readv_state);
331         int ret;
332
333         ret = tsocket_simple_int_recv(req, perrno);
334         if (ret == 0) {
335                 ret = state->ret;
336         }
337
338         tevent_req_received(req);
339         return ret;
340 }
341
342 struct tstream_gensec_writev_state {
343         struct tevent_context *ev;
344         struct tstream_context *stream;
345
346         struct iovec *vector;
347         int count;
348
349         struct {
350                 off_t ofs;
351                 size_t left;
352                 DATA_BLOB blob;
353         } unwrapped;
354
355         struct {
356                 uint8_t hdr[4];
357                 DATA_BLOB blob;
358                 struct iovec iov[2];
359         } wrapped;
360
361         int ret;
362 };
363
364 static void tstream_gensec_writev_wrapped_next(struct tevent_req *req);
365
366 static struct tevent_req *tstream_gensec_writev_send(TALLOC_CTX *mem_ctx,
367                                         struct tevent_context *ev,
368                                         struct tstream_context *stream,
369                                         const struct iovec *vector,
370                                         size_t count)
371 {
372         struct tstream_gensec *tgss =
373                 tstream_context_data(stream,
374                 struct tstream_gensec);
375         struct tevent_req *req;
376         struct tstream_gensec_writev_state *state;
377         int i;
378         int total;
379         int chunk;
380
381         req = tevent_req_create(mem_ctx, &state,
382                                 struct tstream_gensec_writev_state);
383         if (req == NULL) {
384                 return NULL;
385         }
386
387         if (tgss->error != 0) {
388                 tevent_req_error(req, tgss->error);
389                 return tevent_req_post(req, ev);
390         }
391
392         state->ev = ev;
393         state->stream = stream;
394         state->ret = 0;
395
396         /*
397          * we make a copy of the vector so we can change the structure
398          */
399         state->vector = talloc_array(state, struct iovec, count);
400         if (tevent_req_nomem(state->vector, req)) {
401                 return tevent_req_post(req, ev);
402         }
403         memcpy(state->vector, vector, sizeof(struct iovec) * count);
404         state->count = count;
405
406         total = 0;
407         for (i = 0; i < count; i++) {
408                 /*
409                  * the generic tstream code makes sure that
410                  * this never wraps.
411                  */
412                 total += vector[i].iov_len;
413         }
414
415         /*
416          * We may need to send data in chunks.
417          */
418         chunk = MIN(total, tgss->write.max_unwrapped_size);
419
420         state->unwrapped.blob = data_blob_talloc(state, NULL, chunk);
421         if (tevent_req_nomem(state->unwrapped.blob.data, req)) {
422                 return tevent_req_post(req, ev);
423         }
424
425         tstream_gensec_writev_wrapped_next(req);
426         if (!tevent_req_is_in_progress(req)) {
427                 return tevent_req_post(req, ev);
428         }
429
430         return req;
431 }
432
433 static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq);
434
435 static void tstream_gensec_writev_wrapped_next(struct tevent_req *req)
436 {
437         struct tstream_gensec_writev_state *state =
438                 tevent_req_data(req,
439                 struct tstream_gensec_writev_state);
440         struct tstream_gensec *tgss =
441                 tstream_context_data(state->stream,
442                 struct tstream_gensec);
443         struct tevent_req *subreq;
444         NTSTATUS status;
445
446         data_blob_free(&state->wrapped.blob);
447
448         state->unwrapped.left = state->unwrapped.blob.length;
449         state->unwrapped.ofs = 0;
450
451         /*
452          * first fill our buffer
453          */
454         while (state->unwrapped.left > 0 && state->count > 0) {
455                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
456                 size_t len = MIN(state->unwrapped.left, state->vector[0].iov_len);
457
458                 memcpy(state->unwrapped.blob.data + state->unwrapped.ofs, base, len);
459
460                 base += len;
461                 state->vector[0].iov_base = (char *) base;
462                 state->vector[0].iov_len -= len;
463
464                 state->unwrapped.ofs += len;
465                 state->unwrapped.left -= len;
466
467                 if (state->vector[0].iov_len == 0) {
468                         state->vector += 1;
469                         state->count -= 1;
470                 }
471
472                 state->ret += len;
473         }
474
475         if (state->unwrapped.ofs == 0) {
476                 tevent_req_done(req);
477                 return;
478         }
479
480         state->unwrapped.blob.length = state->unwrapped.ofs;
481
482         status = gensec_wrap(tgss->gensec_security,
483                              state,
484                              &state->unwrapped.blob,
485                              &state->wrapped.blob);
486         if (!NT_STATUS_IS_OK(status)) {
487                 tgss->error = EIO;
488                 tevent_req_error(req, tgss->error);
489                 return;
490         }
491
492         RSIVAL(state->wrapped.hdr, 0, state->wrapped.blob.length);
493
494         state->wrapped.iov[0].iov_base = (void *)state->wrapped.hdr;
495         state->wrapped.iov[0].iov_len = sizeof(state->wrapped.hdr);
496         state->wrapped.iov[1].iov_base = (void *)state->wrapped.blob.data;
497         state->wrapped.iov[1].iov_len = state->wrapped.blob.length;
498
499         subreq = tstream_writev_send(state, state->ev,
500                                       tgss->plain_stream,
501                                       state->wrapped.iov, 2);
502         if (tevent_req_nomem(subreq, req)) {
503                 return;
504         }
505         tevent_req_set_callback(subreq,
506                                 tstream_gensec_writev_wrapped_done,
507                                 req);
508 }
509
510 static void tstream_gensec_writev_wrapped_done(struct tevent_req *subreq)
511 {
512         struct tevent_req *req =
513                 tevent_req_callback_data(subreq,
514                 struct tevent_req);
515         struct tstream_gensec_writev_state *state =
516                 tevent_req_data(req,
517                 struct tstream_gensec_writev_state);
518         struct tstream_gensec *tgss =
519                 tstream_context_data(state->stream,
520                 struct tstream_gensec);
521         int sys_errno;
522         int ret;
523
524         ret = tstream_writev_recv(subreq, &sys_errno);
525         TALLOC_FREE(subreq);
526         if (ret == -1) {
527                 tgss->error = sys_errno;
528                 tevent_req_error(req, sys_errno);
529                 return;
530         }
531
532         tstream_gensec_writev_wrapped_next(req);
533 }
534
535 static int tstream_gensec_writev_recv(struct tevent_req *req,
536                                    int *perrno)
537 {
538         struct tstream_gensec_writev_state *state =
539                 tevent_req_data(req,
540                 struct tstream_gensec_writev_state);
541         int ret;
542
543         ret = tsocket_simple_int_recv(req, perrno);
544         if (ret == 0) {
545                 ret = state->ret;
546         }
547
548         tevent_req_received(req);
549         return ret;
550 }
551
552 struct tstream_gensec_disconnect_state {
553         uint8_t _dummy;
554 };
555
556 static struct tevent_req *tstream_gensec_disconnect_send(TALLOC_CTX *mem_ctx,
557                                                          struct tevent_context *ev,
558                                                          struct tstream_context *stream)
559 {
560         struct tstream_gensec *tgss =
561                 tstream_context_data(stream,
562                 struct tstream_gensec);
563         struct tevent_req *req;
564         struct tstream_gensec_disconnect_state *state;
565
566         req = tevent_req_create(mem_ctx, &state,
567                                 struct tstream_gensec_disconnect_state);
568         if (req == NULL) {
569                 return NULL;
570         }
571
572         if (tgss->error != 0) {
573                 tevent_req_error(req, tgss->error);
574                 return tevent_req_post(req, ev);
575         }
576
577         /*
578          * The caller is responsible to do the real disconnect
579          * on the plain stream!
580          */
581         tgss->plain_stream = NULL;
582         tgss->error = ENOTCONN;
583
584         tevent_req_done(req);
585         return tevent_req_post(req, ev);
586 }
587
588 static int tstream_gensec_disconnect_recv(struct tevent_req *req,
589                                        int *perrno)
590 {
591         int ret;
592
593         ret = tsocket_simple_int_recv(req, perrno);
594
595         tevent_req_received(req);
596         return ret;
597 }
598
599 static const struct tstream_context_ops tstream_gensec_ops = {
600         .name                   = "gensec",
601
602         .pending_bytes          = tstream_gensec_pending_bytes,
603
604         .readv_send             = tstream_gensec_readv_send,
605         .readv_recv             = tstream_gensec_readv_recv,
606
607         .writev_send            = tstream_gensec_writev_send,
608         .writev_recv            = tstream_gensec_writev_recv,
609
610         .disconnect_send        = tstream_gensec_disconnect_send,
611         .disconnect_recv        = tstream_gensec_disconnect_recv,
612 };