s4:lib/tls - include GNUTLS headers consistently using <...>
[samba.git] / source4 / lib / tls / tls.c
index c3a6047e065aee25eca68c861e893c7759ea6d76..7bf2ff8e432a3d7db24f29d08f9c7a714caf2af7 100644 (file)
@@ -9,7 +9,7 @@
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 #include "lib/events/events.h"
 #include "lib/socket/socket.h"
+#include "lib/tls/tls.h"
+#include "param/param.h"
 
-#if HAVE_LIBGNUTLS
-#include "gnutls/gnutls.h"
+#if ENABLE_GNUTLS
+#include <gnutls/gnutls.h>
 
 #define DH_BITS 1024
 
+#if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)
+typedef gnutls_datum gnutls_datum_t;
+#endif
+
 /* hold persistent tls data */
 struct tls_params {
        gnutls_certificate_credentials x509_cred;
        gnutls_dh_params dh_params;
-       BOOL tls_enabled;
+       bool tls_enabled;
 };
 #endif
 
 /* hold per connection tls data */
 struct tls_context {
        struct socket_context *socket;
-       struct fd_event *fde;
-       BOOL tls_enabled;
-#if HAVE_LIBGNUTLS
+       struct tevent_fd *fde;
+       bool tls_enabled;
+#if ENABLE_GNUTLS
        gnutls_session session;
-       BOOL done_handshake;
-       BOOL have_first_byte;
+       bool done_handshake;
+       bool have_first_byte;
        uint8_t first_byte;
-       BOOL tls_detect;
+       bool tls_detect;
        const char *plain_chars;
-       BOOL output_pending;
+       bool output_pending;
        gnutls_certificate_credentials xcred;
-       BOOL interrupted;
+       bool interrupted;
 #endif
 };
 
-BOOL tls_enabled(struct socket_context *sock)
+bool tls_enabled(struct socket_context *sock)
 {
        struct tls_context *tls;
        if (!sock) {
-               return False;
+               return false;
        }
        if (strcmp(sock->backend_name, "tls") != 0) {
-               return False;
+               return false;
        }
        tls = talloc_get_type(sock->private_data, struct tls_context);
        if (!tls) {
-               return False;
+               return false;
        }
        return tls->tls_enabled;
 }
 
 
-#if HAVE_LIBGNUTLS
+#if ENABLE_GNUTLS
 
 static const struct socket_ops tls_socket_ops;
 
@@ -112,7 +117,7 @@ static ssize_t tls_pull(gnutls_transport_ptr ptr, void *buf, size_t size)
        
        if (tls->have_first_byte) {
                *(uint8_t *)buf = tls->first_byte;
-               tls->have_first_byte = False;
+               tls->have_first_byte = false;
                return 1;
        }
 
@@ -121,21 +126,21 @@ static ssize_t tls_pull(gnutls_transport_ptr ptr, void *buf, size_t size)
                return 0;
        }
        if (NT_STATUS_IS_ERR(status)) {
-               EVENT_FD_NOT_READABLE(tls->fde);
-               EVENT_FD_NOT_WRITEABLE(tls->fde);
+               TEVENT_FD_NOT_READABLE(tls->fde);
+               TEVENT_FD_NOT_WRITEABLE(tls->fde);
                errno = EBADF;
                return -1;
        }
        if (!NT_STATUS_IS_OK(status)) {
-               EVENT_FD_READABLE(tls->fde);
+               TEVENT_FD_READABLE(tls->fde);
                errno = EAGAIN;
                return -1;
        }
        if (tls->output_pending) {
-               EVENT_FD_WRITEABLE(tls->fde);
+               TEVENT_FD_WRITEABLE(tls->fde);
        }
        if (size != nread) {
-               EVENT_FD_READABLE(tls->fde);
+               TEVENT_FD_READABLE(tls->fde);
        }
        return nread;
 }
@@ -163,11 +168,11 @@ static ssize_t tls_push(gnutls_transport_ptr ptr, const void *buf, size_t size)
                return -1;
        }
        if (!NT_STATUS_IS_OK(status)) {
-               EVENT_FD_WRITEABLE(tls->fde);
+               TEVENT_FD_WRITEABLE(tls->fde);
                return -1;
        }
        if (size != nwritten) {
-               EVENT_FD_WRITEABLE(tls->fde);
+               TEVENT_FD_WRITEABLE(tls->fde);
        }
        return nwritten;
 }
@@ -180,7 +185,7 @@ static int tls_destructor(struct tls_context *tls)
        int ret;
        ret = gnutls_bye(tls->session, GNUTLS_SHUT_WR);
        if (ret < 0) {
-               DEBUG(0,("TLS gnutls_bye failed - %s\n", gnutls_strerror(ret)));
+               DEBUG(4,("TLS gnutls_bye failed - %s\n", gnutls_strerror(ret)));
        }
        return 0;
 }
@@ -200,7 +205,7 @@ static NTSTATUS tls_handshake(struct tls_context *tls)
        ret = gnutls_handshake(tls->session);
        if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
                if (gnutls_record_get_direction(tls->session) == 1) {
-                       EVENT_FD_WRITEABLE(tls->fde);
+                       TEVENT_FD_WRITEABLE(tls->fde);
                }
                return STATUS_MORE_ENTRIES;
        }
@@ -208,7 +213,7 @@ static NTSTATUS tls_handshake(struct tls_context *tls)
                DEBUG(0,("TLS gnutls_handshake failed - %s\n", gnutls_strerror(ret)));
                return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
        }
-       tls->done_handshake = True;
+       tls->done_handshake = true;
        return NT_STATUS_OK;
 }
 
@@ -230,7 +235,7 @@ static NTSTATUS tls_interrupted(struct tls_context *tls)
        if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
                return STATUS_MORE_ENTRIES;
        }
-       tls->interrupted = False;
+       tls->interrupted = false;
        return NT_STATUS_OK;
 }
 
@@ -269,15 +274,15 @@ static NTSTATUS tls_socket_recv(struct socket_context *sock, void *buf,
                status = socket_recv(tls->socket, &tls->first_byte, 1, nread);
                NT_STATUS_NOT_OK_RETURN(status);
                if (*nread == 0) return NT_STATUS_OK;
-               tls->tls_detect = False;
+               tls->tls_detect = false;
                /* look for the first byte of a valid HTTP operation */
                if (strchr(tls->plain_chars, tls->first_byte)) {
                        /* not a tls link */
-                       tls->tls_enabled = False;
+                       tls->tls_enabled = false;
                        *(uint8_t *)buf = tls->first_byte;
                        return NT_STATUS_OK;
                }
-               tls->have_first_byte = True;
+               tls->have_first_byte = true;
        }
 
        if (!tls->tls_enabled) {
@@ -293,9 +298,9 @@ static NTSTATUS tls_socket_recv(struct socket_context *sock, void *buf,
        ret = gnutls_record_recv(tls->session, buf, wantlen);
        if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
                if (gnutls_record_get_direction(tls->session) == 1) {
-                       EVENT_FD_WRITEABLE(tls->fde);
+                       TEVENT_FD_WRITEABLE(tls->fde);
                }
-               tls->interrupted = True;
+               tls->interrupted = true;
                return STATUS_MORE_ENTRIES;
        }
        if (ret < 0) {
@@ -329,13 +334,13 @@ static NTSTATUS tls_socket_send(struct socket_context *sock,
        ret = gnutls_record_send(tls->session, blob->data, blob->length);
        if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
                if (gnutls_record_get_direction(tls->session) == 1) {
-                       EVENT_FD_WRITEABLE(tls->fde);
+                       TEVENT_FD_WRITEABLE(tls->fde);
                }
-               tls->interrupted = True;
+               tls->interrupted = true;
                return STATUS_MORE_ENTRIES;
        }
        if (ret < 0) {
-               DEBUG(0,("gnutls_record_send of %d failed - %s\n", blob->length, gnutls_strerror(ret)));
+               DEBUG(0,("gnutls_record_send of %d failed - %s\n", (int)blob->length, gnutls_strerror(ret)));
                return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
        }
        *sendlen = ret;
@@ -347,31 +352,38 @@ static NTSTATUS tls_socket_send(struct socket_context *sock,
 /*
   initialise global tls state
 */
-struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx)
+struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
 {
        struct tls_params *params;
        int ret;
        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
-       const char *keyfile = private_path(tmp_ctx, lp_tls_keyfile());
-       const char *certfile = private_path(tmp_ctx, lp_tls_certfile());
-       const char *cafile = private_path(tmp_ctx, lp_tls_cafile());
-       const char *crlfile = private_path(tmp_ctx, lp_tls_crlfile());
-       void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *);
-
+       const char *keyfile = lpcfg_tls_keyfile(tmp_ctx, lp_ctx);
+       const char *certfile = lpcfg_tls_certfile(tmp_ctx, lp_ctx);
+       const char *cafile = lpcfg_tls_cafile(tmp_ctx, lp_ctx);
+       const char *crlfile = lpcfg_tls_crlfile(tmp_ctx, lp_ctx);
+       const char *dhpfile = lpcfg_tls_dhpfile(tmp_ctx, lp_ctx);
+       void tls_cert_generate(TALLOC_CTX *, const char *, const char *, const char *, const char *);
        params = talloc(mem_ctx, struct tls_params);
        if (params == NULL) {
                talloc_free(tmp_ctx);
                return NULL;
        }
 
-       if (!lp_tls_enabled() || keyfile == NULL || *keyfile == 0) {
-               params->tls_enabled = False;
+       if (!lpcfg_tls_enabled(lp_ctx) || keyfile == NULL || *keyfile == 0) {
+               params->tls_enabled = false;
                talloc_free(tmp_ctx);
                return params;
        }
 
        if (!file_exist(cafile)) {
-               tls_cert_generate(params, keyfile, certfile, cafile);
+               char *hostname = talloc_asprintf(mem_ctx, "%s.%s",
+                                                lpcfg_netbios_name(lp_ctx),
+                                                lpcfg_dnsdomain(lp_ctx));
+               if (hostname == NULL) {
+                       goto init_failed;
+               }
+               tls_cert_generate(params, hostname, keyfile, certfile, cafile);
+               talloc_free(hostname);
        }
 
        ret = gnutls_global_init();
@@ -408,22 +420,38 @@ struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx)
                goto init_failed;
        }
        
+       
        ret = gnutls_dh_params_init(&params->dh_params);
        if (ret < 0) goto init_failed;
 
-       ret = gnutls_dh_params_generate2(params->dh_params, DH_BITS);
-       if (ret < 0) goto init_failed;
+       if (dhpfile && *dhpfile) {
+               gnutls_datum_t dhparms;
+               size_t size;
+               dhparms.data = (uint8_t *)file_load(dhpfile, &size, 0, mem_ctx);
 
+               if (!dhparms.data) {
+                       DEBUG(0,("Failed to read DH Parms from %s\n", dhpfile));
+                       goto init_failed;
+               }
+               dhparms.size = size;
+                       
+               ret = gnutls_dh_params_import_pkcs3(params->dh_params, &dhparms, GNUTLS_X509_FMT_PEM);
+               if (ret < 0) goto init_failed;
+       } else {
+               ret = gnutls_dh_params_generate2(params->dh_params, DH_BITS);
+               if (ret < 0) goto init_failed;
+       }
+               
        gnutls_certificate_set_dh_params(params->x509_cred, params->dh_params);
 
-       params->tls_enabled = True;
+       params->tls_enabled = true;
 
        talloc_free(tmp_ctx);
        return params;
 
 init_failed:
        DEBUG(0,("GNUTLS failed to initialise - %s\n", gnutls_strerror(ret)));
-       params->tls_enabled = False;
+       params->tls_enabled = false;
        talloc_free(tmp_ctx);
        return params;
 }
@@ -433,8 +461,8 @@ init_failed:
   setup for a new connection
 */
 struct socket_context *tls_init_server(struct tls_params *params, 
-                                      struct socket_context *socket,
-                                      struct fd_event *fde, 
+                                      struct socket_context *socket_ctx,
+                                      struct tevent_fd *fde, 
                                       const char *plain_chars)
 {
        struct tls_context *tls;
@@ -442,9 +470,9 @@ struct socket_context *tls_init_server(struct tls_params *params,
        struct socket_context *new_sock;
        NTSTATUS nt_status;
        
-       nt_status = socket_create_with_ops(socket, &tls_socket_ops, &new_sock, 
+       nt_status = socket_create_with_ops(socket_ctx, &tls_socket_ops, &new_sock, 
                                           SOCKET_TYPE_STREAM, 
-                                          socket->flags | SOCKET_FLAG_ENCRYPT);
+                                          socket_ctx->flags | SOCKET_FLAG_ENCRYPT);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return NULL;
        }
@@ -454,16 +482,9 @@ struct socket_context *tls_init_server(struct tls_params *params,
                return NULL;
        }
 
-       tls->socket          = socket;
+       tls->socket          = socket_ctx;
+       talloc_steal(tls, socket_ctx);
        tls->fde             = fde;
-       if (talloc_reference(tls, fde) == NULL) {
-               talloc_free(new_sock);
-               return NULL;
-       }
-       if (talloc_reference(tls, socket) == NULL) {
-               talloc_free(new_sock);
-               return NULL;
-       }
 
        new_sock->private_data    = tls;
 
@@ -484,20 +505,22 @@ struct socket_context *tls_init_server(struct tls_params *params,
        gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr)tls);
        gnutls_transport_set_pull_function(tls->session, (gnutls_pull_func)tls_pull);
        gnutls_transport_set_push_function(tls->session, (gnutls_push_func)tls_push);
+#if GNUTLS_VERSION_MAJOR < 3
        gnutls_transport_set_lowat(tls->session, 0);
+#endif
 
        tls->plain_chars = plain_chars;
        if (plain_chars) {
-               tls->tls_detect = True;
+               tls->tls_detect = true;
        } else {
-               tls->tls_detect = False;
+               tls->tls_detect = false;
        }
 
-       tls->output_pending  = False;
-       tls->done_handshake  = False;
-       tls->have_first_byte = False;
-       tls->tls_enabled     = True;
-       tls->interrupted     = False;
+       tls->output_pending  = false;
+       tls->done_handshake  = false;
+       tls->have_first_byte = false;
+       tls->tls_enabled     = true;
+       tls->interrupted     = false;
        
        new_sock->state = SOCKET_STATE_SERVER_CONNECTED;
 
@@ -513,19 +536,19 @@ failed:
 /*
   setup for a new client connection
 */
-struct socket_context *tls_init_client(struct socket_context *socket,
-                                      struct fd_event *fde)
+struct socket_context *tls_init_client(struct socket_context *socket_ctx,
+                                      struct tevent_fd *fde,
+                                      const char *ca_path)
 {
        struct tls_context *tls;
        int ret = 0;
        const int cert_type_priority[] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
-       char *cafile;
        struct socket_context *new_sock;
        NTSTATUS nt_status;
        
-       nt_status = socket_create_with_ops(socket, &tls_socket_ops, &new_sock, 
+       nt_status = socket_create_with_ops(socket_ctx, &tls_socket_ops, &new_sock, 
                                           SOCKET_TYPE_STREAM, 
-                                          socket->flags | SOCKET_FLAG_ENCRYPT);
+                                          socket_ctx->flags | SOCKET_FLAG_ENCRYPT);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return NULL;
        }
@@ -533,26 +556,16 @@ struct socket_context *tls_init_client(struct socket_context *socket,
        tls = talloc(new_sock, struct tls_context);
        if (tls == NULL) return NULL;
 
-       tls->socket          = socket;
+       tls->socket          = socket_ctx;
+       talloc_steal(tls, socket_ctx);
        tls->fde             = fde;
-       if (talloc_reference(tls, fde) == NULL) {
-               return NULL;
-       }
-       if (talloc_reference(tls, socket) == NULL) {
-               return NULL;
-       }
-       new_sock->private_data    = tls;
 
-       cafile = private_path(tls, lp_tls_cafile());
-       if (!cafile || !*cafile) {
-               goto failed;
-       }
+       new_sock->private_data    = tls;
 
        gnutls_global_init();
 
        gnutls_certificate_allocate_credentials(&tls->xcred);
-       gnutls_certificate_set_x509_trust_file(tls->xcred, cafile, GNUTLS_X509_FMT_PEM);
-       talloc_free(cafile);
+       gnutls_certificate_set_x509_trust_file(tls->xcred, ca_path, GNUTLS_X509_FMT_PEM);
        TLSCHECK(gnutls_init(&tls->session, GNUTLS_CLIENT));
        TLSCHECK(gnutls_set_default_priority(tls->session));
        gnutls_certificate_type_set_priority(tls->session, cert_type_priority);
@@ -563,14 +576,16 @@ struct socket_context *tls_init_client(struct socket_context *socket,
        gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr)tls);
        gnutls_transport_set_pull_function(tls->session, (gnutls_pull_func)tls_pull);
        gnutls_transport_set_push_function(tls->session, (gnutls_push_func)tls_push);
+#if GNUTLS_VERSION_MAJOR < 3
        gnutls_transport_set_lowat(tls->session, 0);
-       tls->tls_detect = False;
+#endif
+       tls->tls_detect = false;
 
-       tls->output_pending  = False;
-       tls->done_handshake  = False;
-       tls->have_first_byte = False;
-       tls->tls_enabled     = True;
-       tls->interrupted     = False;
+       tls->output_pending  = false;
+       tls->done_handshake  = false;
+       tls->have_first_byte = false;
+       tls->tls_enabled     = true;
+       tls->interrupted     = false;
        
        new_sock->state = SOCKET_STATE_CLIENT_CONNECTED;
 
@@ -578,7 +593,7 @@ struct socket_context *tls_init_client(struct socket_context *socket,
 
 failed:
        DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
-       tls->tls_enabled = False;
+       tls->tls_enabled = false;
        return new_sock;
 }
 
@@ -627,17 +642,12 @@ static const struct socket_ops tls_socket_ops = {
        .fn_get_fd              = tls_socket_get_fd
 };
 
-BOOL tls_support(struct tls_params *params)
-{
-       return params->tls_enabled;
-}
-
 #else
 
 /* for systems without tls we just fail the operations, and the caller
  * will retain the original socket */
 
-struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx)
+struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
 {
        return talloc_new(mem_ctx);
 }
@@ -647,7 +657,7 @@ struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx)
 */
 struct socket_context *tls_init_server(struct tls_params *params, 
                                    struct socket_context *socket,
-                                   struct fd_event *fde, 
+                                   struct tevent_fd *fde, 
                                    const char *plain_chars)
 {
        return NULL;
@@ -658,15 +668,11 @@ struct socket_context *tls_init_server(struct tls_params *params,
   setup for a new client connection
 */
 struct socket_context *tls_init_client(struct socket_context *socket,
-                                      struct fd_event *fde)
+                                      struct tevent_fd *fde,
+                                      const char *ca_path)
 {
        return NULL;
 }
 
-BOOL tls_support(struct tls_params *params)
-{
-       return False;
-}
-
 #endif