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
;
298 if (tlss
->error
!= 0) {
303 if (tlss
->pull
.subreq
) {
308 if (tlss
->pull
.iov
.iov_base
) {
312 b
= (uint8_t *)tlss
->pull
.iov
.iov_base
;
314 n
= MIN(tlss
->pull
.iov
.iov_len
, size
);
317 tlss
->pull
.iov
.iov_len
-= n
;
319 tlss
->pull
.iov
.iov_base
= (char *)b
;
320 if (tlss
->pull
.iov
.iov_len
== 0) {
321 tlss
->pull
.iov
.iov_base
= NULL
;
322 TALLOC_FREE(tlss
->pull
.buf
);
332 len
= MIN(size
, UINT16_MAX
);
334 tlss
->pull
.buf
= talloc_array(tlss
, uint8_t, len
);
335 if (tlss
->pull
.buf
== NULL
) {
339 tlss
->pull
.iov
.iov_base
= (char *)tlss
->pull
.buf
;
340 tlss
->pull
.iov
.iov_len
= len
;
342 subreq
= tstream_readv_send(tlss
,
346 if (subreq
== NULL
) {
350 tevent_req_set_callback(subreq
, tstream_tls_pull_done
, stream
);
352 tlss
->pull
.subreq
= subreq
;
357 static void tstream_tls_pull_done(struct tevent_req
*subreq
)
359 struct tstream_context
*stream
=
360 tevent_req_callback_data(subreq
,
361 struct tstream_context
);
362 struct tstream_tls
*tlss
=
363 tstream_context_data(stream
,
368 tlss
->pull
.subreq
= NULL
;
370 ret
= tstream_readv_recv(subreq
, &sys_errno
);
373 tlss
->error
= sys_errno
;
374 tstream_tls_retry(stream
, false);
378 tstream_tls_retry(stream
, false);
380 #endif /* ENABLE_GNUTLS */
382 static int tstream_tls_destructor(struct tstream_tls
*tlss
)
385 if (tlss
->tls_session
) {
386 gnutls_deinit(tlss
->tls_session
);
387 tlss
->tls_session
= NULL
;
389 #endif /* ENABLE_GNUTLS */
393 static ssize_t
tstream_tls_pending_bytes(struct tstream_context
*stream
)
395 struct tstream_tls
*tlss
=
396 tstream_context_data(stream
,
400 if (tlss
->error
!= 0) {
406 ret
= gnutls_record_check_pending(tlss
->tls_session
);
407 ret
+= tlss
->read
.left
;
408 #else /* ENABLE_GNUTLS */
411 #endif /* ENABLE_GNUTLS */
415 struct tstream_tls_readv_state
{
416 struct tstream_context
*stream
;
418 struct iovec
*vector
;
424 static void tstream_tls_readv_crypt_next(struct tevent_req
*req
);
426 static struct tevent_req
*tstream_tls_readv_send(TALLOC_CTX
*mem_ctx
,
427 struct tevent_context
*ev
,
428 struct tstream_context
*stream
,
429 struct iovec
*vector
,
432 struct tstream_tls
*tlss
=
433 tstream_context_data(stream
,
435 struct tevent_req
*req
;
436 struct tstream_tls_readv_state
*state
;
438 tlss
->read
.req
= NULL
;
439 tlss
->current_ev
= ev
;
441 req
= tevent_req_create(mem_ctx
, &state
,
442 struct tstream_tls_readv_state
);
447 state
->stream
= stream
;
450 if (tlss
->error
!= 0) {
451 tevent_req_error(req
, tlss
->error
);
452 return tevent_req_post(req
, ev
);
456 * we make a copy of the vector so we can change the structure
458 state
->vector
= talloc_array(state
, struct iovec
, count
);
459 if (tevent_req_nomem(state
->vector
, req
)) {
460 return tevent_req_post(req
, ev
);
462 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
463 state
->count
= count
;
465 tstream_tls_readv_crypt_next(req
);
466 if (!tevent_req_is_in_progress(req
)) {
467 return tevent_req_post(req
, ev
);
473 static void tstream_tls_readv_crypt_next(struct tevent_req
*req
)
475 struct tstream_tls_readv_state
*state
=
477 struct tstream_tls_readv_state
);
478 struct tstream_tls
*tlss
=
479 tstream_context_data(state
->stream
,
483 * copy the pending buffer first
485 while (tlss
->read
.left
> 0 && state
->count
> 0) {
486 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
487 size_t len
= MIN(tlss
->read
.left
, state
->vector
[0].iov_len
);
489 memcpy(base
, tlss
->read
.buffer
+ tlss
->read
.ofs
, len
);
492 state
->vector
[0].iov_base
= (char *) base
;
493 state
->vector
[0].iov_len
-= len
;
495 tlss
->read
.ofs
+= len
;
496 tlss
->read
.left
-= len
;
498 if (state
->vector
[0].iov_len
== 0) {
506 if (state
->count
== 0) {
507 tevent_req_done(req
);
511 tlss
->read
.req
= req
;
512 tstream_tls_retry_read(state
->stream
);
515 static void tstream_tls_retry_read(struct tstream_context
*stream
)
517 struct tstream_tls
*tlss
=
518 tstream_context_data(stream
,
520 struct tevent_req
*req
= tlss
->read
.req
;
524 if (tlss
->error
!= 0) {
525 tevent_req_error(req
, tlss
->error
);
532 ret
= gnutls_record_recv(tlss
->tls_session
,
534 sizeof(tlss
->read
.buffer
));
535 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
539 tlss
->read
.req
= NULL
;
541 if (gnutls_error_is_fatal(ret
) != 0) {
542 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
544 tevent_req_error(req
, tlss
->error
);
550 tevent_req_error(req
, tlss
->error
);
554 tlss
->read
.left
= ret
;
555 tstream_tls_readv_crypt_next(req
);
556 #else /* ENABLE_GNUTLS */
557 tevent_req_error(req
, ENOSYS
);
558 #endif /* ENABLE_GNUTLS */
561 static int tstream_tls_readv_recv(struct tevent_req
*req
,
564 struct tstream_tls_readv_state
*state
=
566 struct tstream_tls_readv_state
);
567 struct tstream_tls
*tlss
=
568 tstream_context_data(state
->stream
,
572 tlss
->read
.req
= NULL
;
574 ret
= tsocket_simple_int_recv(req
, perrno
);
579 tevent_req_received(req
);
583 struct tstream_tls_writev_state
{
584 struct tstream_context
*stream
;
586 struct iovec
*vector
;
592 static void tstream_tls_writev_crypt_next(struct tevent_req
*req
);
594 static struct tevent_req
*tstream_tls_writev_send(TALLOC_CTX
*mem_ctx
,
595 struct tevent_context
*ev
,
596 struct tstream_context
*stream
,
597 const struct iovec
*vector
,
600 struct tstream_tls
*tlss
=
601 tstream_context_data(stream
,
603 struct tevent_req
*req
;
604 struct tstream_tls_writev_state
*state
;
606 tlss
->write
.req
= NULL
;
607 tlss
->current_ev
= ev
;
609 req
= tevent_req_create(mem_ctx
, &state
,
610 struct tstream_tls_writev_state
);
615 state
->stream
= stream
;
618 if (tlss
->error
!= 0) {
619 tevent_req_error(req
, tlss
->error
);
620 return tevent_req_post(req
, ev
);
624 * we make a copy of the vector so we can change the structure
626 state
->vector
= talloc_array(state
, struct iovec
, count
);
627 if (tevent_req_nomem(state
->vector
, req
)) {
628 return tevent_req_post(req
, ev
);
630 memcpy(state
->vector
, vector
, sizeof(struct iovec
) * count
);
631 state
->count
= count
;
633 tstream_tls_writev_crypt_next(req
);
634 if (!tevent_req_is_in_progress(req
)) {
635 return tevent_req_post(req
, ev
);
641 static void tstream_tls_writev_crypt_next(struct tevent_req
*req
)
643 struct tstream_tls_writev_state
*state
=
645 struct tstream_tls_writev_state
);
646 struct tstream_tls
*tlss
=
647 tstream_context_data(state
->stream
,
650 tlss
->write
.left
= sizeof(tlss
->write
.buffer
);
654 * first fill our buffer
656 while (tlss
->write
.left
> 0 && state
->count
> 0) {
657 uint8_t *base
= (uint8_t *)state
->vector
[0].iov_base
;
658 size_t len
= MIN(tlss
->write
.left
, state
->vector
[0].iov_len
);
660 memcpy(tlss
->write
.buffer
+ tlss
->write
.ofs
, base
, len
);
663 state
->vector
[0].iov_base
= (char *) base
;
664 state
->vector
[0].iov_len
-= len
;
666 tlss
->write
.ofs
+= len
;
667 tlss
->write
.left
-= len
;
669 if (state
->vector
[0].iov_len
== 0) {
677 if (tlss
->write
.ofs
== 0) {
678 tevent_req_done(req
);
682 tlss
->write
.left
= tlss
->write
.ofs
;
685 tlss
->write
.req
= req
;
686 tstream_tls_retry_write(state
->stream
);
689 static void tstream_tls_retry_write(struct tstream_context
*stream
)
691 struct tstream_tls
*tlss
=
692 tstream_context_data(stream
,
694 struct tevent_req
*req
= tlss
->write
.req
;
698 if (tlss
->error
!= 0) {
699 tevent_req_error(req
, tlss
->error
);
703 ret
= gnutls_record_send(tlss
->tls_session
,
704 tlss
->write
.buffer
+ tlss
->write
.ofs
,
706 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
710 tlss
->write
.req
= NULL
;
712 if (gnutls_error_is_fatal(ret
) != 0) {
713 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
715 tevent_req_error(req
, tlss
->error
);
721 tevent_req_error(req
, tlss
->error
);
725 tlss
->write
.ofs
+= ret
;
726 tlss
->write
.left
-= ret
;
728 if (tlss
->write
.left
> 0) {
729 tlss
->write
.req
= req
;
730 tstream_tls_retry_write(stream
);
734 tstream_tls_writev_crypt_next(req
);
735 #else /* ENABLE_GNUTLS */
736 tevent_req_error(req
, ENOSYS
);
737 #endif /* ENABLE_GNUTLS */
740 static int tstream_tls_writev_recv(struct tevent_req
*req
,
743 struct tstream_tls_writev_state
*state
=
745 struct tstream_tls_writev_state
);
746 struct tstream_tls
*tlss
=
747 tstream_context_data(state
->stream
,
751 tlss
->write
.req
= NULL
;
753 ret
= tsocket_simple_int_recv(req
, perrno
);
758 tevent_req_received(req
);
762 struct tstream_tls_disconnect_state
{
766 static struct tevent_req
*tstream_tls_disconnect_send(TALLOC_CTX
*mem_ctx
,
767 struct tevent_context
*ev
,
768 struct tstream_context
*stream
)
770 struct tstream_tls
*tlss
=
771 tstream_context_data(stream
,
773 struct tevent_req
*req
;
774 struct tstream_tls_disconnect_state
*state
;
776 tlss
->disconnect
.req
= NULL
;
777 tlss
->current_ev
= ev
;
779 req
= tevent_req_create(mem_ctx
, &state
,
780 struct tstream_tls_disconnect_state
);
785 if (tlss
->error
!= 0) {
786 tevent_req_error(req
, tlss
->error
);
787 return tevent_req_post(req
, ev
);
790 tlss
->disconnect
.req
= req
;
791 tstream_tls_retry_disconnect(stream
);
792 if (!tevent_req_is_in_progress(req
)) {
793 return tevent_req_post(req
, ev
);
799 static void tstream_tls_retry_disconnect(struct tstream_context
*stream
)
801 struct tstream_tls
*tlss
=
802 tstream_context_data(stream
,
804 struct tevent_req
*req
= tlss
->disconnect
.req
;
808 if (tlss
->error
!= 0) {
809 tevent_req_error(req
, tlss
->error
);
813 ret
= gnutls_bye(tlss
->tls_session
, GNUTLS_SHUT_WR
);
814 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
818 tlss
->disconnect
.req
= NULL
;
820 if (gnutls_error_is_fatal(ret
) != 0) {
821 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
823 tevent_req_error(req
, tlss
->error
);
827 if (ret
!= GNUTLS_E_SUCCESS
) {
828 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
830 tevent_req_error(req
, tlss
->error
);
834 tevent_req_done(req
);
835 #else /* ENABLE_GNUTLS */
836 tevent_req_error(req
, ENOSYS
);
837 #endif /* ENABLE_GNUTLS */
840 static int tstream_tls_disconnect_recv(struct tevent_req
*req
,
845 ret
= tsocket_simple_int_recv(req
, perrno
);
847 tevent_req_received(req
);
851 static const struct tstream_context_ops tstream_tls_ops
= {
854 .pending_bytes
= tstream_tls_pending_bytes
,
856 .readv_send
= tstream_tls_readv_send
,
857 .readv_recv
= tstream_tls_readv_recv
,
859 .writev_send
= tstream_tls_writev_send
,
860 .writev_recv
= tstream_tls_writev_recv
,
862 .disconnect_send
= tstream_tls_disconnect_send
,
863 .disconnect_recv
= tstream_tls_disconnect_recv
,
866 struct tstream_tls_params
{
868 gnutls_certificate_credentials x509_cred
;
869 gnutls_dh_params dh_params
;
870 #endif /* ENABLE_GNUTLS */
874 static int tstream_tls_params_destructor(struct tstream_tls_params
*tlsp
)
877 if (tlsp
->x509_cred
) {
878 gnutls_certificate_free_credentials(tlsp
->x509_cred
);
879 tlsp
->x509_cred
= NULL
;
881 if (tlsp
->dh_params
) {
882 gnutls_dh_params_deinit(tlsp
->dh_params
);
883 tlsp
->dh_params
= NULL
;
885 #endif /* ENABLE_GNUTLS */
889 bool tstream_tls_params_enabled(struct tstream_tls_params
*tlsp
)
891 return tlsp
->tls_enabled
;
894 NTSTATUS
tstream_tls_params_client(TALLOC_CTX
*mem_ctx
,
896 const char *crl_file
,
897 struct tstream_tls_params
**_tlsp
)
900 struct tstream_tls_params
*tlsp
;
903 ret
= gnutls_global_init();
904 if (ret
!= GNUTLS_E_SUCCESS
) {
905 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
906 return NT_STATUS_NOT_SUPPORTED
;
909 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
910 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
912 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
914 ret
= gnutls_certificate_allocate_credentials(&tlsp
->x509_cred
);
915 if (ret
!= GNUTLS_E_SUCCESS
) {
916 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
918 return NT_STATUS_NO_MEMORY
;
921 if (ca_file
&& *ca_file
) {
922 ret
= gnutls_certificate_set_x509_trust_file(tlsp
->x509_cred
,
924 GNUTLS_X509_FMT_PEM
);
926 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
927 ca_file
, gnutls_strerror(ret
)));
929 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
933 if (crl_file
&& *crl_file
) {
934 ret
= gnutls_certificate_set_x509_crl_file(tlsp
->x509_cred
,
936 GNUTLS_X509_FMT_PEM
);
938 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
939 crl_file
, gnutls_strerror(ret
)));
941 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
945 tlsp
->tls_enabled
= true;
949 #else /* ENABLE_GNUTLS */
950 return NT_STATUS_NOT_IMPLEMENTED
;
951 #endif /* ENABLE_GNUTLS */
954 struct tstream_tls_connect_state
{
955 struct tstream_context
*tls_stream
;
958 struct tevent_req
*_tstream_tls_connect_send(TALLOC_CTX
*mem_ctx
,
959 struct tevent_context
*ev
,
960 struct tstream_context
*plain_stream
,
961 struct tstream_tls_params
*tls_params
,
962 const char *location
)
964 struct tevent_req
*req
;
965 struct tstream_tls_connect_state
*state
;
967 struct tstream_tls
*tlss
;
969 static const int cert_type_priority
[] = {
974 #endif /* ENABLE_GNUTLS */
976 req
= tevent_req_create(mem_ctx
, &state
,
977 struct tstream_tls_connect_state
);
983 state
->tls_stream
= tstream_context_create(state
,
988 if (tevent_req_nomem(state
->tls_stream
, req
)) {
989 return tevent_req_post(req
, ev
);
992 talloc_set_destructor(tlss
, tstream_tls_destructor
);
994 tlss
->plain_stream
= plain_stream
;
996 tlss
->current_ev
= ev
;
997 tlss
->retry_im
= tevent_create_immediate(tlss
);
998 if (tevent_req_nomem(tlss
->retry_im
, req
)) {
999 return tevent_req_post(req
, ev
);
1002 ret
= gnutls_init(&tlss
->tls_session
, GNUTLS_CLIENT
);
1003 if (ret
!= GNUTLS_E_SUCCESS
) {
1004 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1005 tevent_req_error(req
, EINVAL
);
1006 return tevent_req_post(req
, ev
);
1009 ret
= gnutls_set_default_priority(tlss
->tls_session
);
1010 if (ret
!= GNUTLS_E_SUCCESS
) {
1011 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1012 tevent_req_error(req
, EINVAL
);
1013 return tevent_req_post(req
, ev
);
1016 gnutls_certificate_type_set_priority(tlss
->tls_session
, cert_type_priority
);
1018 ret
= gnutls_credentials_set(tlss
->tls_session
,
1019 GNUTLS_CRD_CERTIFICATE
,
1020 tls_params
->x509_cred
);
1021 if (ret
!= GNUTLS_E_SUCCESS
) {
1022 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1023 tevent_req_error(req
, EINVAL
);
1024 return tevent_req_post(req
, ev
);
1027 gnutls_transport_set_ptr(tlss
->tls_session
, (gnutls_transport_ptr
)state
->tls_stream
);
1028 gnutls_transport_set_pull_function(tlss
->tls_session
,
1029 (gnutls_pull_func
)tstream_tls_pull_function
);
1030 gnutls_transport_set_push_function(tlss
->tls_session
,
1031 (gnutls_push_func
)tstream_tls_push_function
);
1032 #if GNUTLS_VERSION_MAJOR < 3
1033 gnutls_transport_set_lowat(tlss
->tls_session
, 0);
1036 tlss
->handshake
.req
= req
;
1037 tstream_tls_retry_handshake(state
->tls_stream
);
1038 if (!tevent_req_is_in_progress(req
)) {
1039 return tevent_req_post(req
, ev
);
1043 #else /* ENABLE_GNUTLS */
1044 tevent_req_error(req
, ENOSYS
);
1045 return tevent_req_post(req
, ev
);
1046 #endif /* ENABLE_GNUTLS */
1049 int tstream_tls_connect_recv(struct tevent_req
*req
,
1051 TALLOC_CTX
*mem_ctx
,
1052 struct tstream_context
**tls_stream
)
1054 struct tstream_tls_connect_state
*state
=
1055 tevent_req_data(req
,
1056 struct tstream_tls_connect_state
);
1058 if (tevent_req_is_unix_error(req
, perrno
)) {
1059 tevent_req_received(req
);
1063 *tls_stream
= talloc_move(mem_ctx
, &state
->tls_stream
);
1064 tevent_req_received(req
);
1068 extern void tls_cert_generate(TALLOC_CTX
*, const char *, const char *, const char *, const char *);
1071 initialise global tls state
1073 NTSTATUS
tstream_tls_params_server(TALLOC_CTX
*mem_ctx
,
1074 const char *dns_host_name
,
1076 const char *key_file
,
1077 const char *cert_file
,
1078 const char *ca_file
,
1079 const char *crl_file
,
1080 const char *dhp_file
,
1081 struct tstream_tls_params
**_tlsp
)
1083 struct tstream_tls_params
*tlsp
;
1087 if (!enabled
|| key_file
== NULL
|| *key_file
== 0) {
1088 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1089 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1090 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1091 tlsp
->tls_enabled
= false;
1094 return NT_STATUS_OK
;
1097 ret
= gnutls_global_init();
1098 if (ret
!= GNUTLS_E_SUCCESS
) {
1099 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1100 return NT_STATUS_NOT_SUPPORTED
;
1103 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1104 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1106 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1108 if (!file_exist(ca_file
)) {
1109 tls_cert_generate(tlsp
, dns_host_name
,
1110 key_file
, cert_file
, ca_file
);
1113 ret
= gnutls_certificate_allocate_credentials(&tlsp
->x509_cred
);
1114 if (ret
!= GNUTLS_E_SUCCESS
) {
1115 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1117 return NT_STATUS_NO_MEMORY
;
1120 if (ca_file
&& *ca_file
) {
1121 ret
= gnutls_certificate_set_x509_trust_file(tlsp
->x509_cred
,
1123 GNUTLS_X509_FMT_PEM
);
1125 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1126 ca_file
, gnutls_strerror(ret
)));
1128 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1132 if (crl_file
&& *crl_file
) {
1133 ret
= gnutls_certificate_set_x509_crl_file(tlsp
->x509_cred
,
1135 GNUTLS_X509_FMT_PEM
);
1137 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1138 crl_file
, gnutls_strerror(ret
)));
1140 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1144 ret
= gnutls_certificate_set_x509_key_file(tlsp
->x509_cred
,
1145 cert_file
, key_file
,
1146 GNUTLS_X509_FMT_PEM
);
1147 if (ret
!= GNUTLS_E_SUCCESS
) {
1148 DEBUG(0,("TLS failed to initialise certfile %s and keyfile %s - %s\n",
1149 cert_file
, key_file
, gnutls_strerror(ret
)));
1151 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1154 ret
= gnutls_dh_params_init(&tlsp
->dh_params
);
1155 if (ret
!= GNUTLS_E_SUCCESS
) {
1156 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1158 return NT_STATUS_NO_MEMORY
;
1161 if (dhp_file
&& *dhp_file
) {
1162 gnutls_datum_t dhparms
;
1165 dhparms
.data
= (uint8_t *)file_load(dhp_file
, &size
, 0, tlsp
);
1167 if (!dhparms
.data
) {
1168 DEBUG(0,("TLS failed to read DH Parms from %s - %d:%s\n",
1169 dhp_file
, errno
, strerror(errno
)));
1171 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1173 dhparms
.size
= size
;
1175 ret
= gnutls_dh_params_import_pkcs3(tlsp
->dh_params
,
1177 GNUTLS_X509_FMT_PEM
);
1178 if (ret
!= GNUTLS_E_SUCCESS
) {
1179 DEBUG(0,("TLS failed to import pkcs3 %s - %s\n",
1180 dhp_file
, gnutls_strerror(ret
)));
1182 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO
;
1185 ret
= gnutls_dh_params_generate2(tlsp
->dh_params
, DH_BITS
);
1186 if (ret
!= GNUTLS_E_SUCCESS
) {
1187 DEBUG(0,("TLS failed to generate dh_params - %s\n",
1188 gnutls_strerror(ret
)));
1190 return NT_STATUS_INTERNAL_ERROR
;
1194 gnutls_certificate_set_dh_params(tlsp
->x509_cred
, tlsp
->dh_params
);
1196 tlsp
->tls_enabled
= true;
1198 #else /* ENABLE_GNUTLS */
1199 tlsp
= talloc_zero(mem_ctx
, struct tstream_tls_params
);
1200 NT_STATUS_HAVE_NO_MEMORY(tlsp
);
1201 talloc_set_destructor(tlsp
, tstream_tls_params_destructor
);
1202 tlsp
->tls_enabled
= false;
1203 #endif /* ENABLE_GNUTLS */
1206 return NT_STATUS_OK
;
1209 struct tstream_tls_accept_state
{
1210 struct tstream_context
*tls_stream
;
1213 struct tevent_req
*_tstream_tls_accept_send(TALLOC_CTX
*mem_ctx
,
1214 struct tevent_context
*ev
,
1215 struct tstream_context
*plain_stream
,
1216 struct tstream_tls_params
*tlsp
,
1217 const char *location
)
1219 struct tevent_req
*req
;
1220 struct tstream_tls_accept_state
*state
;
1221 struct tstream_tls
*tlss
;
1224 #endif /* ENABLE_GNUTLS */
1226 req
= tevent_req_create(mem_ctx
, &state
,
1227 struct tstream_tls_accept_state
);
1232 state
->tls_stream
= tstream_context_create(state
,
1237 if (tevent_req_nomem(state
->tls_stream
, req
)) {
1238 return tevent_req_post(req
, ev
);
1241 talloc_set_destructor(tlss
, tstream_tls_destructor
);
1244 tlss
->plain_stream
= plain_stream
;
1246 tlss
->current_ev
= ev
;
1247 tlss
->retry_im
= tevent_create_immediate(tlss
);
1248 if (tevent_req_nomem(tlss
->retry_im
, req
)) {
1249 return tevent_req_post(req
, ev
);
1252 ret
= gnutls_init(&tlss
->tls_session
, GNUTLS_SERVER
);
1253 if (ret
!= GNUTLS_E_SUCCESS
) {
1254 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1255 tevent_req_error(req
, EINVAL
);
1256 return tevent_req_post(req
, ev
);
1259 ret
= gnutls_set_default_priority(tlss
->tls_session
);
1260 if (ret
!= GNUTLS_E_SUCCESS
) {
1261 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1262 tevent_req_error(req
, EINVAL
);
1263 return tevent_req_post(req
, ev
);
1266 ret
= gnutls_credentials_set(tlss
->tls_session
, GNUTLS_CRD_CERTIFICATE
,
1268 if (ret
!= GNUTLS_E_SUCCESS
) {
1269 DEBUG(0,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1270 tevent_req_error(req
, EINVAL
);
1271 return tevent_req_post(req
, ev
);
1274 gnutls_certificate_server_set_request(tlss
->tls_session
,
1275 GNUTLS_CERT_REQUEST
);
1276 gnutls_dh_set_prime_bits(tlss
->tls_session
, DH_BITS
);
1278 gnutls_transport_set_ptr(tlss
->tls_session
, (gnutls_transport_ptr
)state
->tls_stream
);
1279 gnutls_transport_set_pull_function(tlss
->tls_session
,
1280 (gnutls_pull_func
)tstream_tls_pull_function
);
1281 gnutls_transport_set_push_function(tlss
->tls_session
,
1282 (gnutls_push_func
)tstream_tls_push_function
);
1283 #if GNUTLS_VERSION_MAJOR < 3
1284 gnutls_transport_set_lowat(tlss
->tls_session
, 0);
1287 tlss
->handshake
.req
= req
;
1288 tstream_tls_retry_handshake(state
->tls_stream
);
1289 if (!tevent_req_is_in_progress(req
)) {
1290 return tevent_req_post(req
, ev
);
1294 #else /* ENABLE_GNUTLS */
1295 tevent_req_error(req
, ENOSYS
);
1296 return tevent_req_post(req
, ev
);
1297 #endif /* ENABLE_GNUTLS */
1300 static void tstream_tls_retry_handshake(struct tstream_context
*stream
)
1302 struct tstream_tls
*tlss
=
1303 tstream_context_data(stream
,
1304 struct tstream_tls
);
1305 struct tevent_req
*req
= tlss
->handshake
.req
;
1309 if (tlss
->error
!= 0) {
1310 tevent_req_error(req
, tlss
->error
);
1314 ret
= gnutls_handshake(tlss
->tls_session
);
1315 if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
) {
1319 tlss
->handshake
.req
= NULL
;
1321 if (gnutls_error_is_fatal(ret
) != 0) {
1322 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1324 tevent_req_error(req
, tlss
->error
);
1328 if (ret
!= GNUTLS_E_SUCCESS
) {
1329 DEBUG(1,("TLS %s - %s\n", __location__
, gnutls_strerror(ret
)));
1331 tevent_req_error(req
, tlss
->error
);
1335 tevent_req_done(req
);
1336 #else /* ENABLE_GNUTLS */
1337 tevent_req_error(req
, ENOSYS
);
1338 #endif /* ENABLE_GNUTLS */
1341 int tstream_tls_accept_recv(struct tevent_req
*req
,
1343 TALLOC_CTX
*mem_ctx
,
1344 struct tstream_context
**tls_stream
)
1346 struct tstream_tls_accept_state
*state
=
1347 tevent_req_data(req
,
1348 struct tstream_tls_accept_state
);
1350 if (tevent_req_is_unix_error(req
, perrno
)) {
1351 tevent_req_received(req
);
1355 *tls_stream
= talloc_move(mem_ctx
, &state
->tls_stream
);
1356 tevent_req_received(req
);