r17222: Change the function prototypes for the GENSEc and TLS socket creation
authorAndrew Bartlett <abartlet@samba.org>
Tue, 25 Jul 2006 00:57:27 +0000 (00:57 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:10:20 +0000 (14:10 -0500)
routines to return an NTSTATUS.  This should help track down errors.

Use a bit of talloc_steal and talloc_unlink to get the real socket to
be a child of the GENSEC or TLS socket.

Always return a new socket, even for the 'pass-though' case.

Andrew Bartlett
(This used to be commit 003e2ab93c87267ba28cd67bd85975bad62a8ea2)

source4/auth/gensec/socket.c
source4/auth/gensec/socket.h
source4/ldap_server/ldap_bind.c
source4/ldap_server/ldap_server.c
source4/lib/stream/packet.c
source4/lib/tls/tls.c
source4/libcli/ldap/ldap_bind.c
source4/libcli/ldap/ldap_client.c

index f308f7271262e18a55e66da3c3ca9e3c135d0823..92f2382882689f6195969af67bf08cfc605caaea 100644 (file)
@@ -41,6 +41,7 @@ struct gensec_socket {
        void (*recv_handler)(void *, uint16_t);
        void *recv_private;
        int in_extra_read;
+       BOOL wrap; /* Should we be wrapping on this socket at all? */
 };
 
 static NTSTATUS gensec_socket_init_fn(struct socket_context *sock)
@@ -61,6 +62,10 @@ static NTSTATUS gensec_socket_init_fn(struct socket_context *sock)
 static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending) 
 {
        struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
+       if (!gensec_socket->wrap) {
+               return socket_pending(gensec_socket->socket, npending);
+       }
+
        if (gensec_socket->read_buffer.length > 0) {
                *npending = gensec_socket->read_buffer.length;
                return NT_STATUS_OK;
@@ -112,6 +117,10 @@ static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf,
 {
        struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
 
+       if (!gensec_socket->wrap) {
+               return socket_recv(gensec_socket->socket, buf, wantlen, nread);
+       }
+
        gensec_socket->error = NT_STATUS_OK;
 
        if (gensec_socket->read_buffer.length == 0) {
@@ -237,6 +246,10 @@ static NTSTATUS gensec_socket_send(struct socket_context *sock,
        TALLOC_CTX *mem_ctx;
        size_t max_input_size;
 
+       if (!gensec_socket->wrap) {
+               return socket_send(gensec_socket->socket, blob, sendlen);
+       }
+
        *sendlen = 0;
 
        /* We have have been interupted, so the caller should be
@@ -309,58 +322,73 @@ static NTSTATUS gensec_socket_send(struct socket_context *sock,
        }
 }
 
-struct socket_context *gensec_socket_init(struct gensec_security *gensec_security,
-                                         struct socket_context *socket,
-                                         struct event_context *ev,
-                                         void (*recv_handler)(void *, uint16_t),
-                                         void *recv_private)
+/* Turn a normal socket into a potentially GENSEC wrapped socket */
+
+NTSTATUS gensec_socket_init(struct gensec_security *gensec_security,
+                           struct socket_context *current_socket,
+                           struct event_context *ev,
+                           void (*recv_handler)(void *, uint16_t),
+                           void *recv_private,
+                           struct socket_context **new_socket)
 {
        struct gensec_socket *gensec_socket;
        struct socket_context *new_sock;
        NTSTATUS nt_status;
 
-       /* Nothing to do here, if we are not actually wrapping on this socket */
-       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) &&
-           !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
-               return socket;
-       }
-
-       nt_status = socket_create_with_ops(socket, &gensec_socket_ops, &new_sock, 
-                                          SOCKET_TYPE_STREAM, socket->flags | SOCKET_FLAG_ENCRYPT);
+       nt_status = socket_create_with_ops(current_socket, &gensec_socket_ops, &new_sock, 
+                                          SOCKET_TYPE_STREAM, current_socket->flags | SOCKET_FLAG_ENCRYPT);
        if (!NT_STATUS_IS_OK(nt_status)) {
-               return NULL;
+               *new_socket = NULL;
+               return nt_status;
        }
 
+       new_sock->state = current_socket->state;
+
        gensec_socket = talloc(new_sock, struct gensec_socket);
        if (gensec_socket == NULL) {
-               return NULL;
+               *new_socket = NULL;
+               return NT_STATUS_NO_MEMORY;
        }
 
-       gensec_socket->eof = False;
-       gensec_socket->error = NT_STATUS_OK;
-       gensec_socket->interrupted = False;
-       gensec_socket->in_extra_read = 0;
+       new_sock->private_data       = gensec_socket;
+       gensec_socket->socket        = current_socket;
 
-       gensec_socket->read_buffer = data_blob(NULL, 0);
+       if (talloc_reference(gensec_socket, current_socket) == NULL) {
+               *new_socket = NULL;
+               return NT_STATUS_NO_MEMORY;
+       }
 
-       gensec_socket->gensec_security = gensec_security;
-       gensec_socket->socket          = socket;
-       if (talloc_reference(gensec_socket, socket) == NULL) {
-               return NULL;
+       /* Nothing to do here, if we are not actually wrapping on this socket */
+       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) &&
+           !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+               
+               gensec_socket->wrap = False;
+               *new_socket = new_sock;
+               return NT_STATUS_OK;
        }
-       gensec_socket->recv_handler    = recv_handler;
-       gensec_socket->recv_private    = recv_private;
-       gensec_socket->ev              = ev;
 
-       new_sock->private_data    = gensec_socket;
+       gensec_socket->gensec_security = gensec_security;
+
+       gensec_socket->wrap          = True;
+       gensec_socket->eof           = False;
+       gensec_socket->error         = NT_STATUS_OK;
+       gensec_socket->interrupted   = False;
+       gensec_socket->in_extra_read = 0;
+
+       gensec_socket->read_buffer   = data_blob(NULL, 0);
+
+       gensec_socket->recv_handler  = recv_handler;
+       gensec_socket->recv_private  = recv_private;
+       gensec_socket->ev            = ev;
 
        gensec_socket->packet = packet_init(gensec_socket);
        if (gensec_socket->packet == NULL) {
-               return NULL;
+               *new_socket = NULL;
+               return NT_STATUS_NO_MEMORY;
        }
 
        packet_set_private(gensec_socket->packet, gensec_socket);
-       packet_set_socket(gensec_socket->packet, socket);
+       packet_set_socket(gensec_socket->packet, gensec_socket->socket);
        packet_set_callback(gensec_socket->packet, gensec_socket_unwrap);
        packet_set_full_request(gensec_socket->packet, packet_full_request_u32);
        packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler);
@@ -368,9 +396,8 @@ struct socket_context *gensec_socket_init(struct gensec_security *gensec_securit
 
        /* TODO: full-request that knows about maximum packet size */
 
-       new_sock->state = socket->state;
-
-       return new_sock;
+       *new_socket = new_sock;
+       return NT_STATUS_OK;
 }
 
 
index 1641e50868f93b9c27e847c05aa9b4cca732437b..a70b728e3f21ddb1fb2706cac9bd5cf7bb16243f 100644 (file)
@@ -20,8 +20,9 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-struct socket_context *gensec_socket_init(struct gensec_security *gensec_security,
-                                         struct socket_context *socket,
-                                         struct event_context *ev,
-                                         void (*recv_handler)(void *, uint16_t),
-                                         void *recv_private);
+NTSTATUS gensec_socket_init(struct gensec_security *gensec_security,
+                           struct socket_context *current_socket,
+                           struct event_context *ev,
+                           void (*recv_handler)(void *, uint16_t),
+                           void *recv_private,
+                           struct socket_context **new_socket);
index 3afb617499d5bc17cef960337f8555f52dbad7fa..daa82c1e48516544c3d97035b62a2d853527da48 100644 (file)
@@ -98,9 +98,11 @@ struct ldapsrv_sasl_context {
 static void ldapsrv_set_sasl(void *private) 
 {
        struct ldapsrv_sasl_context *ctx = talloc_get_type(private, struct ldapsrv_sasl_context);
+       talloc_steal(ctx->conn->connection, ctx->sasl_socket);
+       talloc_unlink(ctx->conn->connection, ctx->conn->connection->socket);
+
        ctx->conn->connection->socket = ctx->sasl_socket;
-       talloc_steal(ctx->conn->connection->socket, ctx->sasl_socket);
-       packet_set_socket(ctx->conn->packet, ctx->sasl_socket);
+       packet_set_socket(ctx->conn->packet, ctx->conn->connection->socket);
 }
 
 static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
@@ -193,21 +195,24 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
 
                ctx = talloc(call, struct ldapsrv_sasl_context); 
 
-               if (ctx) {
+               if (!ctx) {
+                       status = NT_STATUS_NO_MEMORY;
+               } else {
                        ctx->conn = conn;
-                       ctx->sasl_socket = gensec_socket_init(conn->gensec, 
-                                                             conn->connection->socket,
-                                                             conn->connection->event.ctx, 
-                                                             stream_io_handler_callback,
-                                                             conn->connection);
-               }
-
-               if (!ctx || !ctx->sasl_socket) {
+                       status = gensec_socket_init(conn->gensec, 
+                                                   conn->connection->socket,
+                                                   conn->connection->event.ctx, 
+                                                   stream_io_handler_callback,
+                                                   conn->connection,
+                                                   &ctx->sasl_socket);
+               } 
+
+               if (!ctx || !NT_STATUS_IS_OK(status)) {
                        conn->session_info = old_session_info;
                        result = LDAP_OPERATIONS_ERROR;
                        errstr = talloc_asprintf(reply, 
-                                                "SASL:[%s]: Failed to setup SASL socket (out of memory)", 
-                                                req->creds.SASL.mechanism);
+                                                "SASL:[%s]: Failed to setup SASL socket: %s", 
+                                                req->creds.SASL.mechanism, nt_errstr(status));
                } else {
 
                        call->send_callback = ldapsrv_set_sasl;
index cfbe6eb5b25c010bbd078f44e4d84696cd032bed..7807a936669f5869598c408f374dc0938da692af 100644 (file)
@@ -342,12 +342,16 @@ static void ldapsrv_accept(struct stream_connection *c)
        talloc_free(socket_address);
 
        if (port == 636) {
-               c->socket = tls_init_server(ldapsrv_service->tls_params, c->socket, 
-                                           c->event.fde, NULL);
-               if (!c->socket) {
+               struct socket_context *tls_socket = tls_init_server(ldapsrv_service->tls_params, c->socket, 
+                                                                   c->event.fde, NULL);
+               if (!tls_socket) {
                        ldapsrv_terminate_connection(conn, "ldapsrv_accept: tls_init_server() failed");
                        return;
                }
+               talloc_unlink(c, c->socket);
+               talloc_steal(c, tls_socket);
+               c->socket = tls_socket;
+
        } else if (port == 3268) /* Global catalog */ {
                conn->global_catalog = True;
        }
index 2759c752149c11a63d98488c37b8c4f47718a85f..0d144354866e14c72117f2a88da31b497e875312 100644 (file)
@@ -270,6 +270,16 @@ _PUBLIC_ void packet_recv(struct packet_context *pc)
                return;
        }
 
+       if (npending + pc->num_read < npending) {
+               packet_error(pc, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       if (npending + pc->num_read < pc->num_read) {
+               packet_error(pc, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
        /* possibly expand the partial packet buffer */
        if (npending + pc->num_read > pc->partial.length) {
                status = data_blob_realloc(pc, &pc->partial, npending+pc->num_read);
@@ -279,6 +289,20 @@ _PUBLIC_ void packet_recv(struct packet_context *pc)
                }
        }
 
+       if (pc->partial.length < pc->num_read + npending) {
+               packet_error(pc, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
+       if ((uint8_t *)pc->partial.data + pc->num_read < (uint8_t *)pc->partial.data) {
+               packet_error(pc, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+       if ((uint8_t *)pc->partial.data + pc->num_read + npending < (uint8_t *)pc->partial.data) {
+               packet_error(pc, NT_STATUS_INVALID_PARAMETER);
+               return;
+       }
+
        status = socket_recv(pc->sock, pc->partial.data + pc->num_read, 
                             npending, &nread);
 
@@ -337,6 +361,7 @@ next_partial:
                        packet_error(pc, NT_STATUS_NO_MEMORY);
                        return;
                }
+               /* Trunate the blob sent to the caller to only the packet length */
                status = data_blob_realloc(pc, &blob, pc->packet_size);
                if (!NT_STATUS_IS_OK(status)) {
                        packet_error(pc, status);
index f9213af2a77b8416123ec0d7061816566c0a9f10..9a37dd0bc31f6d3c7ed4050f04bc095b8c840ec9 100644 (file)
@@ -433,9 +433,9 @@ 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, 
-                                   const char *plain_chars)
+                                      struct socket_context *socket,
+                                      struct fd_event *fde, 
+                                      const char *plain_chars)
 {
        struct tls_context *tls;
        int ret;
@@ -457,17 +457,19 @@ struct socket_context *tls_init_server(struct tls_params *params,
        tls->socket          = socket;
        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;
 
        if (!params->tls_enabled) {
-               tls->tls_enabled = False;
-               return new_sock;
+               talloc_free(new_sock);
+               return NULL;
        }
 
        TLSCHECK(gnutls_init(&tls->session, GNUTLS_SERVER));
@@ -503,9 +505,8 @@ struct socket_context *tls_init_server(struct tls_params *params,
 
 failed:
        DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
-       tls->tls_enabled = False;
-       params->tls_enabled = False;
-       return new_sock;
+       talloc_free(new_sock);
+       return NULL;
 }
 
 
@@ -649,7 +650,10 @@ struct socket_context *tls_init_server(struct tls_params *params,
                                    struct fd_event *fde, 
                                    const char *plain_chars)
 {
-       return socket;
+       if (plain_chars) {
+               return socket;
+       }
+       return NULL;
 }
 
 
@@ -659,7 +663,7 @@ struct socket_context *tls_init_server(struct tls_params *params,
 struct socket_context *tls_init_client(struct socket_context *socket,
                                       struct fd_event *fde)
 {
-       return socket;
+       return NULL;
 }
 
 BOOL tls_support(struct tls_params *params)
index 2b209c38711f3fce8bb12dcd63dfc6e49ed1801d..f1f7872455af676f8fc54dd68a5b34ad767ef2bd 100644 (file)
@@ -370,15 +370,18 @@ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *cr
        talloc_free(tmp_ctx);
 
        if (NT_STATUS_IS_OK(status)) {
-               struct socket_context *socket = gensec_socket_init(conn->gensec, 
-                                                                  conn->sock,
-                                                                  conn->event.event_ctx, 
-                                                                  ldap_read_io_handler,
-                                                                  conn);
-               if (socket) {
-                       conn->sock = socket;
-                       talloc_steal(conn->sock, socket);
-                       packet_set_socket(conn->packet, socket);
+               struct socket_context *sasl_socket;
+               status = gensec_socket_init(conn->gensec, 
+                                           conn->sock,
+                                           conn->event.event_ctx, 
+                                           ldap_read_io_handler,
+                                           conn,
+                                           &sasl_socket);
+               if (NT_STATUS_IS_OK(status)) {
+                       talloc_steal(conn->sock, sasl_socket);
+                       talloc_unlink(conn, conn->sock);
+                       conn->sock = sasl_socket;
+                       packet_set_socket(conn->packet, conn->sock);
                } else {
                        status = NT_STATUS_NO_MEMORY;
                        goto failed;
index 2e834b5244f8ea0406754f8eee99f3c80f092521..eb7b9c632751b13332d65d6d3704b75d40a4d4b2 100644 (file)
@@ -320,7 +320,6 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
 
 static void ldap_connect_recv_conn(struct composite_context *ctx)
 {
-       struct socket_context *initial_socket;
        struct ldap_connect_state *state =
                talloc_get_type(ctx->async.private_data,
                                struct ldap_connect_state);
@@ -341,13 +340,15 @@ static void ldap_connect_recv_conn(struct composite_context *ctx)
        }
 
        talloc_steal(conn, conn->sock);
-       initial_socket = conn->sock;
        if (conn->ldaps) {
-               conn->sock = tls_init_client(conn->sock, conn->event.fde);
-               if (conn->sock == NULL) {
-                       talloc_free(initial_socket);
+               struct socket_context *tls_socket = tls_init_client(conn->sock, conn->event.fde);
+               if (tls_socket == NULL) {
+                       talloc_free(conn->sock);
                        return;
                }
+               talloc_unlink(conn, conn->sock);
+               conn->sock = tls_socket;
+               talloc_steal(conn, conn->sock);
        }
 
        conn->packet = packet_init(conn);