CVE-2013-4476: s4:libtls: check for safe permissions of tls private key file (key...
[Samba.git] / source4 / lib / tls / tls_tstream.c
blob2cb75edba489a5843078ec742398a527d689b707
1 /*
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/>.
20 #include "includes.h"
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"
28 #if ENABLE_GNUTLS
29 #include <gnutls/gnutls.h>
31 #define DH_BITS 1024
33 #if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
34 typedef gnutls_datum gnutls_datum_t;
35 #endif
37 #endif /* ENABLE_GNUTLS */
39 static const struct tstream_context_ops tstream_tls_ops;
41 struct tstream_tls {
42 struct tstream_context *plain_stream;
43 int error;
45 #if ENABLE_GNUTLS
46 gnutls_session tls_session;
47 #endif /* ENABLE_GNUTLS */
49 struct tevent_context *current_ev;
51 struct tevent_immediate *retry_im;
53 struct {
54 uint8_t *buf;
55 off_t ofs;
56 struct iovec iov;
57 struct tevent_req *subreq;
58 struct tevent_immediate *im;
59 } push;
61 struct {
62 uint8_t *buf;
63 struct iovec iov;
64 struct tevent_req *subreq;
65 } pull;
67 struct {
68 struct tevent_req *req;
69 } handshake;
71 struct {
72 off_t ofs;
73 size_t left;
74 uint8_t buffer[1024];
75 struct tevent_req *req;
76 } write;
78 struct {
79 off_t ofs;
80 size_t left;
81 uint8_t buffer[1024];
82 struct tevent_req *req;
83 } read;
85 struct {
86 struct tevent_req *req;
87 } disconnect;
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,
96 void *private_data);
98 static void tstream_tls_retry(struct tstream_context *stream, bool deferred)
101 struct tstream_tls *tlss =
102 tstream_context_data(stream,
103 struct tstream_tls);
105 if (tlss->disconnect.req) {
106 tstream_tls_retry_disconnect(stream);
107 return;
110 if (tlss->handshake.req) {
111 tstream_tls_retry_handshake(stream);
112 return;
115 if (tlss->write.req && tlss->read.req && !deferred) {
116 tevent_schedule_immediate(tlss->retry_im, tlss->current_ev,
117 tstream_tls_retry_trigger,
118 stream);
121 if (tlss->write.req) {
122 tstream_tls_retry_write(stream);
123 return;
126 if (tlss->read.req) {
127 tstream_tls_retry_read(stream);
128 return;
132 static void tstream_tls_retry_trigger(struct tevent_context *ctx,
133 struct tevent_immediate *im,
134 void *private_data)
136 struct tstream_context *stream =
137 talloc_get_type_abort(private_data,
138 struct tstream_context);
140 tstream_tls_retry(stream, true);
143 #if ENABLE_GNUTLS
144 static void tstream_tls_push_trigger_write(struct tevent_context *ev,
145 struct tevent_immediate *im,
146 void *private_data);
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,
156 struct tstream_tls);
157 uint8_t *nbuf;
158 size_t len;
160 if (tlss->error != 0) {
161 errno = tlss->error;
162 return -1;
165 if (tlss->push.subreq) {
166 errno = EAGAIN;
167 return -1;
170 len = MIN(size, UINT16_MAX - tlss->push.ofs);
172 if (len == 0) {
173 errno = EAGAIN;
174 return -1;
177 nbuf = talloc_realloc(tlss, tlss->push.buf,
178 uint8_t, tlss->push.ofs + len);
179 if (nbuf == NULL) {
180 if (tlss->push.buf) {
181 errno = EAGAIN;
182 return -1;
185 return -1;
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) {
194 errno = ENOMEM;
195 return -1;
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
210 * handle EAGAIN.
212 tevent_schedule_immediate(tlss->push.im,
213 tlss->current_ev,
214 tstream_tls_push_trigger_write,
215 stream);
218 tlss->push.ofs += len;
219 return 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,
226 void *private_data)
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,
233 struct tstream_tls);
234 struct tevent_req *subreq;
236 if (tlss->push.subreq) {
237 /* nothing todo */
238 return;
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,
245 tlss->current_ev,
246 tlss->plain_stream,
247 &tlss->push.iov, 1);
248 if (subreq == NULL) {
249 tlss->error = ENOMEM;
250 tstream_tls_retry(stream, false);
251 return;
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,
265 struct tstream_tls);
266 int ret;
267 int sys_errno;
269 tlss->push.subreq = NULL;
270 ZERO_STRUCT(tlss->push.iov);
271 TALLOC_FREE(tlss->push.buf);
272 tlss->push.ofs = 0;
274 ret = tstream_writev_recv(subreq, &sys_errno);
275 TALLOC_FREE(subreq);
276 if (ret == -1) {
277 tlss->error = sys_errno;
278 tstream_tls_retry(stream, false);
279 return;
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,
295 struct tstream_tls);
296 struct tevent_req *subreq;
297 size_t len;
299 if (tlss->error != 0) {
300 errno = tlss->error;
301 return -1;
304 if (tlss->pull.subreq) {
305 errno = EAGAIN;
306 return -1;
309 if (tlss->pull.iov.iov_base) {
310 uint8_t *b;
311 size_t n;
313 b = (uint8_t *)tlss->pull.iov.iov_base;
315 n = MIN(tlss->pull.iov.iov_len, size);
316 memcpy(buf, b, n);
318 tlss->pull.iov.iov_len -= n;
319 b += 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);
326 return n;
329 if (size == 0) {
330 return 0;
333 len = MIN(size, UINT16_MAX);
335 tlss->pull.buf = talloc_array(tlss, uint8_t, len);
336 if (tlss->pull.buf == NULL) {
337 return -1;
340 tlss->pull.iov.iov_base = (char *)tlss->pull.buf;
341 tlss->pull.iov.iov_len = len;
343 subreq = tstream_readv_send(tlss,
344 tlss->current_ev,
345 tlss->plain_stream,
346 &tlss->pull.iov, 1);
347 if (subreq == NULL) {
348 errno = ENOMEM;
349 return -1;
351 tevent_req_set_callback(subreq, tstream_tls_pull_done, stream);
353 tlss->pull.subreq = subreq;
354 errno = EAGAIN;
355 return -1;
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,
365 struct tstream_tls);
366 int ret;
367 int sys_errno;
369 tlss->pull.subreq = NULL;
371 ret = tstream_readv_recv(subreq, &sys_errno);
372 TALLOC_FREE(subreq);
373 if (ret == -1) {
374 tlss->error = sys_errno;
375 tstream_tls_retry(stream, false);
376 return;
379 tstream_tls_retry(stream, false);
381 #endif /* ENABLE_GNUTLS */
383 static int tstream_tls_destructor(struct tstream_tls *tlss)
385 #if ENABLE_GNUTLS
386 if (tlss->tls_session) {
387 gnutls_deinit(tlss->tls_session);
388 tlss->tls_session = NULL;
390 #endif /* ENABLE_GNUTLS */
391 return 0;
394 static ssize_t tstream_tls_pending_bytes(struct tstream_context *stream)
396 struct tstream_tls *tlss =
397 tstream_context_data(stream,
398 struct tstream_tls);
399 size_t ret;
401 if (tlss->error != 0) {
402 errno = tlss->error;
403 return -1;
406 #if ENABLE_GNUTLS
407 ret = gnutls_record_check_pending(tlss->tls_session);
408 ret += tlss->read.left;
409 #else /* ENABLE_GNUTLS */
410 errno = ENOSYS;
411 ret = -1;
412 #endif /* ENABLE_GNUTLS */
413 return ret;
416 struct tstream_tls_readv_state {
417 struct tstream_context *stream;
419 struct iovec *vector;
420 int count;
422 int ret;
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,
431 size_t count)
433 struct tstream_tls *tlss =
434 tstream_context_data(stream,
435 struct tstream_tls);
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);
444 if (req == NULL) {
445 return NULL;
448 state->stream = stream;
449 state->ret = 0;
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);
471 return req;
474 static void tstream_tls_readv_crypt_next(struct tevent_req *req)
476 struct tstream_tls_readv_state *state =
477 tevent_req_data(req,
478 struct tstream_tls_readv_state);
479 struct tstream_tls *tlss =
480 tstream_context_data(state->stream,
481 struct tstream_tls);
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);
492 base += 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) {
500 state->vector += 1;
501 state->count -= 1;
504 state->ret += len;
507 if (state->count == 0) {
508 tevent_req_done(req);
509 return;
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,
520 struct tstream_tls);
521 struct tevent_req *req = tlss->read.req;
522 #if ENABLE_GNUTLS
523 int ret;
525 if (tlss->error != 0) {
526 tevent_req_error(req, tlss->error);
527 return;
530 tlss->read.left = 0;
531 tlss->read.ofs = 0;
533 ret = gnutls_record_recv(tlss->tls_session,
534 tlss->read.buffer,
535 sizeof(tlss->read.buffer));
536 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
537 return;
540 tlss->read.req = NULL;
542 if (gnutls_error_is_fatal(ret) != 0) {
543 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
544 tlss->error = EIO;
545 tevent_req_error(req, tlss->error);
546 return;
549 if (ret == 0) {
550 tlss->error = EPIPE;
551 tevent_req_error(req, tlss->error);
552 return;
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,
563 int *perrno)
565 struct tstream_tls_readv_state *state =
566 tevent_req_data(req,
567 struct tstream_tls_readv_state);
568 struct tstream_tls *tlss =
569 tstream_context_data(state->stream,
570 struct tstream_tls);
571 int ret;
573 tlss->read.req = NULL;
575 ret = tsocket_simple_int_recv(req, perrno);
576 if (ret == 0) {
577 ret = state->ret;
580 tevent_req_received(req);
581 return ret;
584 struct tstream_tls_writev_state {
585 struct tstream_context *stream;
587 struct iovec *vector;
588 int count;
590 int ret;
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,
599 size_t count)
601 struct tstream_tls *tlss =
602 tstream_context_data(stream,
603 struct tstream_tls);
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);
612 if (req == NULL) {
613 return NULL;
616 state->stream = stream;
617 state->ret = 0;
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);
639 return req;
642 static void tstream_tls_writev_crypt_next(struct tevent_req *req)
644 struct tstream_tls_writev_state *state =
645 tevent_req_data(req,
646 struct tstream_tls_writev_state);
647 struct tstream_tls *tlss =
648 tstream_context_data(state->stream,
649 struct tstream_tls);
651 tlss->write.left = sizeof(tlss->write.buffer);
652 tlss->write.ofs = 0;
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);
663 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) {
671 state->vector += 1;
672 state->count -= 1;
675 state->ret += len;
678 if (tlss->write.ofs == 0) {
679 tevent_req_done(req);
680 return;
683 tlss->write.left = tlss->write.ofs;
684 tlss->write.ofs = 0;
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,
694 struct tstream_tls);
695 struct tevent_req *req = tlss->write.req;
696 #if ENABLE_GNUTLS
697 int ret;
699 if (tlss->error != 0) {
700 tevent_req_error(req, tlss->error);
701 return;
704 ret = gnutls_record_send(tlss->tls_session,
705 tlss->write.buffer + tlss->write.ofs,
706 tlss->write.left);
707 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
708 return;
711 tlss->write.req = NULL;
713 if (gnutls_error_is_fatal(ret) != 0) {
714 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
715 tlss->error = EIO;
716 tevent_req_error(req, tlss->error);
717 return;
720 if (ret == 0) {
721 tlss->error = EPIPE;
722 tevent_req_error(req, tlss->error);
723 return;
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);
732 return;
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,
742 int *perrno)
744 struct tstream_tls_writev_state *state =
745 tevent_req_data(req,
746 struct tstream_tls_writev_state);
747 struct tstream_tls *tlss =
748 tstream_context_data(state->stream,
749 struct tstream_tls);
750 int ret;
752 tlss->write.req = NULL;
754 ret = tsocket_simple_int_recv(req, perrno);
755 if (ret == 0) {
756 ret = state->ret;
759 tevent_req_received(req);
760 return ret;
763 struct tstream_tls_disconnect_state {
764 uint8_t _dummy;
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,
773 struct tstream_tls);
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);
782 if (req == NULL) {
783 return NULL;
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);
797 return req;
800 static void tstream_tls_retry_disconnect(struct tstream_context *stream)
802 struct tstream_tls *tlss =
803 tstream_context_data(stream,
804 struct tstream_tls);
805 struct tevent_req *req = tlss->disconnect.req;
806 #if ENABLE_GNUTLS
807 int ret;
809 if (tlss->error != 0) {
810 tevent_req_error(req, tlss->error);
811 return;
814 ret = gnutls_bye(tlss->tls_session, GNUTLS_SHUT_WR);
815 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
816 return;
819 tlss->disconnect.req = NULL;
821 if (gnutls_error_is_fatal(ret) != 0) {
822 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
823 tlss->error = EIO;
824 tevent_req_error(req, tlss->error);
825 return;
828 if (ret != GNUTLS_E_SUCCESS) {
829 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
830 tlss->error = EIO;
831 tevent_req_error(req, tlss->error);
832 return;
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,
842 int *perrno)
844 int ret;
846 ret = tsocket_simple_int_recv(req, perrno);
848 tevent_req_received(req);
849 return ret;
852 static const struct tstream_context_ops tstream_tls_ops = {
853 .name = "tls",
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 {
868 #if ENABLE_GNUTLS
869 gnutls_certificate_credentials x509_cred;
870 gnutls_dh_params dh_params;
871 #endif /* ENABLE_GNUTLS */
872 bool tls_enabled;
875 static int tstream_tls_params_destructor(struct tstream_tls_params *tlsp)
877 #if ENABLE_GNUTLS
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 */
887 return 0;
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,
896 const char *ca_file,
897 const char *crl_file,
898 struct tstream_tls_params **_tlsp)
900 #if ENABLE_GNUTLS
901 struct tstream_tls_params *tlsp;
902 int ret;
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)));
918 talloc_free(tlsp);
919 return NT_STATUS_NO_MEMORY;
922 if (ca_file && *ca_file) {
923 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
924 ca_file,
925 GNUTLS_X509_FMT_PEM);
926 if (ret < 0) {
927 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
928 ca_file, gnutls_strerror(ret)));
929 talloc_free(tlsp);
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,
936 crl_file,
937 GNUTLS_X509_FMT_PEM);
938 if (ret < 0) {
939 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
940 crl_file, gnutls_strerror(ret)));
941 talloc_free(tlsp);
942 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
946 tlsp->tls_enabled = true;
948 *_tlsp = tlsp;
949 return NT_STATUS_OK;
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;
967 #if ENABLE_GNUTLS
968 struct tstream_tls *tlss;
969 int ret;
970 static const int cert_type_priority[] = {
971 GNUTLS_CRT_X509,
972 GNUTLS_CRT_OPENPGP,
975 #endif /* ENABLE_GNUTLS */
977 req = tevent_req_create(mem_ctx, &state,
978 struct tstream_tls_connect_state);
979 if (req == NULL) {
980 return NULL;
983 #if ENABLE_GNUTLS
984 state->tls_stream = tstream_context_create(state,
985 &tstream_tls_ops,
986 &tlss,
987 struct tstream_tls,
988 location);
989 if (tevent_req_nomem(state->tls_stream, req)) {
990 return tevent_req_post(req, ev);
992 ZERO_STRUCTP(tlss);
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);
1035 #endif
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);
1043 return req;
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,
1051 int *perrno,
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);
1061 return -1;
1064 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1065 tevent_req_received(req);
1066 return 0;
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,
1076 bool enabled,
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;
1085 #if ENABLE_GNUTLS
1086 int ret;
1087 struct stat st;
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;
1095 *_tlsp = tlsp;
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",
1123 key_file,
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)));
1132 talloc_free(tlsp);
1133 return NT_STATUS_NO_MEMORY;
1136 if (ca_file && *ca_file) {
1137 ret = gnutls_certificate_set_x509_trust_file(tlsp->x509_cred,
1138 ca_file,
1139 GNUTLS_X509_FMT_PEM);
1140 if (ret < 0) {
1141 DEBUG(0,("TLS failed to initialise cafile %s - %s\n",
1142 ca_file, gnutls_strerror(ret)));
1143 talloc_free(tlsp);
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,
1150 crl_file,
1151 GNUTLS_X509_FMT_PEM);
1152 if (ret < 0) {
1153 DEBUG(0,("TLS failed to initialise crlfile %s - %s\n",
1154 crl_file, gnutls_strerror(ret)));
1155 talloc_free(tlsp);
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)));
1166 talloc_free(tlsp);
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)));
1173 talloc_free(tlsp);
1174 return NT_STATUS_NO_MEMORY;
1177 if (dhp_file && *dhp_file) {
1178 gnutls_datum_t dhparms;
1179 size_t size;
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)));
1186 talloc_free(tlsp);
1187 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1189 dhparms.size = size;
1191 ret = gnutls_dh_params_import_pkcs3(tlsp->dh_params,
1192 &dhparms,
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)));
1197 talloc_free(tlsp);
1198 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1200 } else {
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)));
1205 talloc_free(tlsp);
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 */
1221 *_tlsp = tlsp;
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;
1238 #if ENABLE_GNUTLS
1239 int ret;
1240 #endif /* ENABLE_GNUTLS */
1242 req = tevent_req_create(mem_ctx, &state,
1243 struct tstream_tls_accept_state);
1244 if (req == NULL) {
1245 return NULL;
1248 state->tls_stream = tstream_context_create(state,
1249 &tstream_tls_ops,
1250 &tlss,
1251 struct tstream_tls,
1252 location);
1253 if (tevent_req_nomem(state->tls_stream, req)) {
1254 return tevent_req_post(req, ev);
1256 ZERO_STRUCTP(tlss);
1257 talloc_set_destructor(tlss, tstream_tls_destructor);
1259 #if ENABLE_GNUTLS
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,
1283 tlsp->x509_cred);
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);
1301 #endif
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);
1309 return req;
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;
1322 #if ENABLE_GNUTLS
1323 int ret;
1325 if (tlss->error != 0) {
1326 tevent_req_error(req, tlss->error);
1327 return;
1330 ret = gnutls_handshake(tlss->tls_session);
1331 if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
1332 return;
1335 tlss->handshake.req = NULL;
1337 if (gnutls_error_is_fatal(ret) != 0) {
1338 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1339 tlss->error = EIO;
1340 tevent_req_error(req, tlss->error);
1341 return;
1344 if (ret != GNUTLS_E_SUCCESS) {
1345 DEBUG(1,("TLS %s - %s\n", __location__, gnutls_strerror(ret)));
1346 tlss->error = EIO;
1347 tevent_req_error(req, tlss->error);
1348 return;
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,
1358 int *perrno,
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);
1368 return -1;
1371 *tls_stream = talloc_move(mem_ctx, &state->tls_stream);
1372 tevent_req_received(req);
1373 return 0;