96e6f6b99827ce4ad187f61fcdd8a407bdc0cc5f
[metze/samba/wip.git] / source4 / lib / tls / tls_tstream.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "system/network.h"
22 #include "../util/tevent_unix.h"
23 #include "../lib/tsocket/tsocket.h"
24 #include "../lib/tsocket/tsocket_internal.h"
25 #include "lib/tls/tls.h"
26
27 #if ENABLE_GNUTLS
28 #include "gnutls/gnutls.h"
29
30 #define DH_BITS 1024
31
32 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
33 typedef gnutls_datum gnutls_datum_t;
34 #endif
35
36 #endif /* ENABLE_GNUTLS */
37
38 static const struct tstream_context_ops tstream_tls_ops;
39
40 struct tstream_tls {
41         struct tstream_context *plain_stream;
42         int error;
43
44 #if ENABLE_GNUTLS
45         gnutls_session tls_session;
46 #endif /* ENABLE_GNUTLS */
47
48         struct tevent_context *current_ev;
49
50         struct tevent_immediate *im;
51
52         struct {
53                 uint8_t buffer[1024];
54                 struct iovec iov;
55                 struct tevent_req *subreq;
56         } push, pull;
57
58         struct {
59                 struct tevent_req *req;
60         } handshake;
61
62         struct {
63                 off_t ofs;
64                 size_t left;
65                 uint8_t buffer[1024];
66                 struct tevent_req *req;
67         } write;
68
69         struct {
70                 off_t ofs;
71                 size_t left;
72                 uint8_t buffer[1024];
73                 struct tevent_req *req;
74         } read;
75
76         struct {
77                 struct tevent_req *req;
78         } disconnect;
79 };
80
81 static void tstream_tls_retry_handshake(struct tstream_context *stream);
82 static void tstream_tls_retry_read(struct tstream_context *stream);
83 static void tstream_tls_retry_write(struct tstream_context *stream);
84 static void tstream_tls_retry_disconnect(struct tstream_context *stream);
85 static void tstream_tls_retry_trigger(struct tevent_context *ctx,
86                                       struct tevent_immediate *im,
87                                       void *private_data);
88
89 static void tstream_tls_retry(struct tstream_context *stream, bool deferred)
90 {
91
92         struct tstream_tls *tlss =
93                 tstream_context_data(stream,
94                 struct tstream_tls);
95
96         if (tlss->disconnect.req) {
97                 tstream_tls_retry_disconnect(stream);
98                 return;
99         }
100
101         if (tlss->handshake.req) {
102                 tstream_tls_retry_handshake(stream);
103                 return;
104         }
105
106         if (tlss->write.req && tlss->read.req && !deferred) {
107                 tevent_schedule_immediate(tlss->im, tlss->current_ev,
108                                           tstream_tls_retry_trigger,
109                                           stream);
110         }
111
112         if (tlss->write.req) {
113                 tstream_tls_retry_write(stream);
114                 return;
115         }
116
117         if (tlss->read.req) {
118                 tstream_tls_retry_read(stream);
119                 return;
120         }
121 }
122
123 static void tstream_tls_retry_trigger(struct tevent_context *ctx,
124                                       struct tevent_immediate *im,
125                                       void *private_data)
126 {
127         struct tstream_context *stream =
128                 talloc_get_type_abort(private_data,
129                 struct tstream_context);
130
131         tstream_tls_retry(stream, true);
132 }
133
134 #if ENABLE_GNUTLS
135 static void tstream_tls_push_done(struct tevent_req *subreq);
136
137 static ssize_t tstream_tls_push_function(gnutls_transport_ptr ptr,
138                                          const void *buf, size_t size)
139 {
140         struct tstream_context *stream =
141                 talloc_get_type_abort(ptr,
142                 struct tstream_context);
143         struct tstream_tls *tlss =
144                 tstream_context_data(stream,
145                 struct tstream_tls);
146         struct tevent_req *subreq;
147
148         if (tlss->error != 0) {
149                 errno = tlss->error;
150                 return -1;
151         }
152
153         if (tlss->push.subreq) {
154                 errno = EAGAIN;
155                 return -1;
156         }
157
158         tlss->push.iov.iov_base = tlss->push.buffer;
159         tlss->push.iov.iov_len = MIN(size, sizeof(tlss->push.buffer));
160
161         memcpy(tlss->push.buffer, buf, tlss->push.iov.iov_len);
162
163         subreq = tstream_writev_send(tlss,
164                                      tlss->current_ev,
165                                      tlss->plain_stream,
166                                      &tlss->push.iov, 1);
167         if (subreq == NULL) {
168                 errno = ENOMEM;
169                 return -1;
170         }
171         tevent_req_set_callback(subreq, tstream_tls_push_done, stream);
172
173         tlss->push.subreq = subreq;
174
175         return tlss->push.iov.iov_len;
176 }
177
178 static void tstream_tls_push_done(struct tevent_req *subreq)
179 {
180         struct tstream_context *stream =
181                 tevent_req_callback_data(subreq,
182                 struct tstream_context);
183         struct tstream_tls *tlss =
184                 tstream_context_data(stream,
185                 struct tstream_tls);
186         int ret;
187         int sys_errno;
188
189         tlss->push.subreq = NULL;
190         ZERO_STRUCT(tlss->push.iov);
191
192         ret = tstream_writev_recv(subreq, &sys_errno);
193         TALLOC_FREE(subreq);
194         if (ret == -1) {
195                 tlss->error = sys_errno;
196                 tstream_tls_retry(stream, false);
197                 return;
198         }
199
200         tstream_tls_retry(stream, false);
201 }
202
203 static void tstream_tls_pull_done(struct tevent_req *subreq);
204
205 static ssize_t tstream_tls_pull_function(gnutls_transport_ptr ptr,
206                                          void *buf, size_t size)
207 {
208         struct tstream_context *stream =
209                 talloc_get_type_abort(ptr,
210                 struct tstream_context);
211         struct tstream_tls *tlss =
212                 tstream_context_data(stream,
213                 struct tstream_tls);
214         struct tevent_req *subreq;
215
216         if (tlss->error != 0) {
217                 errno = tlss->error;
218                 return -1;
219         }
220
221         if (tlss->pull.subreq) {
222                 errno = EAGAIN;
223                 return -1;
224         }
225
226         if (tlss->pull.iov.iov_base) {
227                 size_t n;
228
229                 n = MIN(tlss->pull.iov.iov_len, size);
230                 memcpy(buf, tlss->pull.iov.iov_base, n);
231
232                 tlss->pull.iov.iov_len -= n;
233                 if (tlss->pull.iov.iov_len == 0) {
234                         tlss->pull.iov.iov_base = NULL;
235                 }
236
237                 return n;
238         }
239
240         if (size == 0) {
241                 return 0;
242         }
243
244         tlss->pull.iov.iov_base = tlss->pull.buffer;
245         tlss->pull.iov.iov_len = MIN(size, sizeof(tlss->pull.buffer));
246
247         subreq = tstream_readv_send(tlss,
248                                     tlss->current_ev,
249                                     tlss->plain_stream,
250                                     &tlss->pull.iov, 1);
251         if (subreq == NULL) {
252                 errno = ENOMEM;
253                 return -1;
254         }
255         tevent_req_set_callback(subreq, tstream_tls_pull_done, stream);
256
257         tlss->pull.subreq = subreq;
258         errno = EAGAIN;
259         return -1;
260 }
261
262 static void tstream_tls_pull_done(struct tevent_req *subreq)
263 {
264         struct tstream_context *stream =
265                 tevent_req_callback_data(subreq,
266                 struct tstream_context);
267         struct tstream_tls *tlss =
268                 tstream_context_data(stream,
269                 struct tstream_tls);
270         int ret;
271         int sys_errno;
272
273         tlss->pull.subreq = NULL;
274
275         ret = tstream_readv_recv(subreq, &sys_errno);
276         TALLOC_FREE(subreq);
277         if (ret == -1) {
278                 tlss->error = sys_errno;
279                 tstream_tls_retry(stream, false);
280                 return;
281         }
282
283         tstream_tls_retry(stream, false);
284 }
285 #endif /* ENABLE_GNUTLS */
286
287 static int tstream_tls_destructor(struct tstream_tls *tlss)
288 {
289 #if ENABLE_GNUTLS
290         if (tlss->tls_session) {
291                 gnutls_deinit(tlss->tls_session);
292                 tlss->tls_session = NULL;
293         }
294 #endif /* ENABLE_GNUTLS */
295         return 0;
296 }
297
298 static ssize_t tstream_tls_pending_bytes(struct tstream_context *stream)
299 {
300         struct tstream_tls *tlss =
301                 tstream_context_data(stream,
302                 struct tstream_tls);
303         size_t ret;
304
305         if (tlss->error != 0) {
306                 errno = tlss->error;
307                 return -1;
308         }
309
310 #if ENABLE_GNUTLS
311         ret = gnutls_record_check_pending(tlss->tls_session);
312         ret += tlss->read.left;
313 #else /* ENABLE_GNUTLS */
314         errno = ENOSYS;
315         ret = -1;
316 #endif /* ENABLE_GNUTLS */
317         return ret;
318 }
319
320 struct tstream_tls_readv_state {
321         struct tstream_context *stream;
322
323         struct iovec *vector;
324         int count;
325
326         int ret;
327 };
328
329 static void tstream_tls_readv_crypt_next(struct tevent_req *req);
330
331 static struct tevent_req *tstream_tls_readv_send(TALLOC_CTX *mem_ctx,
332                                         struct tevent_context *ev,
333                                         struct tstream_context *stream,
334                                         struct iovec *vector,
335                                         size_t count)
336 {
337         struct tstream_tls *tlss =
338                 tstream_context_data(stream,
339                 struct tstream_tls);
340         struct tevent_req *req;
341         struct tstream_tls_readv_state *state;
342
343         tlss->read.req = NULL;
344         tlss->current_ev = ev;
345
346         req = tevent_req_create(mem_ctx, &state,
347                                 struct tstream_tls_readv_state);
348         if (req == NULL) {
349                 return NULL;
350         }
351
352         state->stream = stream;
353         state->ret = 0;
354
355         if (tlss->error != 0) {
356                 tevent_req_error(req, tlss->error);
357                 return tevent_req_post(req, ev);
358         }
359
360         /*
361          * we make a copy of the vector so we can change the structure
362          */
363         state->vector = talloc_array(state, struct iovec, count);
364         if (tevent_req_nomem(state->vector, req)) {
365                 return tevent_req_post(req, ev);
366         }
367         memcpy(state->vector, vector, sizeof(struct iovec) * count);
368         state->count = count;
369
370         tstream_tls_readv_crypt_next(req);
371         if (!tevent_req_is_in_progress(req)) {
372                 return tevent_req_post(req, ev);
373         }
374
375         return req;
376 }
377
378 static void tstream_tls_readv_crypt_next(struct tevent_req *req)
379 {
380         struct tstream_tls_readv_state *state =
381                 tevent_req_data(req,
382                 struct tstream_tls_readv_state);
383         struct tstream_tls *tlss =
384                 tstream_context_data(state->stream,
385                 struct tstream_tls);
386
387         /*
388          * copy the pending buffer first
389          */
390         while (tlss->read.left > 0 && state->count > 0) {
391                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
392                 size_t len = MIN(tlss->read.left, state->vector[0].iov_len);
393
394                 memcpy(base, tlss->read.buffer + tlss->read.ofs, len);
395
396                 base += len;
397                 state->vector[0].iov_base = base;
398                 state->vector[0].iov_len -= len;
399
400                 tlss->read.ofs += len;
401                 tlss->read.left -= len;
402
403                 if (state->vector[0].iov_len == 0) {
404                         state->vector += 1;
405                         state->count -= 1;
406                 }
407
408                 state->ret += len;
409         }
410
411         if (state->count == 0) {
412                 tevent_req_done(req);
413                 return;
414         }
415
416         tlss->read.req = req;
417         tstream_tls_retry_read(state->stream);
418 }
419
420 static void tstream_tls_retry_read(struct tstream_context *stream)
421 {
422         struct tstream_tls *tlss =
423                 tstream_context_data(stream,
424                 struct tstream_tls);
425         struct tevent_req *req = tlss->read.req;
426 #if ENABLE_GNUTLS
427         int ret;
428
429         if (tlss->error != 0) {
430                 tevent_req_error(req, tlss->error);
431                 return;
432         }
433
434         tlss->read.left = 0;
435         tlss->read.ofs = 0;
436
437         ret = gnutls_record_recv(tlss->tls_session,
438                                  tlss->read.buffer,
439                                  sizeof(tlss->read.buffer));
440         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
441                 return;
442         }
443
444         tlss->read.req = NULL;
445
446         if (gnutls_error_is_fatal(ret) != 0) {
447                 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
448                 tlss->error = EIO;
449                 tevent_req_error(req, tlss->error);
450                 return;
451         }
452
453         if (ret == 0) {
454                 tlss->error = EPIPE;
455                 tevent_req_error(req, tlss->error);
456                 return;
457         }
458
459         tlss->read.left = ret;
460         tstream_tls_readv_crypt_next(req);
461 #else /* ENABLE_GNUTLS */
462         tevent_req_error(req, ENOSYS);
463 #endif /* ENABLE_GNUTLS */
464 }
465
466 static int tstream_tls_readv_recv(struct tevent_req *req,
467                                   int *perrno)
468 {
469         struct tstream_tls_readv_state *state =
470                 tevent_req_data(req,
471                 struct tstream_tls_readv_state);
472         struct tstream_tls *tlss =
473                 tstream_context_data(state->stream,
474                 struct tstream_tls);
475         int ret;
476
477         tlss->read.req = NULL;
478
479         ret = tsocket_simple_int_recv(req, perrno);
480         if (ret == 0) {
481                 ret = state->ret;
482         }
483
484         tevent_req_received(req);
485         return ret;
486 }
487
488 struct tstream_tls_writev_state {
489         struct tstream_context *stream;
490
491         struct iovec *vector;
492         int count;
493
494         int ret;
495 };
496
497 static void tstream_tls_writev_crypt_next(struct tevent_req *req);
498
499 static struct tevent_req *tstream_tls_writev_send(TALLOC_CTX *mem_ctx,
500                                         struct tevent_context *ev,
501                                         struct tstream_context *stream,
502                                         const struct iovec *vector,
503                                         size_t count)
504 {
505         struct tstream_tls *tlss =
506                 tstream_context_data(stream,
507                 struct tstream_tls);
508         struct tevent_req *req;
509         struct tstream_tls_writev_state *state;
510
511         tlss->write.req = NULL;
512         tlss->current_ev = ev;
513
514         req = tevent_req_create(mem_ctx, &state,
515                                 struct tstream_tls_writev_state);
516         if (req == NULL) {
517                 return NULL;
518         }
519
520         state->stream = stream;
521         state->ret = 0;
522
523         if (tlss->error != 0) {
524                 tevent_req_error(req, tlss->error);
525                 return tevent_req_post(req, ev);
526         }
527
528         /*
529          * we make a copy of the vector so we can change the structure
530          */
531         state->vector = talloc_array(state, struct iovec, count);
532         if (tevent_req_nomem(state->vector, req)) {
533                 return tevent_req_post(req, ev);
534         }
535         memcpy(state->vector, vector, sizeof(struct iovec) * count);
536         state->count = count;
537
538         tstream_tls_writev_crypt_next(req);
539         if (!tevent_req_is_in_progress(req)) {
540                 return tevent_req_post(req, ev);
541         }
542
543         return req;
544 }
545
546 static void tstream_tls_writev_crypt_next(struct tevent_req *req)
547 {
548         struct tstream_tls_writev_state *state =
549                 tevent_req_data(req,
550                 struct tstream_tls_writev_state);
551         struct tstream_tls *tlss =
552                 tstream_context_data(state->stream,
553                 struct tstream_tls);
554
555         tlss->write.left = sizeof(tlss->write.buffer);
556         tlss->write.ofs = 0;
557
558         /*
559          * first fill our buffer
560          */
561         while (tlss->write.left > 0 && state->count > 0) {
562                 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
563                 size_t len = MIN(tlss->write.left, state->vector[0].iov_len);
564
565                 memcpy(tlss->write.buffer + tlss->write.ofs, base, len);
566
567                 base += len;
568                 state->vector[0].iov_base = base;
569                 state->vector[0].iov_len -= len;
570
571                 tlss->write.ofs += len;
572                 tlss->write.left -= len;
573
574                 if (state->vector[0].iov_len == 0) {
575                         state->vector += 1;
576                         state->count -= 1;
577                 }
578
579                 state->ret += len;
580         }
581
582         if (tlss->write.ofs == 0) {
583                 tevent_req_done(req);
584                 return;
585         }
586
587         tlss->write.left = tlss->write.ofs;
588         tlss->write.ofs = 0;
589
590         tlss->write.req = req;
591         tstream_tls_retry_write(state->stream);
592 }
593
594 static void tstream_tls_retry_write(struct tstream_context *stream)
595 {
596         struct tstream_tls *tlss =
597                 tstream_context_data(stream,
598                 struct tstream_tls);
599         struct tevent_req *req = tlss->write.req;
600 #if ENABLE_GNUTLS
601         int ret;
602
603         if (tlss->error != 0) {
604                 tevent_req_error(req, tlss->error);
605                 return;
606         }
607
608         ret = gnutls_record_send(tlss->tls_session,
609                                  tlss->write.buffer + tlss->write.ofs,
610                                  tlss->write.left);
611         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
612                 return;
613         }
614
615         tlss->write.req = NULL;
616
617         if (gnutls_error_is_fatal(ret) != 0) {
618                 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
619                 tlss->error = EIO;
620                 tevent_req_error(req, tlss->error);
621                 return;
622         }
623
624         if (ret == 0) {
625                 tlss->error = EPIPE;
626                 tevent_req_error(req, tlss->error);
627                 return;
628         }
629
630         tlss->write.ofs += ret;
631         tlss->write.left -= ret;
632
633         if (tlss->write.left > 0) {
634                 tlss->write.req = req;
635                 tstream_tls_retry_write(stream);
636                 return;
637         }
638
639         tstream_tls_writev_crypt_next(req);
640 #else /* ENABLE_GNUTLS */
641         tevent_req_error(req, ENOSYS);
642 #endif /* ENABLE_GNUTLS */
643 }
644
645 static int tstream_tls_writev_recv(struct tevent_req *req,
646                                    int *perrno)
647 {
648         struct tstream_tls_writev_state *state =
649                 tevent_req_data(req,
650                 struct tstream_tls_writev_state);
651         struct tstream_tls *tlss =
652                 tstream_context_data(state->stream,
653                 struct tstream_tls);
654         int ret;
655
656         tlss->write.req = NULL;
657
658         ret = tsocket_simple_int_recv(req, perrno);
659         if (ret == 0) {
660                 ret = state->ret;
661         }
662
663         tevent_req_received(req);
664         return ret;
665 }
666
667 struct tstream_tls_disconnect_state {
668         uint8_t _dummy;
669 };
670
671 static struct tevent_req *tstream_tls_disconnect_send(TALLOC_CTX *mem_ctx,
672                                                 struct tevent_context *ev,
673                                                 struct tstream_context *stream)
674 {
675         struct tstream_tls *tlss =
676                 tstream_context_data(stream,
677                 struct tstream_tls);
678         struct tevent_req *req;
679         struct tstream_tls_disconnect_state *state;
680
681         tlss->disconnect.req = NULL;
682         tlss->current_ev = ev;
683
684         req = tevent_req_create(mem_ctx, &state,
685                                 struct tstream_tls_disconnect_state);
686         if (req == NULL) {
687                 return NULL;
688         }
689
690         if (tlss->error != 0) {
691                 tevent_req_error(req, tlss->error);
692                 return tevent_req_post(req, ev);
693         }
694
695         tlss->disconnect.req = req;
696         tstream_tls_retry_disconnect(stream);
697         if (!tevent_req_is_in_progress(req)) {
698                 return tevent_req_post(req, ev);
699         }
700
701         return req;
702 }
703
704 static void tstream_tls_retry_disconnect(struct tstream_context *stream)
705 {
706         struct tstream_tls *tlss =
707                 tstream_context_data(stream,
708                 struct tstream_tls);
709         struct tevent_req *req = tlss->disconnect.req;
710 #if ENABLE_GNUTLS
711         int ret;
712
713         if (tlss->error != 0) {
714                 tevent_req_error(req, tlss->error);
715                 return;
716         }
717
718         ret = gnutls_bye(tlss->tls_session, GNUTLS_SHUT_WR);
719         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
720                 return;
721         }
722
723         tlss->disconnect.req = NULL;
724
725         if (gnutls_error_is_fatal(ret) != 0) {
726                 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
727                 tlss->error = EIO;
728                 tevent_req_error(req, tlss->error);
729                 return;
730         }
731
732         if (ret != GNUTLS_E_SUCCESS) {
733                 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
734                 tlss->error = EIO;
735                 tevent_req_error(req, tlss->error);
736                 return;
737         }
738
739         tevent_req_done(req);
740 #else /* ENABLE_GNUTLS */
741         tevent_req_error(req, ENOSYS);
742 #endif /* ENABLE_GNUTLS */
743 }
744
745 static int tstream_tls_disconnect_recv(struct tevent_req *req,
746                                        int *perrno)
747 {
748         int ret;
749
750         ret = tsocket_simple_int_recv(req, perrno);
751
752         tevent_req_received(req);
753         return ret;
754 }
755
756 static const struct tstream_context_ops tstream_tls_ops = {
757         .name                   = "tls",
758
759         .pending_bytes          = tstream_tls_pending_bytes,
760
761         .readv_send             = tstream_tls_readv_send,
762         .readv_recv             = tstream_tls_readv_recv,
763
764         .writev_send            = tstream_tls_writev_send,
765         .writev_recv            = tstream_tls_writev_recv,
766
767         .disconnect_send        = tstream_tls_disconnect_send,
768         .disconnect_recv        = tstream_tls_disconnect_recv,
769 };
770
771 struct tstream_tls_params {
772 #if ENABLE_GNUTLS
773         gnutls_certificate_credentials x509_cred;
774         gnutls_dh_params dh_params;
775 #endif /* ENABLE_GNUTLS */
776         bool tls_enabled;
777 };
778
779 static int tstream_tls_params_destructor(struct tstream_tls_params *tlsp)
780 {
781 #if ENABLE_GNUTLS
782         if (tlsp->x509_cred) {
783                 gnutls_certificate_free_credentials(tlsp->x509_cred);
784                 tlsp->x509_cred = NULL;
785         }
786         if (tlsp->dh_params) {
787                 gnutls_dh_params_deinit(tlsp->dh_params);
788                 tlsp->dh_params = NULL;
789         }
790 #endif /* ENABLE_GNUTLS */
791         return 0;
792 }
793
794 bool tstream_tls_params_enabled(struct tstream_tls_params *tlsp)
795 {
796         return tlsp->tls_enabled;
797 }
798
799 NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
800                                    const char *ca_file,
801                                    const char *crl_file,
802                                    struct tstream_tls_params **_tlsp)
803 {
804 #if ENABLE_GNUTLS
805         struct tstream_tls_params *tlsp;
806         int ret;
807
808         ret = gnutls_global_init();
809         if (ret != GNUTLS_E_SUCCESS) {
810                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
811                 return NT_STATUS_NOT_SUPPORTED;
812         }
813
814         tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
815         NT_STATUS_HAVE_NO_MEMORY(tlsp);
816
817         talloc_set_destructor(tlsp, tstream_tls_params_destructor);
818
819         ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
820         if (ret != GNUTLS_E_SUCCESS) {
821                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
822                 talloc_free(tlsp);
823                 return NT_STATUS_NO_MEMORY;
824         }
825
826         if (ca_file && *ca_file) {
827                 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
828                                                              ca_file,
829                                                              GNUTLS_X509_FMT_PEM);
830                 if (ret < 0) {
831                         DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
832                                  ca_file, gnutls_strerror(ret)));
833                         talloc_free(tlsp);
834                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
835                 }
836         }
837
838         if (crl_file && *crl_file) {
839                 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
840                                                            crl_file, 
841                                                            GNUTLS_X509_FMT_PEM);
842                 if (ret < 0) {
843                         DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
844                                  crl_file, gnutls_strerror(ret)));
845                         talloc_free(tlsp);
846                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
847                 }
848         }
849
850         tlsp->tls_enabled = true;
851
852         *_tlsp = tlsp;
853         return NT_STATUS_OK;
854 #else /* ENABLE_GNUTLS */
855         return NT_STATUS_NOT_IMPLEMENTED;
856 #endif /* ENABLE_GNUTLS */
857 }
858
859 struct tstream_tls_connect_state {
860         struct tstream_context *tls_stream;
861 };
862
863 struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
864                                              struct tevent_context *ev,
865                                              struct tstream_context *plain_stream,
866                                              struct tstream_tls_params *tls_params,
867                                              const char *location)
868 {
869         struct tevent_req *req;
870         struct tstream_tls_connect_state *state;
871 #if ENABLE_GNUTLS
872         struct tstream_tls *tlss;
873         int ret;
874         static const int cert_type_priority[] = {
875                 GNUTLS_CRT_X509,
876                 GNUTLS_CRT_OPENPGP,
877                 0
878         };
879 #endif /* ENABLE_GNUTLS */
880
881         req = tevent_req_create(mem_ctx, &state,
882                                 struct tstream_tls_connect_state);
883         if (req == NULL) {
884                 return NULL;
885         }
886
887 #if ENABLE_GNUTLS
888         state->tls_stream = tstream_context_create(state,
889                                                    &tstream_tls_ops,
890                                                    &tlss,
891                                                    struct tstream_tls,
892                                                    location);
893         if (tevent_req_nomem(state->tls_stream, req)) {
894                 return tevent_req_post(req, ev);
895         }
896         ZERO_STRUCTP(tlss);
897         talloc_set_destructor(tlss, tstream_tls_destructor);
898
899         tlss->plain_stream = plain_stream;
900
901         tlss->current_ev = ev;
902         tlss->im = tevent_create_immediate(tlss);
903         if (tevent_req_nomem(tlss->im, req)) {
904                 return tevent_req_post(req, ev);
905         }
906
907         ret = gnutls_init(&tlss->tls_session, GNUTLS_CLIENT);
908         if (ret != GNUTLS_E_SUCCESS) {
909                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
910                 tevent_req_error(req, EINVAL);
911                 return tevent_req_post(req, ev);
912         }
913
914         ret = gnutls_set_default_priority(tlss->tls_session);
915         if (ret != GNUTLS_E_SUCCESS) {
916                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
917                 tevent_req_error(req, EINVAL);
918                 return tevent_req_post(req, ev);
919         }
920
921         gnutls_certificate_type_set_priority(tlss->tls_session, cert_type_priority);
922
923         ret = gnutls_credentials_set(tlss->tls_session,
924                                      GNUTLS_CRD_CERTIFICATE,
925                                      tls_params->x509_cred);
926         if (ret != GNUTLS_E_SUCCESS) {
927                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
928                 tevent_req_error(req, EINVAL);
929                 return tevent_req_post(req, ev);
930         }
931
932         gnutls_transport_set_ptr(tlss->tls_session, (gnutls_transport_ptr)state->tls_stream);
933         gnutls_transport_set_pull_function(tlss->tls_session,
934                                            (gnutls_pull_func)tstream_tls_pull_function);
935         gnutls_transport_set_push_function(tlss->tls_session,
936                                            (gnutls_push_func)tstream_tls_push_function);
937         gnutls_transport_set_lowat(tlss->tls_session, 0);
938
939         tlss->handshake.req = req;
940         tstream_tls_retry_handshake(state->tls_stream);
941         if (!tevent_req_is_in_progress(req)) {
942                 return tevent_req_post(req, ev);
943         }
944
945         return req;
946 #else /* ENABLE_GNUTLS */
947         tevent_req_error(req, ENOSYS);
948         return tevent_req_post(req, ev);
949 #endif /* ENABLE_GNUTLS */
950 }
951
952 int tstream_tls_connect_recv(struct tevent_req *req,
953                              int *perrno,
954                              TALLOC_CTX *mem_ctx,
955                              struct tstream_context **tls_stream)
956 {
957         struct tstream_tls_connect_state *state =
958                 tevent_req_data(req,
959                 struct tstream_tls_connect_state);
960
961         if (tevent_req_is_unix_error(req, perrno)) {
962                 tevent_req_received(req);
963                 return -1;
964         }
965
966         *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
967         tevent_req_received(req);
968         return 0;
969 }
970
971 extern void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *, const char *);
972
973 /*
974   initialise global tls state
975 */
976 NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
977                                    const char *dns_host_name,
978                                    bool disable,
979                                    const char *key_file,
980                                    const char *cert_file,
981                                    const char *ca_file,
982                                    const char *crl_file,
983                                    const char *dhp_file,
984                                    struct tstream_tls_params **_tlsp)
985 {
986         struct tstream_tls_params *tlsp;
987 #if ENABLE_GNUTLS
988         int ret;
989
990         ret = gnutls_global_init();
991         if (ret != GNUTLS_E_SUCCESS) {
992                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
993                 return NT_STATUS_NOT_SUPPORTED;
994         }
995
996         tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
997         NT_STATUS_HAVE_NO_MEMORY(tlsp);
998
999         talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1000
1001         if (!file_exist(ca_file)) {
1002                 tls_cert_generate(tlsp, dns_host_name,
1003                                   key_file, cert_file, ca_file);
1004         }
1005
1006         ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
1007         if (ret != GNUTLS_E_SUCCESS) {
1008                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1009                 talloc_free(tlsp);
1010                 return NT_STATUS_NO_MEMORY;
1011         }
1012
1013         if (ca_file && *ca_file) {
1014                 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
1015                                                              ca_file,
1016                                                              GNUTLS_X509_FMT_PEM);
1017                 if (ret < 0) {
1018                         DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1019                                  ca_file, gnutls_strerror(ret)));
1020                         talloc_free(tlsp);
1021                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1022                 }
1023         }
1024
1025         if (crl_file && *crl_file) {
1026                 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
1027                                                            crl_file, 
1028                                                            GNUTLS_X509_FMT_PEM);
1029                 if (ret < 0) {
1030                         DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1031                                  crl_file, gnutls_strerror(ret)));
1032                         talloc_free(tlsp);
1033                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1034                 }
1035         }
1036
1037         ret = gnutls_certificate_set_x509_key_file(tlsp->x509_cred,
1038                                                    cert_file, key_file,
1039                                                    GNUTLS_X509_FMT_PEM);
1040         if (ret != GNUTLS_E_SUCCESS) {
1041                 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1042                          cert_file, key_file, gnutls_strerror(ret)));
1043                 talloc_free(tlsp);
1044                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1045         }
1046
1047         ret = gnutls_dh_params_init(&tlsp->dh_params);
1048         if (ret != GNUTLS_E_SUCCESS) {
1049                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1050                 talloc_free(tlsp);
1051                 return NT_STATUS_NO_MEMORY;
1052         }
1053
1054         if (dhp_file && *dhp_file) {
1055                 gnutls_datum_t dhparms;
1056                 size_t size;
1057
1058                 dhparms.data = (uint8_t *)file_load(dhp_file, &size, 0, tlsp);
1059
1060                 if (!dhparms.data) {
1061                         DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1062                                  dhp_file, errno, strerror(errno)));
1063                         talloc_free(tlsp);
1064                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1065                 }
1066                 dhparms.size = size;
1067
1068                 ret = gnutls_dh_params_import_pkcs3(tlsp->dh_params,
1069                                                     &dhparms,
1070                                                     GNUTLS_X509_FMT_PEM);
1071                 if (ret != GNUTLS_E_SUCCESS) {
1072                         DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1073                                  dhp_file, gnutls_strerror(ret)));
1074                         talloc_free(tlsp);
1075                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1076                 }
1077         } else {
1078                 ret = gnutls_dh_params_generate2(tlsp->dh_params, DH_BITS);
1079                 if (ret != GNUTLS_E_SUCCESS) {
1080                         DEBUG(0,("TLS failed to generate dh_params - %s\n",
1081                                  gnutls_strerror(ret)));
1082                         talloc_free(tlsp);
1083                         return NT_STATUS_INTERNAL_ERROR;
1084                 }
1085         }
1086
1087         gnutls_certificate_set_dh_params(tlsp->x509_cred, tlsp->dh_params);
1088
1089         tlsp->tls_enabled = true;
1090
1091 #else /* ENABLE_GNUTLS */
1092         tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1093         NT_STATUS_HAVE_NO_MEMORY(tlsp);
1094         talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1095         tlsp->tls_enabled = false;
1096 #endif /* ENABLE_GNUTLS */
1097
1098         *_tlsp = tlsp;
1099         return NT_STATUS_OK;
1100 }
1101
1102 struct tstream_tls_accept_state {
1103         struct tstream_context *tls_stream;
1104 };
1105
1106 struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
1107                                             struct tevent_context *ev,
1108                                             struct tstream_context *plain_stream,
1109                                             struct tstream_tls_params *tlsp,
1110                                             const char *location)
1111 {
1112         struct tevent_req *req;
1113         struct tstream_tls_accept_state *state;
1114         struct tstream_tls *tlss;
1115 #if ENABLE_GNUTLS
1116         int ret;
1117 #endif /* ENABLE_GNUTLS */
1118
1119         req = tevent_req_create(mem_ctx, &state,
1120                                 struct tstream_tls_accept_state);
1121         if (req == NULL) {
1122                 return NULL;
1123         }
1124
1125         state->tls_stream = tstream_context_create(state,
1126                                                    &tstream_tls_ops,
1127                                                    &tlss,
1128                                                    struct tstream_tls,
1129                                                    location);
1130         if (tevent_req_nomem(state->tls_stream, req)) {
1131                 return tevent_req_post(req, ev);
1132         }
1133         ZERO_STRUCTP(tlss);
1134         talloc_set_destructor(tlss, tstream_tls_destructor);
1135
1136 #if ENABLE_GNUTLS
1137         tlss->plain_stream = plain_stream;
1138
1139         tlss->current_ev = ev;
1140         tlss->im = tevent_create_immediate(tlss);
1141         if (tevent_req_nomem(tlss->im, req)) {
1142                 return tevent_req_post(req, ev);
1143         }
1144
1145         ret = gnutls_init(&tlss->tls_session, GNUTLS_SERVER);
1146         if (ret != GNUTLS_E_SUCCESS) {
1147                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1148                 tevent_req_error(req, EINVAL);
1149                 return tevent_req_post(req, ev);
1150         }
1151
1152         ret = gnutls_set_default_priority(tlss->tls_session);
1153         if (ret != GNUTLS_E_SUCCESS) {
1154                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1155                 tevent_req_error(req, EINVAL);
1156                 return tevent_req_post(req, ev);
1157         }
1158
1159         ret = gnutls_credentials_set(tlss->tls_session, GNUTLS_CRD_CERTIFICATE,
1160                                      tlsp->x509_cred);
1161         if (ret != GNUTLS_E_SUCCESS) {
1162                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1163                 tevent_req_error(req, EINVAL);
1164                 return tevent_req_post(req, ev);
1165         }
1166
1167         gnutls_certificate_server_set_request(tlss->tls_session,
1168                                               GNUTLS_CERT_REQUEST);
1169         gnutls_dh_set_prime_bits(tlss->tls_session, DH_BITS);
1170
1171         gnutls_transport_set_ptr(tlss->tls_session, (gnutls_transport_ptr)state->tls_stream);
1172         gnutls_transport_set_pull_function(tlss->tls_session,
1173                                            (gnutls_pull_func)tstream_tls_pull_function);
1174         gnutls_transport_set_push_function(tlss->tls_session,
1175                                            (gnutls_push_func)tstream_tls_push_function);
1176         gnutls_transport_set_lowat(tlss->tls_session, 0);
1177
1178         tlss->handshake.req = req;
1179         tstream_tls_retry_handshake(state->tls_stream);
1180         if (!tevent_req_is_in_progress(req)) {
1181                 return tevent_req_post(req, ev);
1182         }
1183
1184         return req;
1185 #else /* ENABLE_GNUTLS */
1186         tevent_req_error(req, ENOSYS);
1187         return tevent_req_post(req, ev);
1188 #endif /* ENABLE_GNUTLS */
1189 }
1190
1191 static void tstream_tls_retry_handshake(struct tstream_context *stream)
1192 {
1193         struct tstream_tls *tlss =
1194                 tstream_context_data(stream,
1195                 struct tstream_tls);
1196         struct tevent_req *req = tlss->handshake.req;
1197 #if ENABLE_GNUTLS
1198         int ret;
1199
1200         if (tlss->error != 0) {
1201                 tevent_req_error(req, tlss->error);
1202                 return;
1203         }
1204
1205         ret = gnutls_handshake(tlss->tls_session);
1206         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
1207                 return;
1208         }
1209
1210         tlss->handshake.req = NULL;
1211
1212         if (gnutls_error_is_fatal(ret) != 0) {
1213                 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1214                 tlss->error = EIO;
1215                 tevent_req_error(req, tlss->error);
1216                 return;
1217         }
1218
1219         if (ret != GNUTLS_E_SUCCESS) {
1220                 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1221                 tlss->error = EIO;
1222                 tevent_req_error(req, tlss->error);
1223                 return;
1224         }
1225
1226         tevent_req_done(req);
1227 #else /* ENABLE_GNUTLS */
1228         tevent_req_error(req, ENOSYS);
1229 #endif /* ENABLE_GNUTLS */
1230 }
1231
1232 int tstream_tls_accept_recv(struct tevent_req *req,
1233                             int *perrno,
1234                             TALLOC_CTX *mem_ctx,
1235                             struct tstream_context **tls_stream)
1236 {
1237         struct tstream_tls_accept_state *state =
1238                 tevent_req_data(req,
1239                 struct tstream_tls_accept_state);
1240
1241         if (tevent_req_is_unix_error(req, perrno)) {
1242                 tevent_req_received(req);
1243                 return -1;
1244         }
1245
1246         *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1247         tevent_req_received(req);
1248         return 0;
1249 }