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
,
158 if (tlss
->error
!= 0) {
163 if (tlss
->push
.subreq
) {
168 if (tlss
->push
.ofs
== sizeof(tlss
->push
.buffer
)) {
173 len
= MIN(size
, sizeof(tlss
->push
.buffer
) - tlss
->push
.ofs
);
174 memcpy(tlss
->push
.buffer
+ tlss
->push
.ofs
, buf
, len
);
176 if (tlss
->push
.im
== NULL
) {
177 tlss
->push
.im
= tevent_create_immediate(tlss
);
178 if (tlss
->push
.im
== NULL
) {
184 if (tlss
->push
.ofs
== 0) {
186 * We'll do start the tstream_writev
187 * in the next event cycle.
189 * This way we can batch all push requests,
190 * if they fit into the buffer.
192 * This is important as gnutls_handshake()
193 * had a bug in some versions e.g. 2.4.1
194 * and others (See bug #7218) and it doesn't
197 tevent_schedule_immediate(tlss
->push
.im
,
199 tstream_tls_push_trigger_write
,
203 tlss
->push
.ofs
+= len
;
207 static void tstream_tls_push_done(struct tevent_req
*subreq
);
209 static void tstream_tls_push_trigger_write(struct tevent_context
*ev
,
210 struct tevent_immediate
*im
,
213 struct tstream_context
*stream
=
214 talloc_get_type_abort(private_data
,
215 struct tstream_context
);
216 struct tstream_tls
*tlss
=
217 tstream_context_data(stream
,
219 struct tevent_req
*subreq
;
221 if (tlss
->push
.subreq
) {
226 tlss
->push
.iov
.iov_base
= (char *)tlss
->push
.buffer
;
227 tlss
->push
.iov
.iov_len
= tlss
->push
.ofs
;
229 subreq
= tstream_writev_send(tlss
,
233 if (subreq
== NULL
) {
234 tlss
->error
= ENOMEM
;
235 tstream_tls_retry(stream
, false);
238 tevent_req_set_callback(subreq
, tstream_tls_push_done
, stream
);
240 tlss
->push
.subreq
= subreq
;
243 static void tstream_tls_push_done(struct tevent_req
*subreq
)
245 struct tstream_context
*stream
=
246 tevent_req_callback_data(subreq
,
247 struct tstream_context
);
248 struct tstream_tls
*tlss
=
249 tstream_context_data(stream
,
254 tlss
->push
.subreq
= NULL
;
255 ZERO_STRUCT(tlss
->push
.iov
);
258 ret
= tstream_writev_recv(subreq
, &sys_errno
);
261 tlss
->error
= sys_errno
;
262 tstream_tls_retry(stream
, false);
266 tstream_tls_retry(stream
, false);
269 static void tstream_tls_pull_done(struct tevent_req
*subreq
);
271 static ssize_t
tstream_tls_pull_function(gnutls_transport_ptr ptr
,
272 void *buf
, size_t size
)
274 struct tstream_context
*stream
=
275 talloc_get_type_abort(ptr
,
276 struct tstream_context
);
277 struct tstream_tls
*tlss
=
278 tstream_context_data(stream
,
280 struct tevent_req
*subreq
;
282 if (tlss
->error
!= 0) {
287 if (tlss
->pull
.subreq
) {
292 if (tlss
->pull
.iov
.iov_base
) {
295 n
= MIN(tlss
->pull
.iov
.iov_len
, size
);
296 memcpy(buf
, tlss
->pull
.iov
.iov_base
, n
);
298 tlss
->pull
.iov
.iov_len
-= n
;
299 if (tlss
->pull
.iov
.iov_len
== 0) {
300 tlss
->pull
.iov
.iov_base
= NULL
;
310 tlss
->pull
.iov
.iov_base
= tlss
->pull
.buffer
;
311 tlss
->pull
.iov
.iov_len
= MIN(size
, sizeof(tlss
->pull
.buffer
));
313 subreq
= tstream_readv_send(tlss
,
317 if (subreq
== NULL
) {
321 tevent_req_set_callback(subreq
, tstream_tls_pull_done
, stream
);
323 tlss
->pull
.subreq
= subreq
;
328 static void tstream_tls_pull_done(struct tevent_req
*subreq
)
330 struct tstream_context
*stream
=
331 tevent_req_callback_data(subreq
,
332 struct tstream_context
);
333 struct tstream_tls
*tlss
=
334 tstream_context_data(stream
,
339 tlss
->pull
.subreq
= NULL
;
341 ret
= tstream_readv_recv(subreq
, &sys_errno
);
344 tlss
->error
= sys_errno
;
345 tstream_tls_retry(stream
, false);
349 tstream_tls_retry(stream
, false);
351 #endif /* ENABLE_GNUTLS */
353 static int tstream_tls_destructor(struct tstream_tls
*tlss
)
356 if (tlss
->tls_session
) {
357 gnutls_deinit(tlss
->tls_session
);
358 tlss
->tls_session
= NULL
;
360 #endif /* ENABLE_GNUTLS */
364 static ssize_t
tstream_tls_pending_bytes(struct tstream_context
*stream
)
366 struct tstream_tls
*tlss
=
367 tstream_context_data(stream
,
371 if (tlss
->error
!= 0) {
377 ret
= gnutls_record_check_pending(tlss
->tls_session
);
378 ret
+= tlss
->read
.left
;
379 #else /* ENABLE_GNUTLS */
382 #endif /* ENABLE_GNUTLS */
386 struct tstream_tls_readv_state
{
387 struct tstream_context
*stream
;
389 struct iovec
*vector
;
395 static void tstream_tls_readv_crypt_next(struct tevent_req
*req
);
397 static struct tevent_req
*tstream_tls_readv_send(TALLOC_CTX
*mem_ctx
,
398 struct tevent_context
*ev
,
399 struct tstream_context
*stream
,
400 struct iovec
*vector
,
403 struct tstream_tls
*tlss
=
404 tstream_context_data(stream
,
406 struct tevent_req
*req
;
407 struct tstream_tls_readv_state
*state
;
409 tlss
->read
.req
= NULL
;
410 tlss
->current_ev
= ev
;
412 req
= tevent_req_create(mem_ctx
, &state
,
413 struct tstream_tls_readv_state
);
418 state
->stream
= stream
;
421 if (tlss
->error
!= 0) {
422 tevent_req_error(req
, tlss
->error
);
423 return tevent_req_post(req
, ev
);
427 * we make a copy of the vector so we can change the structure
429 state
->vector
= talloc_array(state
, struct iovec
, count
);
430 if (tevent_req_nomem(state
->vector
, req
)) {
431 return tevent_req_post(req
, ev
);
433 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
434 state
->count
= count
;
436 tstream_tls_readv_crypt_next(req
);
437 if (!tevent_req_is_in_progress(req
)) {
438 return tevent_req_post(req
, ev
);
444 static void tstream_tls_readv_crypt_next(struct tevent_req
*req
)
446 struct tstream_tls_readv_state
*state
=
448 struct tstream_tls_readv_state
);
449 struct tstream_tls
*tlss
=
450 tstream_context_data(state
->stream
,
454 * copy the pending buffer first
456 while (tlss
->read
.left
> 0 && state
->count
> 0) {
457 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
458 size_t len
= MIN(tlss
->read
.left
, state
->vector
[0].iov_len
);
460 memcpy(base
, tlss
->read
.buffer
+ tlss
->read
.ofs
, len
);
463 state
->vector
[0].iov_base
= (char *) base
;
464 state
->vector
[0].iov_len
-= len
;
466 tlss
->read
.ofs
+= len
;
467 tlss
->read
.left
-= len
;
469 if (state
->vector
[0].iov_len
== 0) {
477 if (state
->count
== 0) {
478 tevent_req_done(req
);
482 tlss
->read
.req
= req
;
483 tstream_tls_retry_read(state
->stream
);
486 static void tstream_tls_retry_read(struct tstream_context
*stream
)
488 struct tstream_tls
*tlss
=
489 tstream_context_data(stream
,
491 struct tevent_req
*req
= tlss
->read
.req
;
495 if (tlss
->error
!= 0) {
496 tevent_req_error(req
, tlss
->error
);
503 ret
= gnutls_record_recv(tlss
->tls_session
,
505 sizeof(tlss
->read
.buffer
));
506 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
510 tlss
->read
.req
= NULL
;
512 if (gnutls_error_is_fatal(ret
) != 0) {
513 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
515 tevent_req_error(req
, tlss
->error
);
521 tevent_req_error(req
, tlss
->error
);
525 tlss
->read
.left
= ret
;
526 tstream_tls_readv_crypt_next(req
);
527 #else /* ENABLE_GNUTLS */
528 tevent_req_error(req
, ENOSYS
);
529 #endif /* ENABLE_GNUTLS */
532 static int tstream_tls_readv_recv(struct tevent_req
*req
,
535 struct tstream_tls_readv_state
*state
=
537 struct tstream_tls_readv_state
);
538 struct tstream_tls
*tlss
=
539 tstream_context_data(state
->stream
,
543 tlss
->read
.req
= NULL
;
545 ret
= tsocket_simple_int_recv(req
, perrno
);
550 tevent_req_received(req
);
554 struct tstream_tls_writev_state
{
555 struct tstream_context
*stream
;
557 struct iovec
*vector
;
563 static void tstream_tls_writev_crypt_next(struct tevent_req
*req
);
565 static struct tevent_req
*tstream_tls_writev_send(TALLOC_CTX
*mem_ctx
,
566 struct tevent_context
*ev
,
567 struct tstream_context
*stream
,
568 const struct iovec
*vector
,
571 struct tstream_tls
*tlss
=
572 tstream_context_data(stream
,
574 struct tevent_req
*req
;
575 struct tstream_tls_writev_state
*state
;
577 tlss
->write
.req
= NULL
;
578 tlss
->current_ev
= ev
;
580 req
= tevent_req_create(mem_ctx
, &state
,
581 struct tstream_tls_writev_state
);
586 state
->stream
= stream
;
589 if (tlss
->error
!= 0) {
590 tevent_req_error(req
, tlss
->error
);
591 return tevent_req_post(req
, ev
);
595 * we make a copy of the vector so we can change the structure
597 state
->vector
= talloc_array(state
, struct iovec
, count
);
598 if (tevent_req_nomem(state
->vector
, req
)) {
599 return tevent_req_post(req
, ev
);
601 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
602 state
->count
= count
;
604 tstream_tls_writev_crypt_next(req
);
605 if (!tevent_req_is_in_progress(req
)) {
606 return tevent_req_post(req
, ev
);
612 static void tstream_tls_writev_crypt_next(struct tevent_req
*req
)
614 struct tstream_tls_writev_state
*state
=
616 struct tstream_tls_writev_state
);
617 struct tstream_tls
*tlss
=
618 tstream_context_data(state
->stream
,
621 tlss
->write
.left
= sizeof(tlss
->write
.buffer
);
625 * first fill our buffer
627 while (tlss
->write
.left
> 0 && state
->count
> 0) {
628 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
629 size_t len
= MIN(tlss
->write
.left
, state
->vector
[0].iov_len
);
631 memcpy(tlss
->write
.buffer
+ tlss
->write
.ofs
, base
, len
);
634 state
->vector
[0].iov_base
= (char *) base
;
635 state
->vector
[0].iov_len
-= len
;
637 tlss
->write
.ofs
+= len
;
638 tlss
->write
.left
-= len
;
640 if (state
->vector
[0].iov_len
== 0) {
648 if (tlss
->write
.ofs
== 0) {
649 tevent_req_done(req
);
653 tlss
->write
.left
= tlss
->write
.ofs
;
656 tlss
->write
.req
= req
;
657 tstream_tls_retry_write(state
->stream
);
660 static void tstream_tls_retry_write(struct tstream_context
*stream
)
662 struct tstream_tls
*tlss
=
663 tstream_context_data(stream
,
665 struct tevent_req
*req
= tlss
->write
.req
;
669 if (tlss
->error
!= 0) {
670 tevent_req_error(req
, tlss
->error
);
674 ret
= gnutls_record_send(tlss
->tls_session
,
675 tlss
->write
.buffer
+ tlss
->write
.ofs
,
677 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
681 tlss
->write
.req
= NULL
;
683 if (gnutls_error_is_fatal(ret
) != 0) {
684 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
686 tevent_req_error(req
, tlss
->error
);
692 tevent_req_error(req
, tlss
->error
);
696 tlss
->write
.ofs
+= ret
;
697 tlss
->write
.left
-= ret
;
699 if (tlss
->write
.left
> 0) {
700 tlss
->write
.req
= req
;
701 tstream_tls_retry_write(stream
);
705 tstream_tls_writev_crypt_next(req
);
706 #else /* ENABLE_GNUTLS */
707 tevent_req_error(req
, ENOSYS
);
708 #endif /* ENABLE_GNUTLS */
711 static int tstream_tls_writev_recv(struct tevent_req
*req
,
714 struct tstream_tls_writev_state
*state
=
716 struct tstream_tls_writev_state
);
717 struct tstream_tls
*tlss
=
718 tstream_context_data(state
->stream
,
722 tlss
->write
.req
= NULL
;
724 ret
= tsocket_simple_int_recv(req
, perrno
);
729 tevent_req_received(req
);
733 struct tstream_tls_disconnect_state
{
737 static struct tevent_req
*tstream_tls_disconnect_send(TALLOC_CTX
*mem_ctx
,
738 struct tevent_context
*ev
,
739 struct tstream_context
*stream
)
741 struct tstream_tls
*tlss
=
742 tstream_context_data(stream
,
744 struct tevent_req
*req
;
745 struct tstream_tls_disconnect_state
*state
;
747 tlss
->disconnect
.req
= NULL
;
748 tlss
->current_ev
= ev
;
750 req
= tevent_req_create(mem_ctx
, &state
,
751 struct tstream_tls_disconnect_state
);
756 if (tlss
->error
!= 0) {
757 tevent_req_error(req
, tlss
->error
);
758 return tevent_req_post(req
, ev
);
761 tlss
->disconnect
.req
= req
;
762 tstream_tls_retry_disconnect(stream
);
763 if (!tevent_req_is_in_progress(req
)) {
764 return tevent_req_post(req
, ev
);
770 static void tstream_tls_retry_disconnect(struct tstream_context
*stream
)
772 struct tstream_tls
*tlss
=
773 tstream_context_data(stream
,
775 struct tevent_req
*req
= tlss
->disconnect
.req
;
779 if (tlss
->error
!= 0) {
780 tevent_req_error(req
, tlss
->error
);
784 ret
= gnutls_bye(tlss
->tls_session
, GNUTLS_SHUT_WR
);
785 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
789 tlss
->disconnect
.req
= NULL
;
791 if (gnutls_error_is_fatal(ret
) != 0) {
792 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
794 tevent_req_error(req
, tlss
->error
);
798 if (ret
!= GNUTLS_E_SUCCESS
) {
799 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
801 tevent_req_error(req
, tlss
->error
);
805 tevent_req_done(req
);
806 #else /* ENABLE_GNUTLS */
807 tevent_req_error(req
, ENOSYS
);
808 #endif /* ENABLE_GNUTLS */
811 static int tstream_tls_disconnect_recv(struct tevent_req
*req
,
816 ret
= tsocket_simple_int_recv(req
, perrno
);
818 tevent_req_received(req
);
822 static const struct tstream_context_ops tstream_tls_ops
= {
825 .pending_bytes
= tstream_tls_pending_bytes
,
827 .readv_send
= tstream_tls_readv_send
,
828 .readv_recv
= tstream_tls_readv_recv
,
830 .writev_send
= tstream_tls_writev_send
,
831 .writev_recv
= tstream_tls_writev_recv
,
833 .disconnect_send
= tstream_tls_disconnect_send
,
834 .disconnect_recv
= tstream_tls_disconnect_recv
,
837 struct tstream_tls_params
{
839 gnutls_certificate_credentials x509_cred
;
840 gnutls_dh_params dh_params
;
841 #endif /* ENABLE_GNUTLS */
845 static int tstream_tls_params_destructor(struct tstream_tls_params
*tlsp
)
848 if (tlsp
->x509_cred
) {
849 gnutls_certificate_free_credentials(tlsp
->x509_cred
);
850 tlsp
->x509_cred
= NULL
;
852 if (tlsp
->dh_params
) {
853 gnutls_dh_params_deinit(tlsp
->dh_params
);
854 tlsp
->dh_params
= NULL
;
856 #endif /* ENABLE_GNUTLS */
860 bool tstream_tls_params_enabled(struct tstream_tls_params
*tlsp
)
862 return tlsp
->tls_enabled
;
865 NTSTATUS
tstream_tls_params_client(TALLOC_CTX
*mem_ctx
,
867 const char *crl_file
,
868 struct tstream_tls_params
**_tlsp
)
871 struct tstream_tls_params
*tlsp
;
874 ret
= gnutls_global_init();
875 if (ret
!= GNUTLS_E_SUCCESS
) {
876 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
877 return NT_STATUS_NOT_SUPPORTED
;
880 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
881 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
883 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
885 ret
= gnutls_certificate_allocate_credentials(&tlsp
->x509_cred
);
886 if (ret
!= GNUTLS_E_SUCCESS
) {
887 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
889 return NT_STATUS_NO_MEMORY
;
892 if (ca_file
&& *ca_file
) {
893 ret
= gnutls_certificate_set_x509_trust_file(tlsp
->x509_cred
,
895 GNUTLS_X509_FMT_PEM
);
897 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
898 ca_file
, gnutls_strerror(ret
)));
900 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
904 if (crl_file
&& *crl_file
) {
905 ret
= gnutls_certificate_set_x509_crl_file(tlsp
->x509_cred
,
907 GNUTLS_X509_FMT_PEM
);
909 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
910 crl_file
, gnutls_strerror(ret
)));
912 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
916 tlsp
->tls_enabled
= true;
920 #else /* ENABLE_GNUTLS */
921 return NT_STATUS_NOT_IMPLEMENTED
;
922 #endif /* ENABLE_GNUTLS */
925 struct tstream_tls_connect_state
{
926 struct tstream_context
*tls_stream
;
929 struct tevent_req
*_tstream_tls_connect_send(TALLOC_CTX
*mem_ctx
,
930 struct tevent_context
*ev
,
931 struct tstream_context
*plain_stream
,
932 struct tstream_tls_params
*tls_params
,
933 const char *location
)
935 struct tevent_req
*req
;
936 struct tstream_tls_connect_state
*state
;
938 struct tstream_tls
*tlss
;
940 static const int cert_type_priority
[] = {
945 #endif /* ENABLE_GNUTLS */
947 req
= tevent_req_create(mem_ctx
, &state
,
948 struct tstream_tls_connect_state
);
954 state
->tls_stream
= tstream_context_create(state
,
959 if (tevent_req_nomem(state
->tls_stream
, req
)) {
960 return tevent_req_post(req
, ev
);
963 talloc_set_destructor(tlss
, tstream_tls_destructor
);
965 tlss
->plain_stream
= plain_stream
;
967 tlss
->current_ev
= ev
;
968 tlss
->retry_im
= tevent_create_immediate(tlss
);
969 if (tevent_req_nomem(tlss
->retry_im
, req
)) {
970 return tevent_req_post(req
, ev
);
973 ret
= gnutls_init(&tlss
->tls_session
, GNUTLS_CLIENT
);
974 if (ret
!= GNUTLS_E_SUCCESS
) {
975 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
976 tevent_req_error(req
, EINVAL
);
977 return tevent_req_post(req
, ev
);
980 ret
= gnutls_set_default_priority(tlss
->tls_session
);
981 if (ret
!= GNUTLS_E_SUCCESS
) {
982 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
983 tevent_req_error(req
, EINVAL
);
984 return tevent_req_post(req
, ev
);
987 gnutls_certificate_type_set_priority(tlss
->tls_session
, cert_type_priority
);
989 ret
= gnutls_credentials_set(tlss
->tls_session
,
990 GNUTLS_CRD_CERTIFICATE
,
991 tls_params
->x509_cred
);
992 if (ret
!= GNUTLS_E_SUCCESS
) {
993 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
994 tevent_req_error(req
, EINVAL
);
995 return tevent_req_post(req
, ev
);
998 gnutls_transport_set_ptr(tlss
->tls_session
, (gnutls_transport_ptr
)state
->tls_stream
);
999 gnutls_transport_set_pull_function(tlss
->tls_session
,
1000 (gnutls_pull_func
)tstream_tls_pull_function
);
1001 gnutls_transport_set_push_function(tlss
->tls_session
,
1002 (gnutls_push_func
)tstream_tls_push_function
);
1003 gnutls_transport_set_lowat(tlss
->tls_session
, 0);
1005 tlss
->handshake
.req
= req
;
1006 tstream_tls_retry_handshake(state
->tls_stream
);
1007 if (!tevent_req_is_in_progress(req
)) {
1008 return tevent_req_post(req
, ev
);
1012 #else /* ENABLE_GNUTLS */
1013 tevent_req_error(req
, ENOSYS
);
1014 return tevent_req_post(req
, ev
);
1015 #endif /* ENABLE_GNUTLS */
1018 int tstream_tls_connect_recv(struct tevent_req
*req
,
1020 TALLOC_CTX
*mem_ctx
,
1021 struct tstream_context
**tls_stream
)
1023 struct tstream_tls_connect_state
*state
=
1024 tevent_req_data(req
,
1025 struct tstream_tls_connect_state
);
1027 if (tevent_req_is_unix_error(req
, perrno
)) {
1028 tevent_req_received(req
);
1032 *tls_stream
= talloc_move(mem_ctx
, &state
->tls_stream
);
1033 tevent_req_received(req
);
1037 extern void tls_cert_generate(TALLOC_CTX
*, const char *, const char *, const char *, const char *);
1040 initialise global tls state
1042 NTSTATUS
tstream_tls_params_server(TALLOC_CTX
*mem_ctx
,
1043 const char *dns_host_name
,
1045 const char *key_file
,
1046 const char *cert_file
,
1047 const char *ca_file
,
1048 const char *crl_file
,
1049 const char *dhp_file
,
1050 struct tstream_tls_params
**_tlsp
)
1052 struct tstream_tls_params
*tlsp
;
1056 if (!enabled
|| key_file
== NULL
|| *key_file
== 0) {
1057 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1058 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1059 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1060 tlsp
->tls_enabled
= false;
1063 return NT_STATUS_OK
;
1066 ret
= gnutls_global_init();
1067 if (ret
!= GNUTLS_E_SUCCESS
) {
1068 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1069 return NT_STATUS_NOT_SUPPORTED
;
1072 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1073 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1075 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1077 if (!file_exist(ca_file
)) {
1078 tls_cert_generate(tlsp
, dns_host_name
,
1079 key_file
, cert_file
, ca_file
);
1082 ret
= gnutls_certificate_allocate_credentials(&tlsp
->x509_cred
);
1083 if (ret
!= GNUTLS_E_SUCCESS
) {
1084 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1086 return NT_STATUS_NO_MEMORY
;
1089 if (ca_file
&& *ca_file
) {
1090 ret
= gnutls_certificate_set_x509_trust_file(tlsp
->x509_cred
,
1092 GNUTLS_X509_FMT_PEM
);
1094 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1095 ca_file
, gnutls_strerror(ret
)));
1097 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1101 if (crl_file
&& *crl_file
) {
1102 ret
= gnutls_certificate_set_x509_crl_file(tlsp
->x509_cred
,
1104 GNUTLS_X509_FMT_PEM
);
1106 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1107 crl_file
, gnutls_strerror(ret
)));
1109 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1113 ret
= gnutls_certificate_set_x509_key_file(tlsp
->x509_cred
,
1114 cert_file
, key_file
,
1115 GNUTLS_X509_FMT_PEM
);
1116 if (ret
!= GNUTLS_E_SUCCESS
) {
1117 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1118 cert_file
, key_file
, gnutls_strerror(ret
)));
1120 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1123 ret
= gnutls_dh_params_init(&tlsp
->dh_params
);
1124 if (ret
!= GNUTLS_E_SUCCESS
) {
1125 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1127 return NT_STATUS_NO_MEMORY
;
1130 if (dhp_file
&& *dhp_file
) {
1131 gnutls_datum_t dhparms
;
1134 dhparms
.data
= (uint8_t *)file_load(dhp_file
, &size
, 0, tlsp
);
1136 if (!dhparms
.data
) {
1137 DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1138 dhp_file
, errno
, strerror(errno
)));
1140 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1142 dhparms
.size
= size
;
1144 ret
= gnutls_dh_params_import_pkcs3(tlsp
->dh_params
,
1146 GNUTLS_X509_FMT_PEM
);
1147 if (ret
!= GNUTLS_E_SUCCESS
) {
1148 DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1149 dhp_file
, gnutls_strerror(ret
)));
1151 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1154 ret
= gnutls_dh_params_generate2(tlsp
->dh_params
, DH_BITS
);
1155 if (ret
!= GNUTLS_E_SUCCESS
) {
1156 DEBUG(0,("TLS failed to generate dh_params - %s\n",
1157 gnutls_strerror(ret
)));
1159 return NT_STATUS_INTERNAL_ERROR
;
1163 gnutls_certificate_set_dh_params(tlsp
->x509_cred
, tlsp
->dh_params
);
1165 tlsp
->tls_enabled
= true;
1167 #else /* ENABLE_GNUTLS */
1168 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1169 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1170 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1171 tlsp
->tls_enabled
= false;
1172 #endif /* ENABLE_GNUTLS */
1175 return NT_STATUS_OK
;
1178 struct tstream_tls_accept_state
{
1179 struct tstream_context
*tls_stream
;
1182 struct tevent_req
*_tstream_tls_accept_send(TALLOC_CTX
*mem_ctx
,
1183 struct tevent_context
*ev
,
1184 struct tstream_context
*plain_stream
,
1185 struct tstream_tls_params
*tlsp
,
1186 const char *location
)
1188 struct tevent_req
*req
;
1189 struct tstream_tls_accept_state
*state
;
1190 struct tstream_tls
*tlss
;
1193 #endif /* ENABLE_GNUTLS */
1195 req
= tevent_req_create(mem_ctx
, &state
,
1196 struct tstream_tls_accept_state
);
1201 state
->tls_stream
= tstream_context_create(state
,
1206 if (tevent_req_nomem(state
->tls_stream
, req
)) {
1207 return tevent_req_post(req
, ev
);
1210 talloc_set_destructor(tlss
, tstream_tls_destructor
);
1213 tlss
->plain_stream
= plain_stream
;
1215 tlss
->current_ev
= ev
;
1216 tlss
->retry_im
= tevent_create_immediate(tlss
);
1217 if (tevent_req_nomem(tlss
->retry_im
, req
)) {
1218 return tevent_req_post(req
, ev
);
1221 ret
= gnutls_init(&tlss
->tls_session
, GNUTLS_SERVER
);
1222 if (ret
!= GNUTLS_E_SUCCESS
) {
1223 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1224 tevent_req_error(req
, EINVAL
);
1225 return tevent_req_post(req
, ev
);
1228 ret
= gnutls_set_default_priority(tlss
->tls_session
);
1229 if (ret
!= GNUTLS_E_SUCCESS
) {
1230 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1231 tevent_req_error(req
, EINVAL
);
1232 return tevent_req_post(req
, ev
);
1235 ret
= gnutls_credentials_set(tlss
->tls_session
, GNUTLS_CRD_CERTIFICATE
,
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 gnutls_certificate_server_set_request(tlss
->tls_session
,
1244 GNUTLS_CERT_REQUEST
);
1245 gnutls_dh_set_prime_bits(tlss
->tls_session
, DH_BITS
);
1247 gnutls_transport_set_ptr(tlss
->tls_session
, (gnutls_transport_ptr
)state
->tls_stream
);
1248 gnutls_transport_set_pull_function(tlss
->tls_session
,
1249 (gnutls_pull_func
)tstream_tls_pull_function
);
1250 gnutls_transport_set_push_function(tlss
->tls_session
,
1251 (gnutls_push_func
)tstream_tls_push_function
);
1252 gnutls_transport_set_lowat(tlss
->tls_session
, 0);
1254 tlss
->handshake
.req
= req
;
1255 tstream_tls_retry_handshake(state
->tls_stream
);
1256 if (!tevent_req_is_in_progress(req
)) {
1257 return tevent_req_post(req
, ev
);
1261 #else /* ENABLE_GNUTLS */
1262 tevent_req_error(req
, ENOSYS
);
1263 return tevent_req_post(req
, ev
);
1264 #endif /* ENABLE_GNUTLS */
1267 static void tstream_tls_retry_handshake(struct tstream_context
*stream
)
1269 struct tstream_tls
*tlss
=
1270 tstream_context_data(stream
,
1271 struct tstream_tls
);
1272 struct tevent_req
*req
= tlss
->handshake
.req
;
1276 if (tlss
->error
!= 0) {
1277 tevent_req_error(req
, tlss
->error
);
1281 ret
= gnutls_handshake(tlss
->tls_session
);
1282 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
1286 tlss
->handshake
.req
= NULL
;
1288 if (gnutls_error_is_fatal(ret
) != 0) {
1289 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1291 tevent_req_error(req
, tlss
->error
);
1295 if (ret
!= GNUTLS_E_SUCCESS
) {
1296 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1298 tevent_req_error(req
, tlss
->error
);
1302 tevent_req_done(req
);
1303 #else /* ENABLE_GNUTLS */
1304 tevent_req_error(req
, ENOSYS
);
1305 #endif /* ENABLE_GNUTLS */
1308 int tstream_tls_accept_recv(struct tevent_req
*req
,
1310 TALLOC_CTX
*mem_ctx
,
1311 struct tstream_context
**tls_stream
)
1313 struct tstream_tls_accept_state
*state
=
1314 tevent_req_data(req
,
1315 struct tstream_tls_accept_state
);
1317 if (tevent_req_is_unix_error(req
, perrno
)) {
1318 tevent_req_received(req
);
1322 *tls_stream
= talloc_move(mem_ctx
, &state
->tls_stream
);
1323 tevent_req_received(req
);