s4:lib/tls: fix enabled logic in tstream_tls_params_server()
[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 enabled,
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         if (!enabled || key_file == NULL || *key_file == 0) {
991                 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
992                 NT_STATUS_HAVE_NO_MEMORY(tlsp);
993                 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
994                 tlsp->tls_enabled = false;
995
996                 *_tlsp = tlsp;
997                 return NT_STATUS_OK;
998         }
999
1000         ret = gnutls_global_init();
1001         if (ret != GNUTLS_E_SUCCESS) {
1002                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1003                 return NT_STATUS_NOT_SUPPORTED;
1004         }
1005
1006         tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1007         NT_STATUS_HAVE_NO_MEMORY(tlsp);
1008
1009         talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1010
1011         if (!file_exist(ca_file)) {
1012                 tls_cert_generate(tlsp, dns_host_name,
1013                                   key_file, cert_file, ca_file);
1014         }
1015
1016         ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
1017         if (ret != GNUTLS_E_SUCCESS) {
1018                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1019                 talloc_free(tlsp);
1020                 return NT_STATUS_NO_MEMORY;
1021         }
1022
1023         if (ca_file && *ca_file) {
1024                 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
1025                                                              ca_file,
1026                                                              GNUTLS_X509_FMT_PEM);
1027                 if (ret < 0) {
1028                         DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1029                                  ca_file, gnutls_strerror(ret)));
1030                         talloc_free(tlsp);
1031                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1032                 }
1033         }
1034
1035         if (crl_file && *crl_file) {
1036                 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
1037                                                            crl_file, 
1038                                                            GNUTLS_X509_FMT_PEM);
1039                 if (ret < 0) {
1040                         DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1041                                  crl_file, gnutls_strerror(ret)));
1042                         talloc_free(tlsp);
1043                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1044                 }
1045         }
1046
1047         ret = gnutls_certificate_set_x509_key_file(tlsp->x509_cred,
1048                                                    cert_file, key_file,
1049                                                    GNUTLS_X509_FMT_PEM);
1050         if (ret != GNUTLS_E_SUCCESS) {
1051                 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1052                          cert_file, key_file, gnutls_strerror(ret)));
1053                 talloc_free(tlsp);
1054                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1055         }
1056
1057         ret = gnutls_dh_params_init(&tlsp->dh_params);
1058         if (ret != GNUTLS_E_SUCCESS) {
1059                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1060                 talloc_free(tlsp);
1061                 return NT_STATUS_NO_MEMORY;
1062         }
1063
1064         if (dhp_file && *dhp_file) {
1065                 gnutls_datum_t dhparms;
1066                 size_t size;
1067
1068                 dhparms.data = (uint8_t *)file_load(dhp_file, &size, 0, tlsp);
1069
1070                 if (!dhparms.data) {
1071                         DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1072                                  dhp_file, errno, strerror(errno)));
1073                         talloc_free(tlsp);
1074                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1075                 }
1076                 dhparms.size = size;
1077
1078                 ret = gnutls_dh_params_import_pkcs3(tlsp->dh_params,
1079                                                     &dhparms,
1080                                                     GNUTLS_X509_FMT_PEM);
1081                 if (ret != GNUTLS_E_SUCCESS) {
1082                         DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1083                                  dhp_file, gnutls_strerror(ret)));
1084                         talloc_free(tlsp);
1085                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1086                 }
1087         } else {
1088                 ret = gnutls_dh_params_generate2(tlsp->dh_params, DH_BITS);
1089                 if (ret != GNUTLS_E_SUCCESS) {
1090                         DEBUG(0,("TLS failed to generate dh_params - %s\n",
1091                                  gnutls_strerror(ret)));
1092                         talloc_free(tlsp);
1093                         return NT_STATUS_INTERNAL_ERROR;
1094                 }
1095         }
1096
1097         gnutls_certificate_set_dh_params(tlsp->x509_cred, tlsp->dh_params);
1098
1099         tlsp->tls_enabled = true;
1100
1101 #else /* ENABLE_GNUTLS */
1102         tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1103         NT_STATUS_HAVE_NO_MEMORY(tlsp);
1104         talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1105         tlsp->tls_enabled = false;
1106 #endif /* ENABLE_GNUTLS */
1107
1108         *_tlsp = tlsp;
1109         return NT_STATUS_OK;
1110 }
1111
1112 struct tstream_tls_accept_state {
1113         struct tstream_context *tls_stream;
1114 };
1115
1116 struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
1117                                             struct tevent_context *ev,
1118                                             struct tstream_context *plain_stream,
1119                                             struct tstream_tls_params *tlsp,
1120                                             const char *location)
1121 {
1122         struct tevent_req *req;
1123         struct tstream_tls_accept_state *state;
1124         struct tstream_tls *tlss;
1125 #if ENABLE_GNUTLS
1126         int ret;
1127 #endif /* ENABLE_GNUTLS */
1128
1129         req = tevent_req_create(mem_ctx, &state,
1130                                 struct tstream_tls_accept_state);
1131         if (req == NULL) {
1132                 return NULL;
1133         }
1134
1135         state->tls_stream = tstream_context_create(state,
1136                                                    &tstream_tls_ops,
1137                                                    &tlss,
1138                                                    struct tstream_tls,
1139                                                    location);
1140         if (tevent_req_nomem(state->tls_stream, req)) {
1141                 return tevent_req_post(req, ev);
1142         }
1143         ZERO_STRUCTP(tlss);
1144         talloc_set_destructor(tlss, tstream_tls_destructor);
1145
1146 #if ENABLE_GNUTLS
1147         tlss->plain_stream = plain_stream;
1148
1149         tlss->current_ev = ev;
1150         tlss->im = tevent_create_immediate(tlss);
1151         if (tevent_req_nomem(tlss->im, req)) {
1152                 return tevent_req_post(req, ev);
1153         }
1154
1155         ret = gnutls_init(&tlss->tls_session, GNUTLS_SERVER);
1156         if (ret != GNUTLS_E_SUCCESS) {
1157                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1158                 tevent_req_error(req, EINVAL);
1159                 return tevent_req_post(req, ev);
1160         }
1161
1162         ret = gnutls_set_default_priority(tlss->tls_session);
1163         if (ret != GNUTLS_E_SUCCESS) {
1164                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1165                 tevent_req_error(req, EINVAL);
1166                 return tevent_req_post(req, ev);
1167         }
1168
1169         ret = gnutls_credentials_set(tlss->tls_session, GNUTLS_CRD_CERTIFICATE,
1170                                      tlsp->x509_cred);
1171         if (ret != GNUTLS_E_SUCCESS) {
1172                 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1173                 tevent_req_error(req, EINVAL);
1174                 return tevent_req_post(req, ev);
1175         }
1176
1177         gnutls_certificate_server_set_request(tlss->tls_session,
1178                                               GNUTLS_CERT_REQUEST);
1179         gnutls_dh_set_prime_bits(tlss->tls_session, DH_BITS);
1180
1181         gnutls_transport_set_ptr(tlss->tls_session, (gnutls_transport_ptr)state->tls_stream);
1182         gnutls_transport_set_pull_function(tlss->tls_session,
1183                                            (gnutls_pull_func)tstream_tls_pull_function);
1184         gnutls_transport_set_push_function(tlss->tls_session,
1185                                            (gnutls_push_func)tstream_tls_push_function);
1186         gnutls_transport_set_lowat(tlss->tls_session, 0);
1187
1188         tlss->handshake.req = req;
1189         tstream_tls_retry_handshake(state->tls_stream);
1190         if (!tevent_req_is_in_progress(req)) {
1191                 return tevent_req_post(req, ev);
1192         }
1193
1194         return req;
1195 #else /* ENABLE_GNUTLS */
1196         tevent_req_error(req, ENOSYS);
1197         return tevent_req_post(req, ev);
1198 #endif /* ENABLE_GNUTLS */
1199 }
1200
1201 static void tstream_tls_retry_handshake(struct tstream_context *stream)
1202 {
1203         struct tstream_tls *tlss =
1204                 tstream_context_data(stream,
1205                 struct tstream_tls);
1206         struct tevent_req *req = tlss->handshake.req;
1207 #if ENABLE_GNUTLS
1208         int ret;
1209
1210         if (tlss->error != 0) {
1211                 tevent_req_error(req, tlss->error);
1212                 return;
1213         }
1214
1215         ret = gnutls_handshake(tlss->tls_session);
1216         if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
1217                 return;
1218         }
1219
1220         tlss->handshake.req = NULL;
1221
1222         if (gnutls_error_is_fatal(ret) != 0) {
1223                 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1224                 tlss->error = EIO;
1225                 tevent_req_error(req, tlss->error);
1226                 return;
1227         }
1228
1229         if (ret != GNUTLS_E_SUCCESS) {
1230                 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1231                 tlss->error = EIO;
1232                 tevent_req_error(req, tlss->error);
1233                 return;
1234         }
1235
1236         tevent_req_done(req);
1237 #else /* ENABLE_GNUTLS */
1238         tevent_req_error(req, ENOSYS);
1239 #endif /* ENABLE_GNUTLS */
1240 }
1241
1242 int tstream_tls_accept_recv(struct tevent_req *req,
1243                             int *perrno,
1244                             TALLOC_CTX *mem_ctx,
1245                             struct tstream_context **tls_stream)
1246 {
1247         struct tstream_tls_accept_state *state =
1248                 tevent_req_data(req,
1249                 struct tstream_tls_accept_state);
1250
1251         if (tevent_req_is_unix_error(req, perrno)) {
1252                 tevent_req_received(req);
1253                 return -1;
1254         }
1255
1256         *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1257         tevent_req_received(req);
1258         return 0;
1259 }