diff --git a/source/auth/gensec/socket.c b/source/auth/gensec/socket.c index f308f727126..92f23828826 100644 --- a/source/auth/gensec/socket.c +++ b/source/auth/gensec/socket.c @@ -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(current_socket, &gensec_socket_ops, &new_sock, + SOCKET_TYPE_STREAM, current_socket->flags | SOCKET_FLAG_ENCRYPT); + if (!NT_STATUS_IS_OK(nt_status)) { + *new_socket = NULL; + return nt_status; } - nt_status = socket_create_with_ops(socket, &gensec_socket_ops, &new_sock, - SOCKET_TYPE_STREAM, socket->flags | SOCKET_FLAG_ENCRYPT); - if (!NT_STATUS_IS_OK(nt_status)) { - return NULL; - } + 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; + } + + /* 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->gensec_security = gensec_security; - gensec_socket->socket = socket; - if (talloc_reference(gensec_socket, socket) == NULL) { - return NULL; - } - gensec_socket->recv_handler = recv_handler; - gensec_socket->recv_private = recv_private; - gensec_socket->ev = ev; - new_sock->private_data = gensec_socket; + 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; } diff --git a/source/auth/gensec/socket.h b/source/auth/gensec/socket.h index 1641e50868f..a70b728e3f2 100644 --- a/source/auth/gensec/socket.h +++ b/source/auth/gensec/socket.h @@ -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); diff --git a/source/ldap_server/ldap_bind.c b/source/ldap_server/ldap_bind.c index 3afb617499d..daa82c1e485 100644 --- a/source/ldap_server/ldap_bind.c +++ b/source/ldap_server/ldap_bind.c @@ -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); - } + 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; diff --git a/source/ldap_server/ldap_server.c b/source/ldap_server/ldap_server.c index cfbe6eb5b25..7807a936669 100644 --- a/source/ldap_server/ldap_server.c +++ b/source/ldap_server/ldap_server.c @@ -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; } diff --git a/source/lib/stream/packet.c b/source/lib/stream/packet.c index 2759c752149..0d144354866 100644 --- a/source/lib/stream/packet.c +++ b/source/lib/stream/packet.c @@ -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); diff --git a/source/lib/tls/tls.c b/source/lib/tls/tls.c index f9213af2a77..9a37dd0bc31 100644 --- a/source/lib/tls/tls.c +++ b/source/lib/tls/tls.c @@ -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) diff --git a/source/libcli/ldap/ldap_bind.c b/source/libcli/ldap/ldap_bind.c index 2b209c38711..f1f7872455a 100644 --- a/source/libcli/ldap/ldap_bind.c +++ b/source/libcli/ldap/ldap_bind.c @@ -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; diff --git a/source/libcli/ldap/ldap_client.c b/source/libcli/ldap/ldap_client.c index 2e834b5244f..eb7b9c63275 100644 --- a/source/libcli/ldap/ldap_client.c +++ b/source/libcli/ldap/ldap_client.c @@ -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);