2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2010
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.
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.
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/>.
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"
28 #include "gnutls/gnutls.h"
32 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
33 typedef gnutls_datum gnutls_datum_t;
36 #endif /* ENABLE_GNUTLS */
38 static const struct tstream_context_ops tstream_tls_ops;
41 struct tstream_context *plain_stream;
45 gnutls_session tls_session;
46 #endif /* ENABLE_GNUTLS */
48 struct tevent_context *current_ev;
50 struct tevent_immediate *retry_im;
56 struct tevent_req *subreq;
57 struct tevent_immediate *im;
63 struct tevent_req *subreq;
67 struct tevent_req *req;
74 struct tevent_req *req;
81 struct tevent_req *req;
85 struct tevent_req *req;
89 static void tstream_tls_retry_handshake(struct tstream_context *stream);
90 static void tstream_tls_retry_read(struct tstream_context *stream);
91 static void tstream_tls_retry_write(struct tstream_context *stream);
92 static void tstream_tls_retry_disconnect(struct tstream_context *stream);
93 static void tstream_tls_retry_trigger(struct tevent_context *ctx,
94 struct tevent_immediate *im,
97 static void tstream_tls_retry(struct tstream_context *stream, bool deferred)
100 struct tstream_tls *tlss =
101 tstream_context_data(stream,
104 if (tlss->disconnect.req) {
105 tstream_tls_retry_disconnect(stream);
109 if (tlss->handshake.req) {
110 tstream_tls_retry_handshake(stream);
114 if (tlss->write.req && tlss->read.req && !deferred) {
115 tevent_schedule_immediate(tlss->retry_im, tlss->current_ev,
116 tstream_tls_retry_trigger,
120 if (tlss->write.req) {
121 tstream_tls_retry_write(stream);
125 if (tlss->read.req) {
126 tstream_tls_retry_read(stream);
131 static void tstream_tls_retry_trigger(struct tevent_context *ctx,
132 struct tevent_immediate *im,
135 struct tstream_context *stream =
136 talloc_get_type_abort(private_data,
137 struct tstream_context);
139 tstream_tls_retry(stream, true);
143 static void tstream_tls_push_trigger_write(struct tevent_context *ev,
144 struct tevent_immediate *im,
147 static ssize_t tstream_tls_push_function(gnutls_transport_ptr ptr,
148 const void *buf, size_t size)
150 struct tstream_context *stream =
151 talloc_get_type_abort(ptr,
152 struct tstream_context);
153 struct tstream_tls *tlss =
154 tstream_context_data(stream,
159 if (tlss->error != 0) {
164 if (tlss->push.subreq) {
169 len = MIN(size, UINT16_MAX - tlss->push.ofs);
176 nbuf = talloc_realloc(tlss, tlss->push.buf,
177 uint8_t, tlss->push.ofs + len);
179 if (tlss->push.buf) {
186 tlss->push.buf = nbuf;
188 memcpy(tlss->push.buf + tlss->push.ofs, buf, len);
190 if (tlss->push.im == NULL) {
191 tlss->push.im = tevent_create_immediate(tlss);
192 if (tlss->push.im == NULL) {
198 if (tlss->push.ofs == 0) {
200 * We'll do start the tstream_writev
201 * in the next event cycle.
203 * This way we can batch all push requests,
204 * if they fit into a UINT16_MAX buffer.
206 * This is important as gnutls_handshake()
207 * had a bug in some versions e.g. 2.4.1
208 * and others (See bug #7218) and it doesn't
211 tevent_schedule_immediate(tlss->push.im,
213 tstream_tls_push_trigger_write,
217 tlss->push.ofs += len;
221 static void tstream_tls_push_done(struct tevent_req *subreq);
223 static void tstream_tls_push_trigger_write(struct tevent_context *ev,
224 struct tevent_immediate *im,
227 struct tstream_context *stream =
228 talloc_get_type_abort(private_data,
229 struct tstream_context);
230 struct tstream_tls *tlss =
231 tstream_context_data(stream,
233 struct tevent_req *subreq;
235 if (tlss->push.subreq) {
240 tlss->push.iov.iov_base = (char *)tlss->push.buf;
241 tlss->push.iov.iov_len = tlss->push.ofs;
243 subreq = tstream_writev_send(tlss,
247 if (subreq == NULL) {
248 tlss->error = ENOMEM;
249 tstream_tls_retry(stream, false);
252 tevent_req_set_callback(subreq, tstream_tls_push_done, stream);
254 tlss->push.subreq = subreq;
257 static void tstream_tls_push_done(struct tevent_req *subreq)
259 struct tstream_context *stream =
260 tevent_req_callback_data(subreq,
261 struct tstream_context);
262 struct tstream_tls *tlss =
263 tstream_context_data(stream,
268 tlss->push.subreq = NULL;
269 ZERO_STRUCT(tlss->push.iov);
270 TALLOC_FREE(tlss->push.buf);
273 ret = tstream_writev_recv(subreq, &sys_errno);
276 tlss->error = sys_errno;
277 tstream_tls_retry(stream, false);
281 tstream_tls_retry(stream, false);
284 static void tstream_tls_pull_done(struct tevent_req *subreq);
286 static ssize_t tstream_tls_pull_function(gnutls_transport_ptr ptr,
287 void *buf, size_t size)
289 struct tstream_context *stream =
290 talloc_get_type_abort(ptr,
291 struct tstream_context);
292 struct tstream_tls *tlss =
293 tstream_context_data(stream,
295 struct tevent_req *subreq;
297 if (tlss->error != 0) {
302 if (tlss->pull.subreq) {
307 if (tlss->pull.iov.iov_base) {
310 n = MIN(tlss->pull.iov.iov_len, size);
311 memcpy(buf, tlss->pull.iov.iov_base, n);
313 tlss->pull.iov.iov_len -= n;
314 if (tlss->pull.iov.iov_len == 0) {
315 tlss->pull.iov.iov_base = NULL;
325 tlss->pull.iov.iov_base = tlss->pull.buffer;
326 tlss->pull.iov.iov_len = MIN(size, sizeof(tlss->pull.buffer));
328 subreq = tstream_readv_send(tlss,
332 if (subreq == NULL) {
336 tevent_req_set_callback(subreq, tstream_tls_pull_done, stream);
338 tlss->pull.subreq = subreq;
343 static void tstream_tls_pull_done(struct tevent_req *subreq)
345 struct tstream_context *stream =
346 tevent_req_callback_data(subreq,
347 struct tstream_context);
348 struct tstream_tls *tlss =
349 tstream_context_data(stream,
354 tlss->pull.subreq = NULL;
356 ret = tstream_readv_recv(subreq, &sys_errno);
359 tlss->error = sys_errno;
360 tstream_tls_retry(stream, false);
364 tstream_tls_retry(stream, false);
366 #endif /* ENABLE_GNUTLS */
368 static int tstream_tls_destructor(struct tstream_tls *tlss)
371 if (tlss->tls_session) {
372 gnutls_deinit(tlss->tls_session);
373 tlss->tls_session = NULL;
375 #endif /* ENABLE_GNUTLS */
379 static ssize_t tstream_tls_pending_bytes(struct tstream_context *stream)
381 struct tstream_tls *tlss =
382 tstream_context_data(stream,
386 if (tlss->error != 0) {
392 ret = gnutls_record_check_pending(tlss->tls_session);
393 ret += tlss->read.left;
394 #else /* ENABLE_GNUTLS */
397 #endif /* ENABLE_GNUTLS */
401 struct tstream_tls_readv_state {
402 struct tstream_context *stream;
404 struct iovec *vector;
410 static void tstream_tls_readv_crypt_next(struct tevent_req *req);
412 static struct tevent_req *tstream_tls_readv_send(TALLOC_CTX *mem_ctx,
413 struct tevent_context *ev,
414 struct tstream_context *stream,
415 struct iovec *vector,
418 struct tstream_tls *tlss =
419 tstream_context_data(stream,
421 struct tevent_req *req;
422 struct tstream_tls_readv_state *state;
424 tlss->read.req = NULL;
425 tlss->current_ev = ev;
427 req = tevent_req_create(mem_ctx, &state,
428 struct tstream_tls_readv_state);
433 state->stream = stream;
436 if (tlss->error != 0) {
437 tevent_req_error(req, tlss->error);
438 return tevent_req_post(req, ev);
442 * we make a copy of the vector so we can change the structure
444 state->vector = talloc_array(state, struct iovec, count);
445 if (tevent_req_nomem(state->vector, req)) {
446 return tevent_req_post(req, ev);
448 memcpy(state->vector, vector, sizeof(struct iovec) * count);
449 state->count = count;
451 tstream_tls_readv_crypt_next(req);
452 if (!tevent_req_is_in_progress(req)) {
453 return tevent_req_post(req, ev);
459 static void tstream_tls_readv_crypt_next(struct tevent_req *req)
461 struct tstream_tls_readv_state *state =
463 struct tstream_tls_readv_state);
464 struct tstream_tls *tlss =
465 tstream_context_data(state->stream,
469 * copy the pending buffer first
471 while (tlss->read.left > 0 && state->count > 0) {
472 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
473 size_t len = MIN(tlss->read.left, state->vector[0].iov_len);
475 memcpy(base, tlss->read.buffer + tlss->read.ofs, len);
478 state->vector[0].iov_base = base;
479 state->vector[0].iov_len -= len;
481 tlss->read.ofs += len;
482 tlss->read.left -= len;
484 if (state->vector[0].iov_len == 0) {
492 if (state->count == 0) {
493 tevent_req_done(req);
497 tlss->read.req = req;
498 tstream_tls_retry_read(state->stream);
501 static void tstream_tls_retry_read(struct tstream_context *stream)
503 struct tstream_tls *tlss =
504 tstream_context_data(stream,
506 struct tevent_req *req = tlss->read.req;
510 if (tlss->error != 0) {
511 tevent_req_error(req, tlss->error);
518 ret = gnutls_record_recv(tlss->tls_session,
520 sizeof(tlss->read.buffer));
521 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
525 tlss->read.req = NULL;
527 if (gnutls_error_is_fatal(ret) != 0) {
528 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
530 tevent_req_error(req, tlss->error);
536 tevent_req_error(req, tlss->error);
540 tlss->read.left = ret;
541 tstream_tls_readv_crypt_next(req);
542 #else /* ENABLE_GNUTLS */
543 tevent_req_error(req, ENOSYS);
544 #endif /* ENABLE_GNUTLS */
547 static int tstream_tls_readv_recv(struct tevent_req *req,
550 struct tstream_tls_readv_state *state =
552 struct tstream_tls_readv_state);
553 struct tstream_tls *tlss =
554 tstream_context_data(state->stream,
558 tlss->read.req = NULL;
560 ret = tsocket_simple_int_recv(req, perrno);
565 tevent_req_received(req);
569 struct tstream_tls_writev_state {
570 struct tstream_context *stream;
572 struct iovec *vector;
578 static void tstream_tls_writev_crypt_next(struct tevent_req *req);
580 static struct tevent_req *tstream_tls_writev_send(TALLOC_CTX *mem_ctx,
581 struct tevent_context *ev,
582 struct tstream_context *stream,
583 const struct iovec *vector,
586 struct tstream_tls *tlss =
587 tstream_context_data(stream,
589 struct tevent_req *req;
590 struct tstream_tls_writev_state *state;
592 tlss->write.req = NULL;
593 tlss->current_ev = ev;
595 req = tevent_req_create(mem_ctx, &state,
596 struct tstream_tls_writev_state);
601 state->stream = stream;
604 if (tlss->error != 0) {
605 tevent_req_error(req, tlss->error);
606 return tevent_req_post(req, ev);
610 * we make a copy of the vector so we can change the structure
612 state->vector = talloc_array(state, struct iovec, count);
613 if (tevent_req_nomem(state->vector, req)) {
614 return tevent_req_post(req, ev);
616 memcpy(state->vector, vector, sizeof(struct iovec) * count);
617 state->count = count;
619 tstream_tls_writev_crypt_next(req);
620 if (!tevent_req_is_in_progress(req)) {
621 return tevent_req_post(req, ev);
627 static void tstream_tls_writev_crypt_next(struct tevent_req *req)
629 struct tstream_tls_writev_state *state =
631 struct tstream_tls_writev_state);
632 struct tstream_tls *tlss =
633 tstream_context_data(state->stream,
636 tlss->write.left = sizeof(tlss->write.buffer);
640 * first fill our buffer
642 while (tlss->write.left > 0 && state->count > 0) {
643 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
644 size_t len = MIN(tlss->write.left, state->vector[0].iov_len);
646 memcpy(tlss->write.buffer + tlss->write.ofs, base, len);
649 state->vector[0].iov_base = base;
650 state->vector[0].iov_len -= len;
652 tlss->write.ofs += len;
653 tlss->write.left -= len;
655 if (state->vector[0].iov_len == 0) {
663 if (tlss->write.ofs == 0) {
664 tevent_req_done(req);
668 tlss->write.left = tlss->write.ofs;
671 tlss->write.req = req;
672 tstream_tls_retry_write(state->stream);
675 static void tstream_tls_retry_write(struct tstream_context *stream)
677 struct tstream_tls *tlss =
678 tstream_context_data(stream,
680 struct tevent_req *req = tlss->write.req;
684 if (tlss->error != 0) {
685 tevent_req_error(req, tlss->error);
689 ret = gnutls_record_send(tlss->tls_session,
690 tlss->write.buffer + tlss->write.ofs,
692 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
696 tlss->write.req = NULL;
698 if (gnutls_error_is_fatal(ret) != 0) {
699 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
701 tevent_req_error(req, tlss->error);
707 tevent_req_error(req, tlss->error);
711 tlss->write.ofs += ret;
712 tlss->write.left -= ret;
714 if (tlss->write.left > 0) {
715 tlss->write.req = req;
716 tstream_tls_retry_write(stream);
720 tstream_tls_writev_crypt_next(req);
721 #else /* ENABLE_GNUTLS */
722 tevent_req_error(req, ENOSYS);
723 #endif /* ENABLE_GNUTLS */
726 static int tstream_tls_writev_recv(struct tevent_req *req,
729 struct tstream_tls_writev_state *state =
731 struct tstream_tls_writev_state);
732 struct tstream_tls *tlss =
733 tstream_context_data(state->stream,
737 tlss->write.req = NULL;
739 ret = tsocket_simple_int_recv(req, perrno);
744 tevent_req_received(req);
748 struct tstream_tls_disconnect_state {
752 static struct tevent_req *tstream_tls_disconnect_send(TALLOC_CTX *mem_ctx,
753 struct tevent_context *ev,
754 struct tstream_context *stream)
756 struct tstream_tls *tlss =
757 tstream_context_data(stream,
759 struct tevent_req *req;
760 struct tstream_tls_disconnect_state *state;
762 tlss->disconnect.req = NULL;
763 tlss->current_ev = ev;
765 req = tevent_req_create(mem_ctx, &state,
766 struct tstream_tls_disconnect_state);
771 if (tlss->error != 0) {
772 tevent_req_error(req, tlss->error);
773 return tevent_req_post(req, ev);
776 tlss->disconnect.req = req;
777 tstream_tls_retry_disconnect(stream);
778 if (!tevent_req_is_in_progress(req)) {
779 return tevent_req_post(req, ev);
785 static void tstream_tls_retry_disconnect(struct tstream_context *stream)
787 struct tstream_tls *tlss =
788 tstream_context_data(stream,
790 struct tevent_req *req = tlss->disconnect.req;
794 if (tlss->error != 0) {
795 tevent_req_error(req, tlss->error);
799 ret = gnutls_bye(tlss->tls_session, GNUTLS_SHUT_WR);
800 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
804 tlss->disconnect.req = NULL;
806 if (gnutls_error_is_fatal(ret) != 0) {
807 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
809 tevent_req_error(req, tlss->error);
813 if (ret != GNUTLS_E_SUCCESS) {
814 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
816 tevent_req_error(req, tlss->error);
820 tevent_req_done(req);
821 #else /* ENABLE_GNUTLS */
822 tevent_req_error(req, ENOSYS);
823 #endif /* ENABLE_GNUTLS */
826 static int tstream_tls_disconnect_recv(struct tevent_req *req,
831 ret = tsocket_simple_int_recv(req, perrno);
833 tevent_req_received(req);
837 static const struct tstream_context_ops tstream_tls_ops = {
840 .pending_bytes = tstream_tls_pending_bytes,
842 .readv_send = tstream_tls_readv_send,
843 .readv_recv = tstream_tls_readv_recv,
845 .writev_send = tstream_tls_writev_send,
846 .writev_recv = tstream_tls_writev_recv,
848 .disconnect_send = tstream_tls_disconnect_send,
849 .disconnect_recv = tstream_tls_disconnect_recv,
852 struct tstream_tls_params {
854 gnutls_certificate_credentials x509_cred;
855 gnutls_dh_params dh_params;
856 #endif /* ENABLE_GNUTLS */
860 static int tstream_tls_params_destructor(struct tstream_tls_params *tlsp)
863 if (tlsp->x509_cred) {
864 gnutls_certificate_free_credentials(tlsp->x509_cred);
865 tlsp->x509_cred = NULL;
867 if (tlsp->dh_params) {
868 gnutls_dh_params_deinit(tlsp->dh_params);
869 tlsp->dh_params = NULL;
871 #endif /* ENABLE_GNUTLS */
875 bool tstream_tls_params_enabled(struct tstream_tls_params *tlsp)
877 return tlsp->tls_enabled;
880 NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
882 const char *crl_file,
883 struct tstream_tls_params **_tlsp)
886 struct tstream_tls_params *tlsp;
889 ret = gnutls_global_init();
890 if (ret != GNUTLS_E_SUCCESS) {
891 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
892 return NT_STATUS_NOT_SUPPORTED;
895 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
896 NT_STATUS_HAVE_NO_MEMORY(tlsp);
898 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
900 ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
901 if (ret != GNUTLS_E_SUCCESS) {
902 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
904 return NT_STATUS_NO_MEMORY;
907 if (ca_file && *ca_file) {
908 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
910 GNUTLS_X509_FMT_PEM);
912 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
913 ca_file, gnutls_strerror(ret)));
915 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
919 if (crl_file && *crl_file) {
920 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
922 GNUTLS_X509_FMT_PEM);
924 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
925 crl_file, gnutls_strerror(ret)));
927 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
931 tlsp->tls_enabled = true;
935 #else /* ENABLE_GNUTLS */
936 return NT_STATUS_NOT_IMPLEMENTED;
937 #endif /* ENABLE_GNUTLS */
940 struct tstream_tls_connect_state {
941 struct tstream_context *tls_stream;
944 struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
945 struct tevent_context *ev,
946 struct tstream_context *plain_stream,
947 struct tstream_tls_params *tls_params,
948 const char *location)
950 struct tevent_req *req;
951 struct tstream_tls_connect_state *state;
953 struct tstream_tls *tlss;
955 static const int cert_type_priority[] = {
960 #endif /* ENABLE_GNUTLS */
962 req = tevent_req_create(mem_ctx, &state,
963 struct tstream_tls_connect_state);
969 state->tls_stream = tstream_context_create(state,
974 if (tevent_req_nomem(state->tls_stream, req)) {
975 return tevent_req_post(req, ev);
978 talloc_set_destructor(tlss, tstream_tls_destructor);
980 tlss->plain_stream = plain_stream;
982 tlss->current_ev = ev;
983 tlss->retry_im = tevent_create_immediate(tlss);
984 if (tevent_req_nomem(tlss->retry_im, req)) {
985 return tevent_req_post(req, ev);
988 ret = gnutls_init(&tlss->tls_session, GNUTLS_CLIENT);
989 if (ret != GNUTLS_E_SUCCESS) {
990 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
991 tevent_req_error(req, EINVAL);
992 return tevent_req_post(req, ev);
995 ret = gnutls_set_default_priority(tlss->tls_session);
996 if (ret != GNUTLS_E_SUCCESS) {
997 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
998 tevent_req_error(req, EINVAL);
999 return tevent_req_post(req, ev);
1002 gnutls_certificate_type_set_priority(tlss->tls_session, cert_type_priority);
1004 ret = gnutls_credentials_set(tlss->tls_session,
1005 GNUTLS_CRD_CERTIFICATE,
1006 tls_params->x509_cred);
1007 if (ret != GNUTLS_E_SUCCESS) {
1008 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1009 tevent_req_error(req, EINVAL);
1010 return tevent_req_post(req, ev);
1013 gnutls_transport_set_ptr(tlss->tls_session, (gnutls_transport_ptr)state->tls_stream);
1014 gnutls_transport_set_pull_function(tlss->tls_session,
1015 (gnutls_pull_func)tstream_tls_pull_function);
1016 gnutls_transport_set_push_function(tlss->tls_session,
1017 (gnutls_push_func)tstream_tls_push_function);
1018 gnutls_transport_set_lowat(tlss->tls_session, 0);
1020 tlss->handshake.req = req;
1021 tstream_tls_retry_handshake(state->tls_stream);
1022 if (!tevent_req_is_in_progress(req)) {
1023 return tevent_req_post(req, ev);
1027 #else /* ENABLE_GNUTLS */
1028 tevent_req_error(req, ENOSYS);
1029 return tevent_req_post(req, ev);
1030 #endif /* ENABLE_GNUTLS */
1033 int tstream_tls_connect_recv(struct tevent_req *req,
1035 TALLOC_CTX *mem_ctx,
1036 struct tstream_context **tls_stream)
1038 struct tstream_tls_connect_state *state =
1039 tevent_req_data(req,
1040 struct tstream_tls_connect_state);
1042 if (tevent_req_is_unix_error(req, perrno)) {
1043 tevent_req_received(req);
1047 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1048 tevent_req_received(req);
1052 extern void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *, const char *);
1055 initialise global tls state
1057 NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
1058 const char *dns_host_name,
1060 const char *key_file,
1061 const char *cert_file,
1062 const char *ca_file,
1063 const char *crl_file,
1064 const char *dhp_file,
1065 struct tstream_tls_params **_tlsp)
1067 struct tstream_tls_params *tlsp;
1071 if (!enabled || key_file == NULL || *key_file == 0) {
1072 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1073 NT_STATUS_HAVE_NO_MEMORY(tlsp);
1074 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1075 tlsp->tls_enabled = false;
1078 return NT_STATUS_OK;
1081 ret = gnutls_global_init();
1082 if (ret != GNUTLS_E_SUCCESS) {
1083 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1084 return NT_STATUS_NOT_SUPPORTED;
1087 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1088 NT_STATUS_HAVE_NO_MEMORY(tlsp);
1090 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1092 if (!file_exist(ca_file)) {
1093 tls_cert_generate(tlsp, dns_host_name,
1094 key_file, cert_file, ca_file);
1097 ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
1098 if (ret != GNUTLS_E_SUCCESS) {
1099 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1101 return NT_STATUS_NO_MEMORY;
1104 if (ca_file && *ca_file) {
1105 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
1107 GNUTLS_X509_FMT_PEM);
1109 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1110 ca_file, gnutls_strerror(ret)));
1112 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1116 if (crl_file && *crl_file) {
1117 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
1119 GNUTLS_X509_FMT_PEM);
1121 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1122 crl_file, gnutls_strerror(ret)));
1124 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1128 ret = gnutls_certificate_set_x509_key_file(tlsp->x509_cred,
1129 cert_file, key_file,
1130 GNUTLS_X509_FMT_PEM);
1131 if (ret != GNUTLS_E_SUCCESS) {
1132 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1133 cert_file, key_file, gnutls_strerror(ret)));
1135 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1138 ret = gnutls_dh_params_init(&tlsp->dh_params);
1139 if (ret != GNUTLS_E_SUCCESS) {
1140 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1142 return NT_STATUS_NO_MEMORY;
1145 if (dhp_file && *dhp_file) {
1146 gnutls_datum_t dhparms;
1149 dhparms.data = (uint8_t *)file_load(dhp_file, &size, 0, tlsp);
1151 if (!dhparms.data) {
1152 DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1153 dhp_file, errno, strerror(errno)));
1155 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1157 dhparms.size = size;
1159 ret = gnutls_dh_params_import_pkcs3(tlsp->dh_params,
1161 GNUTLS_X509_FMT_PEM);
1162 if (ret != GNUTLS_E_SUCCESS) {
1163 DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1164 dhp_file, gnutls_strerror(ret)));
1166 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1169 ret = gnutls_dh_params_generate2(tlsp->dh_params, DH_BITS);
1170 if (ret != GNUTLS_E_SUCCESS) {
1171 DEBUG(0,("TLS failed to generate dh_params - %s\n",
1172 gnutls_strerror(ret)));
1174 return NT_STATUS_INTERNAL_ERROR;
1178 gnutls_certificate_set_dh_params(tlsp->x509_cred, tlsp->dh_params);
1180 tlsp->tls_enabled = true;
1182 #else /* ENABLE_GNUTLS */
1183 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1184 NT_STATUS_HAVE_NO_MEMORY(tlsp);
1185 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1186 tlsp->tls_enabled = false;
1187 #endif /* ENABLE_GNUTLS */
1190 return NT_STATUS_OK;
1193 struct tstream_tls_accept_state {
1194 struct tstream_context *tls_stream;
1197 struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
1198 struct tevent_context *ev,
1199 struct tstream_context *plain_stream,
1200 struct tstream_tls_params *tlsp,
1201 const char *location)
1203 struct tevent_req *req;
1204 struct tstream_tls_accept_state *state;
1205 struct tstream_tls *tlss;
1208 #endif /* ENABLE_GNUTLS */
1210 req = tevent_req_create(mem_ctx, &state,
1211 struct tstream_tls_accept_state);
1216 state->tls_stream = tstream_context_create(state,
1221 if (tevent_req_nomem(state->tls_stream, req)) {
1222 return tevent_req_post(req, ev);
1225 talloc_set_destructor(tlss, tstream_tls_destructor);
1228 tlss->plain_stream = plain_stream;
1230 tlss->current_ev = ev;
1231 tlss->retry_im = tevent_create_immediate(tlss);
1232 if (tevent_req_nomem(tlss->retry_im, req)) {
1233 return tevent_req_post(req, ev);
1236 ret = gnutls_init(&tlss->tls_session, GNUTLS_SERVER);
1237 if (ret != GNUTLS_E_SUCCESS) {
1238 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1239 tevent_req_error(req, EINVAL);
1240 return tevent_req_post(req, ev);
1243 ret = gnutls_set_default_priority(tlss->tls_session);
1244 if (ret != GNUTLS_E_SUCCESS) {
1245 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1246 tevent_req_error(req, EINVAL);
1247 return tevent_req_post(req, ev);
1250 ret = gnutls_credentials_set(tlss->tls_session, GNUTLS_CRD_CERTIFICATE,
1252 if (ret != GNUTLS_E_SUCCESS) {
1253 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1254 tevent_req_error(req, EINVAL);
1255 return tevent_req_post(req, ev);
1258 gnutls_certificate_server_set_request(tlss->tls_session,
1259 GNUTLS_CERT_REQUEST);
1260 gnutls_dh_set_prime_bits(tlss->tls_session, DH_BITS);
1262 gnutls_transport_set_ptr(tlss->tls_session, (gnutls_transport_ptr)state->tls_stream);
1263 gnutls_transport_set_pull_function(tlss->tls_session,
1264 (gnutls_pull_func)tstream_tls_pull_function);
1265 gnutls_transport_set_push_function(tlss->tls_session,
1266 (gnutls_push_func)tstream_tls_push_function);
1267 gnutls_transport_set_lowat(tlss->tls_session, 0);
1269 tlss->handshake.req = req;
1270 tstream_tls_retry_handshake(state->tls_stream);
1271 if (!tevent_req_is_in_progress(req)) {
1272 return tevent_req_post(req, ev);
1276 #else /* ENABLE_GNUTLS */
1277 tevent_req_error(req, ENOSYS);
1278 return tevent_req_post(req, ev);
1279 #endif /* ENABLE_GNUTLS */
1282 static void tstream_tls_retry_handshake(struct tstream_context *stream)
1284 struct tstream_tls *tlss =
1285 tstream_context_data(stream,
1286 struct tstream_tls);
1287 struct tevent_req *req = tlss->handshake.req;
1291 if (tlss->error != 0) {
1292 tevent_req_error(req, tlss->error);
1296 ret = gnutls_handshake(tlss->tls_session);
1297 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
1301 tlss->handshake.req = NULL;
1303 if (gnutls_error_is_fatal(ret) != 0) {
1304 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1306 tevent_req_error(req, tlss->error);
1310 if (ret != GNUTLS_E_SUCCESS) {
1311 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1313 tevent_req_error(req, tlss->error);
1317 tevent_req_done(req);
1318 #else /* ENABLE_GNUTLS */
1319 tevent_req_error(req, ENOSYS);
1320 #endif /* ENABLE_GNUTLS */
1323 int tstream_tls_accept_recv(struct tevent_req *req,
1325 TALLOC_CTX *mem_ctx,
1326 struct tstream_context **tls_stream)
1328 struct tstream_tls_accept_state *state =
1329 tevent_req_data(req,
1330 struct tstream_tls_accept_state);
1332 if (tevent_req_is_unix_error(req, perrno)) {
1333 tevent_req_received(req);
1337 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1338 tevent_req_received(req);