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) {
311 b = (uint8_t *)tlss->pull.iov.iov_base;
313 n = MIN(tlss->pull.iov.iov_len, size);
316 tlss->pull.iov.iov_len -= n;
318 tlss->pull.iov.iov_base = (char *)b;
319 if (tlss->pull.iov.iov_len == 0) {
320 tlss->pull.iov.iov_base = NULL;
330 tlss->pull.iov.iov_base = tlss->pull.buffer;
331 tlss->pull.iov.iov_len = MIN(size, sizeof(tlss->pull.buffer));
333 subreq = tstream_readv_send(tlss,
337 if (subreq == NULL) {
341 tevent_req_set_callback(subreq, tstream_tls_pull_done, stream);
343 tlss->pull.subreq = subreq;
348 static void tstream_tls_pull_done(struct tevent_req *subreq)
350 struct tstream_context *stream =
351 tevent_req_callback_data(subreq,
352 struct tstream_context);
353 struct tstream_tls *tlss =
354 tstream_context_data(stream,
359 tlss->pull.subreq = NULL;
361 ret = tstream_readv_recv(subreq, &sys_errno);
364 tlss->error = sys_errno;
365 tstream_tls_retry(stream, false);
369 tstream_tls_retry(stream, false);
371 #endif /* ENABLE_GNUTLS */
373 static int tstream_tls_destructor(struct tstream_tls *tlss)
376 if (tlss->tls_session) {
377 gnutls_deinit(tlss->tls_session);
378 tlss->tls_session = NULL;
380 #endif /* ENABLE_GNUTLS */
384 static ssize_t tstream_tls_pending_bytes(struct tstream_context *stream)
386 struct tstream_tls *tlss =
387 tstream_context_data(stream,
391 if (tlss->error != 0) {
397 ret = gnutls_record_check_pending(tlss->tls_session);
398 ret += tlss->read.left;
399 #else /* ENABLE_GNUTLS */
402 #endif /* ENABLE_GNUTLS */
406 struct tstream_tls_readv_state {
407 struct tstream_context *stream;
409 struct iovec *vector;
415 static void tstream_tls_readv_crypt_next(struct tevent_req *req);
417 static struct tevent_req *tstream_tls_readv_send(TALLOC_CTX *mem_ctx,
418 struct tevent_context *ev,
419 struct tstream_context *stream,
420 struct iovec *vector,
423 struct tstream_tls *tlss =
424 tstream_context_data(stream,
426 struct tevent_req *req;
427 struct tstream_tls_readv_state *state;
429 tlss->read.req = NULL;
430 tlss->current_ev = ev;
432 req = tevent_req_create(mem_ctx, &state,
433 struct tstream_tls_readv_state);
438 state->stream = stream;
441 if (tlss->error != 0) {
442 tevent_req_error(req, tlss->error);
443 return tevent_req_post(req, ev);
447 * we make a copy of the vector so we can change the structure
449 state->vector = talloc_array(state, struct iovec, count);
450 if (tevent_req_nomem(state->vector, req)) {
451 return tevent_req_post(req, ev);
453 memcpy(state->vector, vector, sizeof(struct iovec) * count);
454 state->count = count;
456 tstream_tls_readv_crypt_next(req);
457 if (!tevent_req_is_in_progress(req)) {
458 return tevent_req_post(req, ev);
464 static void tstream_tls_readv_crypt_next(struct tevent_req *req)
466 struct tstream_tls_readv_state *state =
468 struct tstream_tls_readv_state);
469 struct tstream_tls *tlss =
470 tstream_context_data(state->stream,
474 * copy the pending buffer first
476 while (tlss->read.left > 0 && state->count > 0) {
477 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
478 size_t len = MIN(tlss->read.left, state->vector[0].iov_len);
480 memcpy(base, tlss->read.buffer + tlss->read.ofs, len);
483 state->vector[0].iov_base = (char *) base;
484 state->vector[0].iov_len -= len;
486 tlss->read.ofs += len;
487 tlss->read.left -= len;
489 if (state->vector[0].iov_len == 0) {
497 if (state->count == 0) {
498 tevent_req_done(req);
502 tlss->read.req = req;
503 tstream_tls_retry_read(state->stream);
506 static void tstream_tls_retry_read(struct tstream_context *stream)
508 struct tstream_tls *tlss =
509 tstream_context_data(stream,
511 struct tevent_req *req = tlss->read.req;
515 if (tlss->error != 0) {
516 tevent_req_error(req, tlss->error);
523 ret = gnutls_record_recv(tlss->tls_session,
525 sizeof(tlss->read.buffer));
526 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
530 tlss->read.req = NULL;
532 if (gnutls_error_is_fatal(ret) != 0) {
533 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
535 tevent_req_error(req, tlss->error);
541 tevent_req_error(req, tlss->error);
545 tlss->read.left = ret;
546 tstream_tls_readv_crypt_next(req);
547 #else /* ENABLE_GNUTLS */
548 tevent_req_error(req, ENOSYS);
549 #endif /* ENABLE_GNUTLS */
552 static int tstream_tls_readv_recv(struct tevent_req *req,
555 struct tstream_tls_readv_state *state =
557 struct tstream_tls_readv_state);
558 struct tstream_tls *tlss =
559 tstream_context_data(state->stream,
563 tlss->read.req = NULL;
565 ret = tsocket_simple_int_recv(req, perrno);
570 tevent_req_received(req);
574 struct tstream_tls_writev_state {
575 struct tstream_context *stream;
577 struct iovec *vector;
583 static void tstream_tls_writev_crypt_next(struct tevent_req *req);
585 static struct tevent_req *tstream_tls_writev_send(TALLOC_CTX *mem_ctx,
586 struct tevent_context *ev,
587 struct tstream_context *stream,
588 const struct iovec *vector,
591 struct tstream_tls *tlss =
592 tstream_context_data(stream,
594 struct tevent_req *req;
595 struct tstream_tls_writev_state *state;
597 tlss->write.req = NULL;
598 tlss->current_ev = ev;
600 req = tevent_req_create(mem_ctx, &state,
601 struct tstream_tls_writev_state);
606 state->stream = stream;
609 if (tlss->error != 0) {
610 tevent_req_error(req, tlss->error);
611 return tevent_req_post(req, ev);
615 * we make a copy of the vector so we can change the structure
617 state->vector = talloc_array(state, struct iovec, count);
618 if (tevent_req_nomem(state->vector, req)) {
619 return tevent_req_post(req, ev);
621 memcpy(state->vector, vector, sizeof(struct iovec) * count);
622 state->count = count;
624 tstream_tls_writev_crypt_next(req);
625 if (!tevent_req_is_in_progress(req)) {
626 return tevent_req_post(req, ev);
632 static void tstream_tls_writev_crypt_next(struct tevent_req *req)
634 struct tstream_tls_writev_state *state =
636 struct tstream_tls_writev_state);
637 struct tstream_tls *tlss =
638 tstream_context_data(state->stream,
641 tlss->write.left = sizeof(tlss->write.buffer);
645 * first fill our buffer
647 while (tlss->write.left > 0 && state->count > 0) {
648 uint8_t *base = (uint8_t *)state->vector[0].iov_base;
649 size_t len = MIN(tlss->write.left, state->vector[0].iov_len);
651 memcpy(tlss->write.buffer + tlss->write.ofs, base, len);
654 state->vector[0].iov_base = (char *) base;
655 state->vector[0].iov_len -= len;
657 tlss->write.ofs += len;
658 tlss->write.left -= len;
660 if (state->vector[0].iov_len == 0) {
668 if (tlss->write.ofs == 0) {
669 tevent_req_done(req);
673 tlss->write.left = tlss->write.ofs;
676 tlss->write.req = req;
677 tstream_tls_retry_write(state->stream);
680 static void tstream_tls_retry_write(struct tstream_context *stream)
682 struct tstream_tls *tlss =
683 tstream_context_data(stream,
685 struct tevent_req *req = tlss->write.req;
689 if (tlss->error != 0) {
690 tevent_req_error(req, tlss->error);
694 ret = gnutls_record_send(tlss->tls_session,
695 tlss->write.buffer + tlss->write.ofs,
697 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
701 tlss->write.req = NULL;
703 if (gnutls_error_is_fatal(ret) != 0) {
704 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
706 tevent_req_error(req, tlss->error);
712 tevent_req_error(req, tlss->error);
716 tlss->write.ofs += ret;
717 tlss->write.left -= ret;
719 if (tlss->write.left > 0) {
720 tlss->write.req = req;
721 tstream_tls_retry_write(stream);
725 tstream_tls_writev_crypt_next(req);
726 #else /* ENABLE_GNUTLS */
727 tevent_req_error(req, ENOSYS);
728 #endif /* ENABLE_GNUTLS */
731 static int tstream_tls_writev_recv(struct tevent_req *req,
734 struct tstream_tls_writev_state *state =
736 struct tstream_tls_writev_state);
737 struct tstream_tls *tlss =
738 tstream_context_data(state->stream,
742 tlss->write.req = NULL;
744 ret = tsocket_simple_int_recv(req, perrno);
749 tevent_req_received(req);
753 struct tstream_tls_disconnect_state {
757 static struct tevent_req *tstream_tls_disconnect_send(TALLOC_CTX *mem_ctx,
758 struct tevent_context *ev,
759 struct tstream_context *stream)
761 struct tstream_tls *tlss =
762 tstream_context_data(stream,
764 struct tevent_req *req;
765 struct tstream_tls_disconnect_state *state;
767 tlss->disconnect.req = NULL;
768 tlss->current_ev = ev;
770 req = tevent_req_create(mem_ctx, &state,
771 struct tstream_tls_disconnect_state);
776 if (tlss->error != 0) {
777 tevent_req_error(req, tlss->error);
778 return tevent_req_post(req, ev);
781 tlss->disconnect.req = req;
782 tstream_tls_retry_disconnect(stream);
783 if (!tevent_req_is_in_progress(req)) {
784 return tevent_req_post(req, ev);
790 static void tstream_tls_retry_disconnect(struct tstream_context *stream)
792 struct tstream_tls *tlss =
793 tstream_context_data(stream,
795 struct tevent_req *req = tlss->disconnect.req;
799 if (tlss->error != 0) {
800 tevent_req_error(req, tlss->error);
804 ret = gnutls_bye(tlss->tls_session, GNUTLS_SHUT_WR);
805 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
809 tlss->disconnect.req = NULL;
811 if (gnutls_error_is_fatal(ret) != 0) {
812 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
814 tevent_req_error(req, tlss->error);
818 if (ret != GNUTLS_E_SUCCESS) {
819 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
821 tevent_req_error(req, tlss->error);
825 tevent_req_done(req);
826 #else /* ENABLE_GNUTLS */
827 tevent_req_error(req, ENOSYS);
828 #endif /* ENABLE_GNUTLS */
831 static int tstream_tls_disconnect_recv(struct tevent_req *req,
836 ret = tsocket_simple_int_recv(req, perrno);
838 tevent_req_received(req);
842 static const struct tstream_context_ops tstream_tls_ops = {
845 .pending_bytes = tstream_tls_pending_bytes,
847 .readv_send = tstream_tls_readv_send,
848 .readv_recv = tstream_tls_readv_recv,
850 .writev_send = tstream_tls_writev_send,
851 .writev_recv = tstream_tls_writev_recv,
853 .disconnect_send = tstream_tls_disconnect_send,
854 .disconnect_recv = tstream_tls_disconnect_recv,
857 struct tstream_tls_params {
859 gnutls_certificate_credentials x509_cred;
860 gnutls_dh_params dh_params;
861 #endif /* ENABLE_GNUTLS */
865 static int tstream_tls_params_destructor(struct tstream_tls_params *tlsp)
868 if (tlsp->x509_cred) {
869 gnutls_certificate_free_credentials(tlsp->x509_cred);
870 tlsp->x509_cred = NULL;
872 if (tlsp->dh_params) {
873 gnutls_dh_params_deinit(tlsp->dh_params);
874 tlsp->dh_params = NULL;
876 #endif /* ENABLE_GNUTLS */
880 bool tstream_tls_params_enabled(struct tstream_tls_params *tlsp)
882 return tlsp->tls_enabled;
885 NTSTATUS tstream_tls_params_client(TALLOC_CTX *mem_ctx,
887 const char *crl_file,
888 struct tstream_tls_params **_tlsp)
891 struct tstream_tls_params *tlsp;
894 ret = gnutls_global_init();
895 if (ret != GNUTLS_E_SUCCESS) {
896 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
897 return NT_STATUS_NOT_SUPPORTED;
900 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
901 NT_STATUS_HAVE_NO_MEMORY(tlsp);
903 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
905 ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
906 if (ret != GNUTLS_E_SUCCESS) {
907 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
909 return NT_STATUS_NO_MEMORY;
912 if (ca_file && *ca_file) {
913 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
915 GNUTLS_X509_FMT_PEM);
917 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
918 ca_file, gnutls_strerror(ret)));
920 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
924 if (crl_file && *crl_file) {
925 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
927 GNUTLS_X509_FMT_PEM);
929 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
930 crl_file, gnutls_strerror(ret)));
932 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
936 tlsp->tls_enabled = true;
940 #else /* ENABLE_GNUTLS */
941 return NT_STATUS_NOT_IMPLEMENTED;
942 #endif /* ENABLE_GNUTLS */
945 struct tstream_tls_connect_state {
946 struct tstream_context *tls_stream;
949 struct tevent_req *_tstream_tls_connect_send(TALLOC_CTX *mem_ctx,
950 struct tevent_context *ev,
951 struct tstream_context *plain_stream,
952 struct tstream_tls_params *tls_params,
953 const char *location)
955 struct tevent_req *req;
956 struct tstream_tls_connect_state *state;
958 struct tstream_tls *tlss;
960 static const int cert_type_priority[] = {
965 #endif /* ENABLE_GNUTLS */
967 req = tevent_req_create(mem_ctx, &state,
968 struct tstream_tls_connect_state);
974 state->tls_stream = tstream_context_create(state,
979 if (tevent_req_nomem(state->tls_stream, req)) {
980 return tevent_req_post(req, ev);
983 talloc_set_destructor(tlss, tstream_tls_destructor);
985 tlss->plain_stream = plain_stream;
987 tlss->current_ev = ev;
988 tlss->retry_im = tevent_create_immediate(tlss);
989 if (tevent_req_nomem(tlss->retry_im, req)) {
990 return tevent_req_post(req, ev);
993 ret = gnutls_init(&tlss->tls_session, GNUTLS_CLIENT);
994 if (ret != GNUTLS_E_SUCCESS) {
995 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
996 tevent_req_error(req, EINVAL);
997 return tevent_req_post(req, ev);
1000 ret = gnutls_set_default_priority(tlss->tls_session);
1001 if (ret != GNUTLS_E_SUCCESS) {
1002 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1003 tevent_req_error(req, EINVAL);
1004 return tevent_req_post(req, ev);
1007 gnutls_certificate_type_set_priority(tlss->tls_session, cert_type_priority);
1009 ret = gnutls_credentials_set(tlss->tls_session,
1010 GNUTLS_CRD_CERTIFICATE,
1011 tls_params->x509_cred);
1012 if (ret != GNUTLS_E_SUCCESS) {
1013 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1014 tevent_req_error(req, EINVAL);
1015 return tevent_req_post(req, ev);
1018 gnutls_transport_set_ptr(tlss->tls_session, (gnutls_transport_ptr)state->tls_stream);
1019 gnutls_transport_set_pull_function(tlss->tls_session,
1020 (gnutls_pull_func)tstream_tls_pull_function);
1021 gnutls_transport_set_push_function(tlss->tls_session,
1022 (gnutls_push_func)tstream_tls_push_function);
1023 gnutls_transport_set_lowat(tlss->tls_session, 0);
1025 tlss->handshake.req = req;
1026 tstream_tls_retry_handshake(state->tls_stream);
1027 if (!tevent_req_is_in_progress(req)) {
1028 return tevent_req_post(req, ev);
1032 #else /* ENABLE_GNUTLS */
1033 tevent_req_error(req, ENOSYS);
1034 return tevent_req_post(req, ev);
1035 #endif /* ENABLE_GNUTLS */
1038 int tstream_tls_connect_recv(struct tevent_req *req,
1040 TALLOC_CTX *mem_ctx,
1041 struct tstream_context **tls_stream)
1043 struct tstream_tls_connect_state *state =
1044 tevent_req_data(req,
1045 struct tstream_tls_connect_state);
1047 if (tevent_req_is_unix_error(req, perrno)) {
1048 tevent_req_received(req);
1052 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1053 tevent_req_received(req);
1057 extern void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *, const char *);
1060 initialise global tls state
1062 NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx,
1063 const char *dns_host_name,
1065 const char *key_file,
1066 const char *cert_file,
1067 const char *ca_file,
1068 const char *crl_file,
1069 const char *dhp_file,
1070 struct tstream_tls_params **_tlsp)
1072 struct tstream_tls_params *tlsp;
1076 if (!enabled || key_file == NULL || *key_file == 0) {
1077 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1078 NT_STATUS_HAVE_NO_MEMORY(tlsp);
1079 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1080 tlsp->tls_enabled = false;
1083 return NT_STATUS_OK;
1086 ret = gnutls_global_init();
1087 if (ret != GNUTLS_E_SUCCESS) {
1088 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1089 return NT_STATUS_NOT_SUPPORTED;
1092 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1093 NT_STATUS_HAVE_NO_MEMORY(tlsp);
1095 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1097 if (!file_exist(ca_file)) {
1098 tls_cert_generate(tlsp, dns_host_name,
1099 key_file, cert_file, ca_file);
1102 ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred);
1103 if (ret != GNUTLS_E_SUCCESS) {
1104 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1106 return NT_STATUS_NO_MEMORY;
1109 if (ca_file && *ca_file) {
1110 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
1112 GNUTLS_X509_FMT_PEM);
1114 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1115 ca_file, gnutls_strerror(ret)));
1117 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1121 if (crl_file && *crl_file) {
1122 ret = gnutls_certificate_set_x509_crl_file(tlsp->x509_cred,
1124 GNUTLS_X509_FMT_PEM);
1126 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1127 crl_file, gnutls_strerror(ret)));
1129 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1133 ret = gnutls_certificate_set_x509_key_file(tlsp->x509_cred,
1134 cert_file, key_file,
1135 GNUTLS_X509_FMT_PEM);
1136 if (ret != GNUTLS_E_SUCCESS) {
1137 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1138 cert_file, key_file, gnutls_strerror(ret)));
1140 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1143 ret = gnutls_dh_params_init(&tlsp->dh_params);
1144 if (ret != GNUTLS_E_SUCCESS) {
1145 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1147 return NT_STATUS_NO_MEMORY;
1150 if (dhp_file && *dhp_file) {
1151 gnutls_datum_t dhparms;
1154 dhparms.data = (uint8_t *)file_load(dhp_file, &size, 0, tlsp);
1156 if (!dhparms.data) {
1157 DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1158 dhp_file, errno, strerror(errno)));
1160 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1162 dhparms.size = size;
1164 ret = gnutls_dh_params_import_pkcs3(tlsp->dh_params,
1166 GNUTLS_X509_FMT_PEM);
1167 if (ret != GNUTLS_E_SUCCESS) {
1168 DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1169 dhp_file, gnutls_strerror(ret)));
1171 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1174 ret = gnutls_dh_params_generate2(tlsp->dh_params, DH_BITS);
1175 if (ret != GNUTLS_E_SUCCESS) {
1176 DEBUG(0,("TLS failed to generate dh_params - %s\n",
1177 gnutls_strerror(ret)));
1179 return NT_STATUS_INTERNAL_ERROR;
1183 gnutls_certificate_set_dh_params(tlsp->x509_cred, tlsp->dh_params);
1185 tlsp->tls_enabled = true;
1187 #else /* ENABLE_GNUTLS */
1188 tlsp = talloc_zero(mem_ctx, struct tstream_tls_params);
1189 NT_STATUS_HAVE_NO_MEMORY(tlsp);
1190 talloc_set_destructor(tlsp, tstream_tls_params_destructor);
1191 tlsp->tls_enabled = false;
1192 #endif /* ENABLE_GNUTLS */
1195 return NT_STATUS_OK;
1198 struct tstream_tls_accept_state {
1199 struct tstream_context *tls_stream;
1202 struct tevent_req *_tstream_tls_accept_send(TALLOC_CTX *mem_ctx,
1203 struct tevent_context *ev,
1204 struct tstream_context *plain_stream,
1205 struct tstream_tls_params *tlsp,
1206 const char *location)
1208 struct tevent_req *req;
1209 struct tstream_tls_accept_state *state;
1210 struct tstream_tls *tlss;
1213 #endif /* ENABLE_GNUTLS */
1215 req = tevent_req_create(mem_ctx, &state,
1216 struct tstream_tls_accept_state);
1221 state->tls_stream = tstream_context_create(state,
1226 if (tevent_req_nomem(state->tls_stream, req)) {
1227 return tevent_req_post(req, ev);
1230 talloc_set_destructor(tlss, tstream_tls_destructor);
1233 tlss->plain_stream = plain_stream;
1235 tlss->current_ev = ev;
1236 tlss->retry_im = tevent_create_immediate(tlss);
1237 if (tevent_req_nomem(tlss->retry_im, req)) {
1238 return tevent_req_post(req, ev);
1241 ret = gnutls_init(&tlss->tls_session, GNUTLS_SERVER);
1242 if (ret != GNUTLS_E_SUCCESS) {
1243 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1244 tevent_req_error(req, EINVAL);
1245 return tevent_req_post(req, ev);
1248 ret = gnutls_set_default_priority(tlss->tls_session);
1249 if (ret != GNUTLS_E_SUCCESS) {
1250 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1251 tevent_req_error(req, EINVAL);
1252 return tevent_req_post(req, ev);
1255 ret = gnutls_credentials_set(tlss->tls_session, GNUTLS_CRD_CERTIFICATE,
1257 if (ret != GNUTLS_E_SUCCESS) {
1258 DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1259 tevent_req_error(req, EINVAL);
1260 return tevent_req_post(req, ev);
1263 gnutls_certificate_server_set_request(tlss->tls_session,
1264 GNUTLS_CERT_REQUEST);
1265 gnutls_dh_set_prime_bits(tlss->tls_session, DH_BITS);
1267 gnutls_transport_set_ptr(tlss->tls_session, (gnutls_transport_ptr)state->tls_stream);
1268 gnutls_transport_set_pull_function(tlss->tls_session,
1269 (gnutls_pull_func)tstream_tls_pull_function);
1270 gnutls_transport_set_push_function(tlss->tls_session,
1271 (gnutls_push_func)tstream_tls_push_function);
1272 gnutls_transport_set_lowat(tlss->tls_session, 0);
1274 tlss->handshake.req = req;
1275 tstream_tls_retry_handshake(state->tls_stream);
1276 if (!tevent_req_is_in_progress(req)) {
1277 return tevent_req_post(req, ev);
1281 #else /* ENABLE_GNUTLS */
1282 tevent_req_error(req, ENOSYS);
1283 return tevent_req_post(req, ev);
1284 #endif /* ENABLE_GNUTLS */
1287 static void tstream_tls_retry_handshake(struct tstream_context *stream)
1289 struct tstream_tls *tlss =
1290 tstream_context_data(stream,
1291 struct tstream_tls);
1292 struct tevent_req *req = tlss->handshake.req;
1296 if (tlss->error != 0) {
1297 tevent_req_error(req, tlss->error);
1301 ret = gnutls_handshake(tlss->tls_session);
1302 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
1306 tlss->handshake.req = NULL;
1308 if (gnutls_error_is_fatal(ret) != 0) {
1309 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1311 tevent_req_error(req, tlss->error);
1315 if (ret != GNUTLS_E_SUCCESS) {
1316 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1318 tevent_req_error(req, tlss->error);
1322 tevent_req_done(req);
1323 #else /* ENABLE_GNUTLS */
1324 tevent_req_error(req, ENOSYS);
1325 #endif /* ENABLE_GNUTLS */
1328 int tstream_tls_accept_recv(struct tevent_req *req,
1330 TALLOC_CTX *mem_ctx,
1331 struct tstream_context **tls_stream)
1333 struct tstream_tls_accept_state *state =
1334 tevent_req_data(req,
1335 struct tstream_tls_accept_state);
1337 if (tevent_req_is_unix_error(req, perrno)) {
1338 tevent_req_received(req);
1342 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1343 tevent_req_received(req);