mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
r17222: 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
This commit is contained in:
parent
7c5a25a423
commit
003e2ab93c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user