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 "system/filesys.h"
23 #include "../util/tevent_unix.h"
24 #include "../lib/tsocket/tsocket.h"
25 #include "../lib/tsocket/tsocket_internal.h"
26 #include "lib/tls/tls.h"
29 #include <gnutls/gnutls.h>
33 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
34 typedef gnutls_datum gnutls_datum_t
;
37 #endif /* ENABLE_GNUTLS */
39 static const struct tstream_context_ops tstream_tls_ops
;
42 struct tstream_context
*plain_stream
;
46 gnutls_session tls_session
;
47 #endif /* ENABLE_GNUTLS */
49 struct tevent_context
*current_ev
;
51 struct tevent_immediate
*retry_im
;
57 struct tevent_req
*subreq
;
58 struct tevent_immediate
*im
;
64 struct tevent_req
*subreq
;
68 struct tevent_req
*req
;
75 struct tevent_req
*req
;
82 struct tevent_req
*req
;
86 struct tevent_req
*req
;
90 static void tstream_tls_retry_handshake(struct tstream_context
*stream
);
91 static void tstream_tls_retry_read(struct tstream_context
*stream
);
92 static void tstream_tls_retry_write(struct tstream_context
*stream
);
93 static void tstream_tls_retry_disconnect(struct tstream_context
*stream
);
94 static void tstream_tls_retry_trigger(struct tevent_context
*ctx
,
95 struct tevent_immediate
*im
,
98 static void tstream_tls_retry(struct tstream_context
*stream
, bool deferred
)
101 struct tstream_tls
*tlss
=
102 tstream_context_data(stream
,
105 if (tlss
->disconnect
.req
) {
106 tstream_tls_retry_disconnect(stream
);
110 if (tlss
->handshake
.req
) {
111 tstream_tls_retry_handshake(stream
);
115 if (tlss
->write
.req
&& tlss
->read
.req
&& !deferred
) {
116 tevent_schedule_immediate(tlss
->retry_im
, tlss
->current_ev
,
117 tstream_tls_retry_trigger
,
121 if (tlss
->write
.req
) {
122 tstream_tls_retry_write(stream
);
126 if (tlss
->read
.req
) {
127 tstream_tls_retry_read(stream
);
132 static void tstream_tls_retry_trigger(struct tevent_context
*ctx
,
133 struct tevent_immediate
*im
,
136 struct tstream_context
*stream
=
137 talloc_get_type_abort(private_data
,
138 struct tstream_context
);
140 tstream_tls_retry(stream
, true);
144 static void tstream_tls_push_trigger_write(struct tevent_context
*ev
,
145 struct tevent_immediate
*im
,
148 static ssize_t
tstream_tls_push_function(gnutls_transport_ptr ptr
,
149 const void *buf
, size_t size
)
151 struct tstream_context
*stream
=
152 talloc_get_type_abort(ptr
,
153 struct tstream_context
);
154 struct tstream_tls
*tlss
=
155 tstream_context_data(stream
,
160 if (tlss
->error
!= 0) {
165 if (tlss
->push
.subreq
) {
170 len
= MIN(size
, UINT16_MAX
- tlss
->push
.ofs
);
177 nbuf
= talloc_realloc(tlss
, tlss
->push
.buf
,
178 uint8_t, tlss
->push
.ofs
+ len
);
180 if (tlss
->push
.buf
) {
187 tlss
->push
.buf
= nbuf
;
189 memcpy(tlss
->push
.buf
+ tlss
->push
.ofs
, buf
, len
);
191 if (tlss
->push
.im
== NULL
) {
192 tlss
->push
.im
= tevent_create_immediate(tlss
);
193 if (tlss
->push
.im
== NULL
) {
199 if (tlss
->push
.ofs
== 0) {
201 * We'll do start the tstream_writev
202 * in the next event cycle.
204 * This way we can batch all push requests,
205 * if they fit into a UINT16_MAX buffer.
207 * This is important as gnutls_handshake()
208 * had a bug in some versions e.g. 2.4.1
209 * and others (See bug #7218) and it doesn't
212 tevent_schedule_immediate(tlss
->push
.im
,
214 tstream_tls_push_trigger_write
,
218 tlss
->push
.ofs
+= len
;
222 static void tstream_tls_push_done(struct tevent_req
*subreq
);
224 static void tstream_tls_push_trigger_write(struct tevent_context
*ev
,
225 struct tevent_immediate
*im
,
228 struct tstream_context
*stream
=
229 talloc_get_type_abort(private_data
,
230 struct tstream_context
);
231 struct tstream_tls
*tlss
=
232 tstream_context_data(stream
,
234 struct tevent_req
*subreq
;
236 if (tlss
->push
.subreq
) {
241 tlss
->push
.iov
.iov_base
= (char *)tlss
->push
.buf
;
242 tlss
->push
.iov
.iov_len
= tlss
->push
.ofs
;
244 subreq
= tstream_writev_send(tlss
,
248 if (subreq
== NULL
) {
249 tlss
->error
= ENOMEM
;
250 tstream_tls_retry(stream
, false);
253 tevent_req_set_callback(subreq
, tstream_tls_push_done
, stream
);
255 tlss
->push
.subreq
= subreq
;
258 static void tstream_tls_push_done(struct tevent_req
*subreq
)
260 struct tstream_context
*stream
=
261 tevent_req_callback_data(subreq
,
262 struct tstream_context
);
263 struct tstream_tls
*tlss
=
264 tstream_context_data(stream
,
269 tlss
->push
.subreq
= NULL
;
270 ZERO_STRUCT(tlss
->push
.iov
);
271 TALLOC_FREE(tlss
->push
.buf
);
274 ret
= tstream_writev_recv(subreq
, &sys_errno
);
277 tlss
->error
= sys_errno
;
278 tstream_tls_retry(stream
, false);
282 tstream_tls_retry(stream
, false);
285 static void tstream_tls_pull_done(struct tevent_req
*subreq
);
287 static ssize_t
tstream_tls_pull_function(gnutls_transport_ptr ptr
,
288 void *buf
, size_t size
)
290 struct tstream_context
*stream
=
291 talloc_get_type_abort(ptr
,
292 struct tstream_context
);
293 struct tstream_tls
*tlss
=
294 tstream_context_data(stream
,
296 struct tevent_req
*subreq
;
299 if (tlss
->error
!= 0) {
304 if (tlss
->pull
.subreq
) {
309 if (tlss
->pull
.iov
.iov_base
) {
313 b
= (uint8_t *)tlss
->pull
.iov
.iov_base
;
315 n
= MIN(tlss
->pull
.iov
.iov_len
, size
);
318 tlss
->pull
.iov
.iov_len
-= n
;
320 tlss
->pull
.iov
.iov_base
= (char *)b
;
321 if (tlss
->pull
.iov
.iov_len
== 0) {
322 tlss
->pull
.iov
.iov_base
= NULL
;
323 TALLOC_FREE(tlss
->pull
.buf
);
333 len
= MIN(size
, UINT16_MAX
);
335 tlss
->pull
.buf
= talloc_array(tlss
, uint8_t, len
);
336 if (tlss
->pull
.buf
== NULL
) {
340 tlss
->pull
.iov
.iov_base
= (char *)tlss
->pull
.buf
;
341 tlss
->pull
.iov
.iov_len
= len
;
343 subreq
= tstream_readv_send(tlss
,
347 if (subreq
== NULL
) {
351 tevent_req_set_callback(subreq
, tstream_tls_pull_done
, stream
);
353 tlss
->pull
.subreq
= subreq
;
358 static void tstream_tls_pull_done(struct tevent_req
*subreq
)
360 struct tstream_context
*stream
=
361 tevent_req_callback_data(subreq
,
362 struct tstream_context
);
363 struct tstream_tls
*tlss
=
364 tstream_context_data(stream
,
369 tlss
->pull
.subreq
= NULL
;
371 ret
= tstream_readv_recv(subreq
, &sys_errno
);
374 tlss
->error
= sys_errno
;
375 tstream_tls_retry(stream
, false);
379 tstream_tls_retry(stream
, false);
381 #endif /* ENABLE_GNUTLS */
383 static int tstream_tls_destructor(struct tstream_tls
*tlss
)
386 if (tlss
->tls_session
) {
387 gnutls_deinit(tlss
->tls_session
);
388 tlss
->tls_session
= NULL
;
390 #endif /* ENABLE_GNUTLS */
394 static ssize_t
tstream_tls_pending_bytes(struct tstream_context
*stream
)
396 struct tstream_tls
*tlss
=
397 tstream_context_data(stream
,
401 if (tlss
->error
!= 0) {
407 ret
= gnutls_record_check_pending(tlss
->tls_session
);
408 ret
+= tlss
->read
.left
;
409 #else /* ENABLE_GNUTLS */
412 #endif /* ENABLE_GNUTLS */
416 struct tstream_tls_readv_state
{
417 struct tstream_context
*stream
;
419 struct iovec
*vector
;
425 static void tstream_tls_readv_crypt_next(struct tevent_req
*req
);
427 static struct tevent_req
*tstream_tls_readv_send(TALLOC_CTX
*mem_ctx
,
428 struct tevent_context
*ev
,
429 struct tstream_context
*stream
,
430 struct iovec
*vector
,
433 struct tstream_tls
*tlss
=
434 tstream_context_data(stream
,
436 struct tevent_req
*req
;
437 struct tstream_tls_readv_state
*state
;
439 tlss
->read
.req
= NULL
;
440 tlss
->current_ev
= ev
;
442 req
= tevent_req_create(mem_ctx
, &state
,
443 struct tstream_tls_readv_state
);
448 state
->stream
= stream
;
451 if (tlss
->error
!= 0) {
452 tevent_req_error(req
, tlss
->error
);
453 return tevent_req_post(req
, ev
);
457 * we make a copy of the vector so we can change the structure
459 state
->vector
= talloc_array(state
, struct iovec
, count
);
460 if (tevent_req_nomem(state
->vector
, req
)) {
461 return tevent_req_post(req
, ev
);
463 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
464 state
->count
= count
;
466 tstream_tls_readv_crypt_next(req
);
467 if (!tevent_req_is_in_progress(req
)) {
468 return tevent_req_post(req
, ev
);
474 static void tstream_tls_readv_crypt_next(struct tevent_req
*req
)
476 struct tstream_tls_readv_state
*state
=
478 struct tstream_tls_readv_state
);
479 struct tstream_tls
*tlss
=
480 tstream_context_data(state
->stream
,
484 * copy the pending buffer first
486 while (tlss
->read
.left
> 0 && state
->count
> 0) {
487 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
488 size_t len
= MIN(tlss
->read
.left
, state
->vector
[0].iov_len
);
490 memcpy(base
, tlss
->read
.buffer
+ tlss
->read
.ofs
, len
);
493 state
->vector
[0].iov_base
= (char *) base
;
494 state
->vector
[0].iov_len
-= len
;
496 tlss
->read
.ofs
+= len
;
497 tlss
->read
.left
-= len
;
499 if (state
->vector
[0].iov_len
== 0) {
507 if (state
->count
== 0) {
508 tevent_req_done(req
);
512 tlss
->read
.req
= req
;
513 tstream_tls_retry_read(state
->stream
);
516 static void tstream_tls_retry_read(struct tstream_context
*stream
)
518 struct tstream_tls
*tlss
=
519 tstream_context_data(stream
,
521 struct tevent_req
*req
= tlss
->read
.req
;
525 if (tlss
->error
!= 0) {
526 tevent_req_error(req
, tlss
->error
);
533 ret
= gnutls_record_recv(tlss
->tls_session
,
535 sizeof(tlss
->read
.buffer
));
536 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
540 tlss
->read
.req
= NULL
;
542 if (gnutls_error_is_fatal(ret
) != 0) {
543 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
545 tevent_req_error(req
, tlss
->error
);
551 tevent_req_error(req
, tlss
->error
);
555 tlss
->read
.left
= ret
;
556 tstream_tls_readv_crypt_next(req
);
557 #else /* ENABLE_GNUTLS */
558 tevent_req_error(req
, ENOSYS
);
559 #endif /* ENABLE_GNUTLS */
562 static int tstream_tls_readv_recv(struct tevent_req
*req
,
565 struct tstream_tls_readv_state
*state
=
567 struct tstream_tls_readv_state
);
568 struct tstream_tls
*tlss
=
569 tstream_context_data(state
->stream
,
573 tlss
->read
.req
= NULL
;
575 ret
= tsocket_simple_int_recv(req
, perrno
);
580 tevent_req_received(req
);
584 struct tstream_tls_writev_state
{
585 struct tstream_context
*stream
;
587 struct iovec
*vector
;
593 static void tstream_tls_writev_crypt_next(struct tevent_req
*req
);
595 static struct tevent_req
*tstream_tls_writev_send(TALLOC_CTX
*mem_ctx
,
596 struct tevent_context
*ev
,
597 struct tstream_context
*stream
,
598 const struct iovec
*vector
,
601 struct tstream_tls
*tlss
=
602 tstream_context_data(stream
,
604 struct tevent_req
*req
;
605 struct tstream_tls_writev_state
*state
;
607 tlss
->write
.req
= NULL
;
608 tlss
->current_ev
= ev
;
610 req
= tevent_req_create(mem_ctx
, &state
,
611 struct tstream_tls_writev_state
);
616 state
->stream
= stream
;
619 if (tlss
->error
!= 0) {
620 tevent_req_error(req
, tlss
->error
);
621 return tevent_req_post(req
, ev
);
625 * we make a copy of the vector so we can change the structure
627 state
->vector
= talloc_array(state
, struct iovec
, count
);
628 if (tevent_req_nomem(state
->vector
, req
)) {
629 return tevent_req_post(req
, ev
);
631 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
632 state
->count
= count
;
634 tstream_tls_writev_crypt_next(req
);
635 if (!tevent_req_is_in_progress(req
)) {
636 return tevent_req_post(req
, ev
);
642 static void tstream_tls_writev_crypt_next(struct tevent_req
*req
)
644 struct tstream_tls_writev_state
*state
=
646 struct tstream_tls_writev_state
);
647 struct tstream_tls
*tlss
=
648 tstream_context_data(state
->stream
,
651 tlss
->write
.left
= sizeof(tlss
->write
.buffer
);
655 * first fill our buffer
657 while (tlss
->write
.left
> 0 && state
->count
> 0) {
658 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
659 size_t len
= MIN(tlss
->write
.left
, state
->vector
[0].iov_len
);
661 memcpy(tlss
->write
.buffer
+ tlss
->write
.ofs
, base
, len
);
664 state
->vector
[0].iov_base
= (char *) base
;
665 state
->vector
[0].iov_len
-= len
;
667 tlss
->write
.ofs
+= len
;
668 tlss
->write
.left
-= len
;
670 if (state
->vector
[0].iov_len
== 0) {
678 if (tlss
->write
.ofs
== 0) {
679 tevent_req_done(req
);
683 tlss
->write
.left
= tlss
->write
.ofs
;
686 tlss
->write
.req
= req
;
687 tstream_tls_retry_write(state
->stream
);
690 static void tstream_tls_retry_write(struct tstream_context
*stream
)
692 struct tstream_tls
*tlss
=
693 tstream_context_data(stream
,
695 struct tevent_req
*req
= tlss
->write
.req
;
699 if (tlss
->error
!= 0) {
700 tevent_req_error(req
, tlss
->error
);
704 ret
= gnutls_record_send(tlss
->tls_session
,
705 tlss
->write
.buffer
+ tlss
->write
.ofs
,
707 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
711 tlss
->write
.req
= NULL
;
713 if (gnutls_error_is_fatal(ret
) != 0) {
714 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
716 tevent_req_error(req
, tlss
->error
);
722 tevent_req_error(req
, tlss
->error
);
726 tlss
->write
.ofs
+= ret
;
727 tlss
->write
.left
-= ret
;
729 if (tlss
->write
.left
> 0) {
730 tlss
->write
.req
= req
;
731 tstream_tls_retry_write(stream
);
735 tstream_tls_writev_crypt_next(req
);
736 #else /* ENABLE_GNUTLS */
737 tevent_req_error(req
, ENOSYS
);
738 #endif /* ENABLE_GNUTLS */
741 static int tstream_tls_writev_recv(struct tevent_req
*req
,
744 struct tstream_tls_writev_state
*state
=
746 struct tstream_tls_writev_state
);
747 struct tstream_tls
*tlss
=
748 tstream_context_data(state
->stream
,
752 tlss
->write
.req
= NULL
;
754 ret
= tsocket_simple_int_recv(req
, perrno
);
759 tevent_req_received(req
);
763 struct tstream_tls_disconnect_state
{
767 static struct tevent_req
*tstream_tls_disconnect_send(TALLOC_CTX
*mem_ctx
,
768 struct tevent_context
*ev
,
769 struct tstream_context
*stream
)
771 struct tstream_tls
*tlss
=
772 tstream_context_data(stream
,
774 struct tevent_req
*req
;
775 struct tstream_tls_disconnect_state
*state
;
777 tlss
->disconnect
.req
= NULL
;
778 tlss
->current_ev
= ev
;
780 req
= tevent_req_create(mem_ctx
, &state
,
781 struct tstream_tls_disconnect_state
);
786 if (tlss
->error
!= 0) {
787 tevent_req_error(req
, tlss
->error
);
788 return tevent_req_post(req
, ev
);
791 tlss
->disconnect
.req
= req
;
792 tstream_tls_retry_disconnect(stream
);
793 if (!tevent_req_is_in_progress(req
)) {
794 return tevent_req_post(req
, ev
);
800 static void tstream_tls_retry_disconnect(struct tstream_context
*stream
)
802 struct tstream_tls
*tlss
=
803 tstream_context_data(stream
,
805 struct tevent_req
*req
= tlss
->disconnect
.req
;
809 if (tlss
->error
!= 0) {
810 tevent_req_error(req
, tlss
->error
);
814 ret
= gnutls_bye(tlss
->tls_session
, GNUTLS_SHUT_WR
);
815 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
819 tlss
->disconnect
.req
= NULL
;
821 if (gnutls_error_is_fatal(ret
) != 0) {
822 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
824 tevent_req_error(req
, tlss
->error
);
828 if (ret
!= GNUTLS_E_SUCCESS
) {
829 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
831 tevent_req_error(req
, tlss
->error
);
835 tevent_req_done(req
);
836 #else /* ENABLE_GNUTLS */
837 tevent_req_error(req
, ENOSYS
);
838 #endif /* ENABLE_GNUTLS */
841 static int tstream_tls_disconnect_recv(struct tevent_req
*req
,
846 ret
= tsocket_simple_int_recv(req
, perrno
);
848 tevent_req_received(req
);
852 static const struct tstream_context_ops tstream_tls_ops
= {
855 .pending_bytes
= tstream_tls_pending_bytes
,
857 .readv_send
= tstream_tls_readv_send
,
858 .readv_recv
= tstream_tls_readv_recv
,
860 .writev_send
= tstream_tls_writev_send
,
861 .writev_recv
= tstream_tls_writev_recv
,
863 .disconnect_send
= tstream_tls_disconnect_send
,
864 .disconnect_recv
= tstream_tls_disconnect_recv
,
867 struct tstream_tls_params
{
869 gnutls_certificate_credentials x509_cred
;
870 gnutls_dh_params dh_params
;
871 #endif /* ENABLE_GNUTLS */
875 static int tstream_tls_params_destructor(struct tstream_tls_params
*tlsp
)
878 if (tlsp
->x509_cred
) {
879 gnutls_certificate_free_credentials(tlsp
->x509_cred
);
880 tlsp
->x509_cred
= NULL
;
882 if (tlsp
->dh_params
) {
883 gnutls_dh_params_deinit(tlsp
->dh_params
);
884 tlsp
->dh_params
= NULL
;
886 #endif /* ENABLE_GNUTLS */
890 bool tstream_tls_params_enabled(struct tstream_tls_params
*tlsp
)
892 return tlsp
->tls_enabled
;
895 NTSTATUS
tstream_tls_params_client(TALLOC_CTX
*mem_ctx
,
897 const char *crl_file
,
898 struct tstream_tls_params
**_tlsp
)
901 struct tstream_tls_params
*tlsp
;
904 ret
= gnutls_global_init();
905 if (ret
!= GNUTLS_E_SUCCESS
) {
906 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
907 return NT_STATUS_NOT_SUPPORTED
;
910 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
911 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
913 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
915 ret
= gnutls_certificate_allocate_credentials(&tlsp
->x509_cred
);
916 if (ret
!= GNUTLS_E_SUCCESS
) {
917 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
919 return NT_STATUS_NO_MEMORY
;
922 if (ca_file
&& *ca_file
) {
923 ret
= gnutls_certificate_set_x509_trust_file(tlsp
->x509_cred
,
925 GNUTLS_X509_FMT_PEM
);
927 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
928 ca_file
, gnutls_strerror(ret
)));
930 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
934 if (crl_file
&& *crl_file
) {
935 ret
= gnutls_certificate_set_x509_crl_file(tlsp
->x509_cred
,
937 GNUTLS_X509_FMT_PEM
);
939 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
940 crl_file
, gnutls_strerror(ret
)));
942 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
946 tlsp
->tls_enabled
= true;
950 #else /* ENABLE_GNUTLS */
951 return NT_STATUS_NOT_IMPLEMENTED
;
952 #endif /* ENABLE_GNUTLS */
955 struct tstream_tls_connect_state
{
956 struct tstream_context
*tls_stream
;
959 struct tevent_req
*_tstream_tls_connect_send(TALLOC_CTX
*mem_ctx
,
960 struct tevent_context
*ev
,
961 struct tstream_context
*plain_stream
,
962 struct tstream_tls_params
*tls_params
,
963 const char *location
)
965 struct tevent_req
*req
;
966 struct tstream_tls_connect_state
*state
;
968 struct tstream_tls
*tlss
;
970 static const int cert_type_priority
[] = {
975 #endif /* ENABLE_GNUTLS */
977 req
= tevent_req_create(mem_ctx
, &state
,
978 struct tstream_tls_connect_state
);
984 state
->tls_stream
= tstream_context_create(state
,
989 if (tevent_req_nomem(state
->tls_stream
, req
)) {
990 return tevent_req_post(req
, ev
);
993 talloc_set_destructor(tlss
, tstream_tls_destructor
);
995 tlss
->plain_stream
= plain_stream
;
997 tlss
->current_ev
= ev
;
998 tlss
->retry_im
= tevent_create_immediate(tlss
);
999 if (tevent_req_nomem(tlss
->retry_im
, req
)) {
1000 return tevent_req_post(req
, ev
);
1003 ret
= gnutls_init(&tlss
->tls_session
, GNUTLS_CLIENT
);
1004 if (ret
!= GNUTLS_E_SUCCESS
) {
1005 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1006 tevent_req_error(req
, EINVAL
);
1007 return tevent_req_post(req
, ev
);
1010 ret
= gnutls_set_default_priority(tlss
->tls_session
);
1011 if (ret
!= GNUTLS_E_SUCCESS
) {
1012 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1013 tevent_req_error(req
, EINVAL
);
1014 return tevent_req_post(req
, ev
);
1017 gnutls_certificate_type_set_priority(tlss
->tls_session
, cert_type_priority
);
1019 ret
= gnutls_credentials_set(tlss
->tls_session
,
1020 GNUTLS_CRD_CERTIFICATE
,
1021 tls_params
->x509_cred
);
1022 if (ret
!= GNUTLS_E_SUCCESS
) {
1023 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1024 tevent_req_error(req
, EINVAL
);
1025 return tevent_req_post(req
, ev
);
1028 gnutls_transport_set_ptr(tlss
->tls_session
, (gnutls_transport_ptr
)state
->tls_stream
);
1029 gnutls_transport_set_pull_function(tlss
->tls_session
,
1030 (gnutls_pull_func
)tstream_tls_pull_function
);
1031 gnutls_transport_set_push_function(tlss
->tls_session
,
1032 (gnutls_push_func
)tstream_tls_push_function
);
1033 #if GNUTLS_VERSION_MAJOR < 3
1034 gnutls_transport_set_lowat(tlss
->tls_session
, 0);
1037 tlss
->handshake
.req
= req
;
1038 tstream_tls_retry_handshake(state
->tls_stream
);
1039 if (!tevent_req_is_in_progress(req
)) {
1040 return tevent_req_post(req
, ev
);
1044 #else /* ENABLE_GNUTLS */
1045 tevent_req_error(req
, ENOSYS
);
1046 return tevent_req_post(req
, ev
);
1047 #endif /* ENABLE_GNUTLS */
1050 int tstream_tls_connect_recv(struct tevent_req
*req
,
1052 TALLOC_CTX
*mem_ctx
,
1053 struct tstream_context
**tls_stream
)
1055 struct tstream_tls_connect_state
*state
=
1056 tevent_req_data(req
,
1057 struct tstream_tls_connect_state
);
1059 if (tevent_req_is_unix_error(req
, perrno
)) {
1060 tevent_req_received(req
);
1064 *tls_stream
= talloc_move(mem_ctx
, &state
->tls_stream
);
1065 tevent_req_received(req
);
1069 extern void tls_cert_generate(TALLOC_CTX
*, const char *, const char *, const char *, const char *);
1072 initialise global tls state
1074 NTSTATUS
tstream_tls_params_server(TALLOC_CTX
*mem_ctx
,
1075 const char *dns_host_name
,
1077 const char *key_file
,
1078 const char *cert_file
,
1079 const char *ca_file
,
1080 const char *crl_file
,
1081 const char *dhp_file
,
1082 struct tstream_tls_params
**_tlsp
)
1084 struct tstream_tls_params
*tlsp
;
1089 if (!enabled
|| key_file
== NULL
|| *key_file
== 0) {
1090 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1091 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1092 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1093 tlsp
->tls_enabled
= false;
1096 return NT_STATUS_OK
;
1099 ret
= gnutls_global_init();
1100 if (ret
!= GNUTLS_E_SUCCESS
) {
1101 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1102 return NT_STATUS_NOT_SUPPORTED
;
1105 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1106 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1108 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1110 if (!file_exist(ca_file
)) {
1111 tls_cert_generate(tlsp
, dns_host_name
,
1112 key_file
, cert_file
, ca_file
);
1115 if (file_exist(key_file
) &&
1116 !file_check_permissions(key_file
, geteuid(), 0600, &st
))
1118 DEBUG(0, ("Invalid permissions on TLS private key file '%s':\n"
1119 "owner uid %u should be %u, mode 0%o should be 0%o\n"
1120 "This is known as CVE-2013-4476.\n"
1121 "Removing all tls .pem files will cause an "
1122 "auto-regeneration with the correct permissions.\n",
1124 (unsigned int)st
.st_uid
, geteuid(),
1125 (unsigned int)(st
.st_mode
& 0777), 0600));
1126 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1129 ret
= gnutls_certificate_allocate_credentials(&tlsp
->x509_cred
);
1130 if (ret
!= GNUTLS_E_SUCCESS
) {
1131 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1133 return NT_STATUS_NO_MEMORY
;
1136 if (ca_file
&& *ca_file
) {
1137 ret
= gnutls_certificate_set_x509_trust_file(tlsp
->x509_cred
,
1139 GNUTLS_X509_FMT_PEM
);
1141 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1142 ca_file
, gnutls_strerror(ret
)));
1144 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1148 if (crl_file
&& *crl_file
) {
1149 ret
= gnutls_certificate_set_x509_crl_file(tlsp
->x509_cred
,
1151 GNUTLS_X509_FMT_PEM
);
1153 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1154 crl_file
, gnutls_strerror(ret
)));
1156 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1160 ret
= gnutls_certificate_set_x509_key_file(tlsp
->x509_cred
,
1161 cert_file
, key_file
,
1162 GNUTLS_X509_FMT_PEM
);
1163 if (ret
!= GNUTLS_E_SUCCESS
) {
1164 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1165 cert_file
, key_file
, gnutls_strerror(ret
)));
1167 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1170 ret
= gnutls_dh_params_init(&tlsp
->dh_params
);
1171 if (ret
!= GNUTLS_E_SUCCESS
) {
1172 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1174 return NT_STATUS_NO_MEMORY
;
1177 if (dhp_file
&& *dhp_file
) {
1178 gnutls_datum_t dhparms
;
1181 dhparms
.data
= (uint8_t *)file_load(dhp_file
, &size
, 0, tlsp
);
1183 if (!dhparms
.data
) {
1184 DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1185 dhp_file
, errno
, strerror(errno
)));
1187 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1189 dhparms
.size
= size
;
1191 ret
= gnutls_dh_params_import_pkcs3(tlsp
->dh_params
,
1193 GNUTLS_X509_FMT_PEM
);
1194 if (ret
!= GNUTLS_E_SUCCESS
) {
1195 DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1196 dhp_file
, gnutls_strerror(ret
)));
1198 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1201 ret
= gnutls_dh_params_generate2(tlsp
->dh_params
, DH_BITS
);
1202 if (ret
!= GNUTLS_E_SUCCESS
) {
1203 DEBUG(0,("TLS failed to generate dh_params - %s\n",
1204 gnutls_strerror(ret
)));
1206 return NT_STATUS_INTERNAL_ERROR
;
1210 gnutls_certificate_set_dh_params(tlsp
->x509_cred
, tlsp
->dh_params
);
1212 tlsp
->tls_enabled
= true;
1214 #else /* ENABLE_GNUTLS */
1215 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1216 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1217 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1218 tlsp
->tls_enabled
= false;
1219 #endif /* ENABLE_GNUTLS */
1222 return NT_STATUS_OK
;
1225 struct tstream_tls_accept_state
{
1226 struct tstream_context
*tls_stream
;
1229 struct tevent_req
*_tstream_tls_accept_send(TALLOC_CTX
*mem_ctx
,
1230 struct tevent_context
*ev
,
1231 struct tstream_context
*plain_stream
,
1232 struct tstream_tls_params
*tlsp
,
1233 const char *location
)
1235 struct tevent_req
*req
;
1236 struct tstream_tls_accept_state
*state
;
1237 struct tstream_tls
*tlss
;
1240 #endif /* ENABLE_GNUTLS */
1242 req
= tevent_req_create(mem_ctx
, &state
,
1243 struct tstream_tls_accept_state
);
1248 state
->tls_stream
= tstream_context_create(state
,
1253 if (tevent_req_nomem(state
->tls_stream
, req
)) {
1254 return tevent_req_post(req
, ev
);
1257 talloc_set_destructor(tlss
, tstream_tls_destructor
);
1260 tlss
->plain_stream
= plain_stream
;
1262 tlss
->current_ev
= ev
;
1263 tlss
->retry_im
= tevent_create_immediate(tlss
);
1264 if (tevent_req_nomem(tlss
->retry_im
, req
)) {
1265 return tevent_req_post(req
, ev
);
1268 ret
= gnutls_init(&tlss
->tls_session
, GNUTLS_SERVER
);
1269 if (ret
!= GNUTLS_E_SUCCESS
) {
1270 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1271 tevent_req_error(req
, EINVAL
);
1272 return tevent_req_post(req
, ev
);
1275 ret
= gnutls_set_default_priority(tlss
->tls_session
);
1276 if (ret
!= GNUTLS_E_SUCCESS
) {
1277 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1278 tevent_req_error(req
, EINVAL
);
1279 return tevent_req_post(req
, ev
);
1282 ret
= gnutls_credentials_set(tlss
->tls_session
, GNUTLS_CRD_CERTIFICATE
,
1284 if (ret
!= GNUTLS_E_SUCCESS
) {
1285 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1286 tevent_req_error(req
, EINVAL
);
1287 return tevent_req_post(req
, ev
);
1290 gnutls_certificate_server_set_request(tlss
->tls_session
,
1291 GNUTLS_CERT_REQUEST
);
1292 gnutls_dh_set_prime_bits(tlss
->tls_session
, DH_BITS
);
1294 gnutls_transport_set_ptr(tlss
->tls_session
, (gnutls_transport_ptr
)state
->tls_stream
);
1295 gnutls_transport_set_pull_function(tlss
->tls_session
,
1296 (gnutls_pull_func
)tstream_tls_pull_function
);
1297 gnutls_transport_set_push_function(tlss
->tls_session
,
1298 (gnutls_push_func
)tstream_tls_push_function
);
1299 #if GNUTLS_VERSION_MAJOR < 3
1300 gnutls_transport_set_lowat(tlss
->tls_session
, 0);
1303 tlss
->handshake
.req
= req
;
1304 tstream_tls_retry_handshake(state
->tls_stream
);
1305 if (!tevent_req_is_in_progress(req
)) {
1306 return tevent_req_post(req
, ev
);
1310 #else /* ENABLE_GNUTLS */
1311 tevent_req_error(req
, ENOSYS
);
1312 return tevent_req_post(req
, ev
);
1313 #endif /* ENABLE_GNUTLS */
1316 static void tstream_tls_retry_handshake(struct tstream_context
*stream
)
1318 struct tstream_tls
*tlss
=
1319 tstream_context_data(stream
,
1320 struct tstream_tls
);
1321 struct tevent_req
*req
= tlss
->handshake
.req
;
1325 if (tlss
->error
!= 0) {
1326 tevent_req_error(req
, tlss
->error
);
1330 ret
= gnutls_handshake(tlss
->tls_session
);
1331 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
1335 tlss
->handshake
.req
= NULL
;
1337 if (gnutls_error_is_fatal(ret
) != 0) {
1338 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1340 tevent_req_error(req
, tlss
->error
);
1344 if (ret
!= GNUTLS_E_SUCCESS
) {
1345 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1347 tevent_req_error(req
, tlss
->error
);
1351 tevent_req_done(req
);
1352 #else /* ENABLE_GNUTLS */
1353 tevent_req_error(req
, ENOSYS
);
1354 #endif /* ENABLE_GNUTLS */
1357 int tstream_tls_accept_recv(struct tevent_req
*req
,
1359 TALLOC_CTX
*mem_ctx
,
1360 struct tstream_context
**tls_stream
)
1362 struct tstream_tls_accept_state
*state
=
1363 tevent_req_data(req
,
1364 struct tstream_tls_accept_state
);
1366 if (tevent_req_is_unix_error(req
, perrno
)) {
1367 tevent_req_received(req
);
1371 *tls_stream
= talloc_move(mem_ctx
, &state
->tls_stream
);
1372 tevent_req_received(req
);