Author: abartlet Date: 2006-07-25 00:57:27 +0000 (Tue, 25 Jul 2006) New Revision: 17222
WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=17222 Log: Change the function prototypes for the GENSEc and TLS socket creation 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 Modified: branches/SAMBA_4_0/source/auth/gensec/socket.c branches/SAMBA_4_0/source/auth/gensec/socket.h branches/SAMBA_4_0/source/ldap_server/ldap_bind.c branches/SAMBA_4_0/source/ldap_server/ldap_server.c branches/SAMBA_4_0/source/lib/stream/packet.c branches/SAMBA_4_0/source/lib/tls/tls.c branches/SAMBA_4_0/source/libcli/ldap/ldap_bind.c branches/SAMBA_4_0/source/libcli/ldap/ldap_client.c Changeset: Modified: branches/SAMBA_4_0/source/auth/gensec/socket.c =================================================================== --- branches/SAMBA_4_0/source/auth/gensec/socket.c 2006-07-25 00:53:03 UTC (rev 17221) +++ branches/SAMBA_4_0/source/auth/gensec/socket.c 2006-07-25 00:57:27 UTC (rev 17222) @@ -41,6 +41,7 @@ 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_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 @@ { 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 @@ 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 @@ } } -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 @@ /* 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; } Modified: branches/SAMBA_4_0/source/auth/gensec/socket.h =================================================================== --- branches/SAMBA_4_0/source/auth/gensec/socket.h 2006-07-25 00:53:03 UTC (rev 17221) +++ branches/SAMBA_4_0/source/auth/gensec/socket.h 2006-07-25 00:57:27 UTC (rev 17222) @@ -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); Modified: branches/SAMBA_4_0/source/ldap_server/ldap_bind.c =================================================================== --- branches/SAMBA_4_0/source/ldap_server/ldap_bind.c 2006-07-25 00:53:03 UTC (rev 17221) +++ branches/SAMBA_4_0/source/ldap_server/ldap_bind.c 2006-07-25 00:57:27 UTC (rev 17222) @@ -98,9 +98,11 @@ 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 @@ 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); - } + status = gensec_socket_init(conn->gensec, + conn->connection->socket, + conn->connection->event.ctx, + stream_io_handler_callback, + conn->connection, + &ctx->sasl_socket); + } - if (!ctx || !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; Modified: branches/SAMBA_4_0/source/ldap_server/ldap_server.c =================================================================== --- branches/SAMBA_4_0/source/ldap_server/ldap_server.c 2006-07-25 00:53:03 UTC (rev 17221) +++ branches/SAMBA_4_0/source/ldap_server/ldap_server.c 2006-07-25 00:57:27 UTC (rev 17222) @@ -342,12 +342,16 @@ 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; } Modified: branches/SAMBA_4_0/source/lib/stream/packet.c =================================================================== --- branches/SAMBA_4_0/source/lib/stream/packet.c 2006-07-25 00:53:03 UTC (rev 17221) +++ branches/SAMBA_4_0/source/lib/stream/packet.c 2006-07-25 00:57:27 UTC (rev 17222) @@ -270,6 +270,16 @@ 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 @@ } } + 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 @@ 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); Modified: branches/SAMBA_4_0/source/lib/tls/tls.c =================================================================== --- branches/SAMBA_4_0/source/lib/tls/tls.c 2006-07-25 00:53:03 UTC (rev 17221) +++ branches/SAMBA_4_0/source/lib/tls/tls.c 2006-07-25 00:57:27 UTC (rev 17222) @@ -433,9 +433,9 @@ 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 @@ 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 @@ 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 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_client(struct socket_context *socket, struct fd_event *fde) { - return socket; + return NULL; } BOOL tls_support(struct tls_params *params) Modified: branches/SAMBA_4_0/source/libcli/ldap/ldap_bind.c =================================================================== --- branches/SAMBA_4_0/source/libcli/ldap/ldap_bind.c 2006-07-25 00:53:03 UTC (rev 17221) +++ branches/SAMBA_4_0/source/libcli/ldap/ldap_bind.c 2006-07-25 00:57:27 UTC (rev 17222) @@ -370,15 +370,18 @@ 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; Modified: branches/SAMBA_4_0/source/libcli/ldap/ldap_client.c =================================================================== --- branches/SAMBA_4_0/source/libcli/ldap/ldap_client.c 2006-07-25 00:53:03 UTC (rev 17221) +++ branches/SAMBA_4_0/source/libcli/ldap/ldap_client.c 2006-07-25 00:57:27 UTC (rev 17222) @@ -320,7 +320,6 @@ 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 @@ } 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);