diff options
-rw-r--r-- | source4/auth/gensec/gensec.c | 34 | ||||
-rw-r--r-- | source4/auth/gensec/gensec.h | 18 | ||||
-rw-r--r-- | source4/auth/gensec/socket.c | 170 | ||||
-rw-r--r-- | source4/auth/gensec/socket.h | 20 | ||||
-rw-r--r-- | source4/auth/gensec/spnego.c | 58 |
5 files changed, 239 insertions, 61 deletions
diff --git a/source4/auth/gensec/gensec.c b/source4/auth/gensec/gensec.c index 7825949bdc..839b538eeb 100644 --- a/source4/auth/gensec/gensec.c +++ b/source4/auth/gensec/gensec.c @@ -4,7 +4,7 @@ Generic Authentication Interface Copyright (C) Andrew Tridgell 2003 - Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006 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 @@ -51,7 +51,9 @@ struct gensec_security_ops **gensec_use_kerberos_mechs(TALLOC_CTX *mem_ctx, int i, j, num_mechs_in; if (use_kerberos == CRED_AUTO_USE_KERBEROS) { - talloc_reference(mem_ctx, old_gensec_list); + if (!talloc_reference(mem_ctx, old_gensec_list)) { + return NULL; + } return old_gensec_list; } @@ -103,13 +105,17 @@ struct gensec_security_ops **gensec_security_mechs(struct gensec_security *gense struct gensec_security_ops **backends; backends = gensec_security_all(); if (!gensec_security) { - talloc_reference(mem_ctx, backends); + if (!talloc_reference(mem_ctx, backends)) { + return NULL; + } return backends; } else { enum credentials_use_kerberos use_kerberos; struct cli_credentials *creds = gensec_get_credentials(gensec_security); if (!creds) { - talloc_reference(mem_ctx, backends); + if (!talloc_reference(mem_ctx, backends)) { + return NULL; + } return backends; } use_kerberos = cli_credentials_get_kerberos_state(creds); @@ -840,25 +846,25 @@ size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size return gensec_security->ops->sig_size(gensec_security, data_size); } -size_t gensec_max_input_size(struct gensec_security *gensec_security) +size_t gensec_max_wrapped_size(struct gensec_security *gensec_security) { - if (!gensec_security->ops->max_input_size) { - return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17); + if (!gensec_security->ops->max_wrapped_size) { + return (1 << 17); } - return gensec_security->ops->max_input_size(gensec_security); + return gensec_security->ops->max_wrapped_size(gensec_security); } -size_t gensec_max_wrapped_size(struct gensec_security *gensec_security) +size_t gensec_max_input_size(struct gensec_security *gensec_security) { - if (!gensec_security->ops->max_wrapped_size) { - return (1 << 17); + if (!gensec_security->ops->max_input_size) { + return (1 << 17) - gensec_sig_size(gensec_security, 1 << 17); } - return gensec_security->ops->max_wrapped_size(gensec_security); + return gensec_security->ops->max_input_size(gensec_security); } -_PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, +NTSTATUS gensec_wrap(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, const DATA_BLOB *in, DATA_BLOB *out) @@ -869,7 +875,7 @@ _PUBLIC_ NTSTATUS gensec_wrap(struct gensec_security *gensec_security, return gensec_security->ops->wrap(gensec_security, mem_ctx, in, out); } -_PUBLIC_ NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, +NTSTATUS gensec_unwrap(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx, const DATA_BLOB *in, DATA_BLOB *out) diff --git a/source4/auth/gensec/gensec.h b/source4/auth/gensec/gensec.h index b154619edf..8156866962 100644 --- a/source4/auth/gensec/gensec.h +++ b/source4/auth/gensec/gensec.h @@ -105,9 +105,21 @@ struct gensec_security_ops { const DATA_BLOB *in, DATA_BLOB *out); NTSTATUS (*unwrap)(struct gensec_security *gensec_security, - TALLOC_CTX *mem_ctx, - const DATA_BLOB *in, - DATA_BLOB *out); + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out); + NTSTATUS (*wrap_packets)(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out, + size_t *len_processed); + NTSTATUS (*unwrap_packets)(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out, + size_t *len_processed); + NTSTATUS (*packet_full_request)(struct gensec_security *gensec_security, + DATA_BLOB blob, size_t *size); NTSTATUS (*session_key)(struct gensec_security *gensec_security, DATA_BLOB *session_key); NTSTATUS (*session_info)(struct gensec_security *gensec_security, struct auth_session_info **session_info); diff --git a/source4/auth/gensec/socket.c b/source4/auth/gensec/socket.c index 92f2382882..592535d8dc 100644 --- a/source4/auth/gensec/socket.c +++ b/source4/auth/gensec/socket.c @@ -58,6 +58,115 @@ static NTSTATUS gensec_socket_init_fn(struct socket_context *sock) return NT_STATUS_OK; } +/* These functions are for use here only (public because SPNEGO must + * use them for recursion) */ +NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out, + size_t *len_processed) +{ + if (!gensec_security->ops->wrap_packets) { + NTSTATUS nt_status; + size_t max_input_size; + DATA_BLOB unwrapped, wrapped; + max_input_size = gensec_max_input_size(gensec_security); + unwrapped = data_blob_const(in->data, MIN(max_input_size, (size_t)in->length)); + + nt_status = gensec_wrap(gensec_security, + mem_ctx, + &unwrapped, &wrapped); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(mem_ctx); + return nt_status; + } + + *out = data_blob_talloc(mem_ctx, NULL, 4); + if (!out->data) { + return NT_STATUS_NO_MEMORY; + } + RSIVAL(out->data, 0, wrapped.length); + + nt_status = data_blob_append(mem_ctx, out, wrapped.data, wrapped.length); + + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + *len_processed = unwrapped.length; + return nt_status; + } + return gensec_security->ops->wrap_packets(gensec_security, mem_ctx, in, out, + len_processed); +} + +/* These functions are for use here only (public because SPNEGO must + * use them for recursion) */ +NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out, + size_t *len_processed) +{ + if (!gensec_security->ops->unwrap_packets) { + DATA_BLOB wrapped; + NTSTATUS nt_status; + size_t packet_size; + if (in->length < 4) { + /* Missing the header we already had! */ + DEBUG(0, ("Asked to unwrap packet of bogus length! How did we get the short packet?!\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + packet_size = RIVAL(in->data, 0); + + wrapped = data_blob_const(in->data + 4, packet_size); + + if (wrapped.length > (in->length - 4)) { + DEBUG(0, ("Asked to unwrap packed of bogus length %d > %d! How did we get this?!\n", + wrapped.length, in->length - 4)); + return NT_STATUS_INTERNAL_ERROR; + } + + nt_status = gensec_unwrap(gensec_security, + mem_ctx, + &wrapped, out); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + *len_processed = packet_size + 4; + return nt_status; + } + return gensec_security->ops->unwrap_packets(gensec_security, mem_ctx, in, out, + len_processed); +} + +/* These functions are for use here only (public because SPNEGO must + * use them for recursion) */ +NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security, + DATA_BLOB blob, size_t *size) +{ + if (gensec_security->ops->packet_full_request) { + return gensec_security->ops->packet_full_request(gensec_security, + blob, size); + } + if (gensec_security->ops->unwrap_packets) { + if (blob.length) { + *size = blob.length; + return NT_STATUS_OK; + } + return STATUS_MORE_ENTRIES; + } + return packet_full_request_u32(NULL, blob, size); +} + +static NTSTATUS gensec_socket_full_request(void *private, DATA_BLOB blob, size_t *size) +{ + struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket); + struct gensec_security *gensec_security = gensec_socket->gensec_security; + return gensec_packet_full_request(gensec_security, blob, size); +} + /* Try to figure out how much data is waiting to be read */ static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending) { @@ -183,37 +292,29 @@ static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf, static NTSTATUS gensec_socket_unwrap(void *private, DATA_BLOB blob) { struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket); - DATA_BLOB wrapped; DATA_BLOB unwrapped; NTSTATUS nt_status; TALLOC_CTX *mem_ctx; uint32_t packet_size; - if (blob.length < 4) { - /* Missing the header we already had! */ - DEBUG(0, ("Asked to unwrap packed of bogus length! How did we get the short packet?!\n")); - return NT_STATUS_INVALID_PARAMETER; - } - - wrapped = data_blob_const(blob.data + 4, blob.length - 4); - - packet_size = RIVAL(blob.data, 0); - if (packet_size != wrapped.length) { - DEBUG(0, ("Asked to unwrap packed of bogus length! How did we get this?!\n")); - return NT_STATUS_INTERNAL_ERROR; - } - mem_ctx = talloc_new(gensec_socket); if (!mem_ctx) { return NT_STATUS_NO_MEMORY; } - nt_status = gensec_unwrap(gensec_socket->gensec_security, - mem_ctx, - &wrapped, &unwrapped); + nt_status = gensec_unwrap_packets(gensec_socket->gensec_security, + mem_ctx, + &blob, &unwrapped, + &packet_size); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; } + + if (packet_size != blob.length) { + DEBUG(0, ("gensec_socket_unwrap: Did not consume entire packet!\n")); + return NT_STATUS_INTERNAL_ERROR; + } + /* We could change this into a linked list, and have * gensec_socket_recv() and gensec_socket_pending() walk the * linked list */ @@ -242,9 +343,8 @@ static NTSTATUS gensec_socket_send(struct socket_context *sock, { NTSTATUS nt_status; struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket); - DATA_BLOB unwrapped, wrapped, out; + DATA_BLOB wrapped; TALLOC_CTX *mem_ctx; - size_t max_input_size; if (!gensec_socket->wrap) { return socket_send(gensec_socket->socket, blob, sendlen); @@ -273,26 +373,10 @@ static NTSTATUS gensec_socket_send(struct socket_context *sock, return NT_STATUS_NO_MEMORY; } - max_input_size = gensec_max_input_size(gensec_socket->gensec_security); - unwrapped = data_blob_const(blob->data, MIN(max_input_size, (size_t)blob->length)); - - nt_status = gensec_wrap(gensec_socket->gensec_security, - mem_ctx, - &unwrapped, &wrapped); - if (!NT_STATUS_IS_OK(nt_status)) { - talloc_free(mem_ctx); - return nt_status; - } - - out = data_blob_talloc(mem_ctx, NULL, 4); - if (!out.data) { - talloc_free(mem_ctx); - return NT_STATUS_NO_MEMORY; - } - RSIVAL(out.data, 0, wrapped.length); - - nt_status = data_blob_append(gensec_socket, &out, wrapped.data, wrapped.length); - + nt_status = gensec_wrap_packets(gensec_socket->gensec_security, + mem_ctx, + blob, &wrapped, + &gensec_socket->orig_send_len); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(mem_ctx); return nt_status; @@ -300,11 +384,9 @@ static NTSTATUS gensec_socket_send(struct socket_context *sock, gensec_socket->interrupted = True; gensec_socket->error = NT_STATUS_OK; - gensec_socket->orig_send_len - = unwrapped.length; nt_status = packet_send_callback(gensec_socket->packet, - out, + wrapped, send_callback, gensec_socket); talloc_free(mem_ctx); @@ -390,7 +472,7 @@ NTSTATUS gensec_socket_init(struct gensec_security *gensec_security, packet_set_private(gensec_socket->packet, gensec_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_full_request(gensec_socket->packet, gensec_socket_full_request); packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler); packet_set_serialise(gensec_socket->packet); diff --git a/source4/auth/gensec/socket.h b/source4/auth/gensec/socket.h index a70b728e3f..53773c5e74 100644 --- a/source4/auth/gensec/socket.h +++ b/source4/auth/gensec/socket.h @@ -26,3 +26,23 @@ NTSTATUS gensec_socket_init(struct gensec_security *gensec_security, void (*recv_handler)(void *, uint16_t), void *recv_private, struct socket_context **new_socket); +/* These functions are for use here only (public because SPNEGO must + * use them for recursion) */ +NTSTATUS gensec_wrap_packets(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out, + size_t *len_processed); +/* These functions are for use here only (public because SPNEGO must + * use them for recursion) */ +NTSTATUS gensec_unwrap_packets(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out, + size_t *len_processed); + +/* These functions are for use here only (public because SPNEGO must + * use them for recursion) */ +NTSTATUS gensec_packet_full_request(struct gensec_security *gensec_security, + DATA_BLOB blob, size_t *size); + diff --git a/source4/auth/gensec/spnego.c b/source4/auth/gensec/spnego.c index a57e8cc846..fa15176e77 100644 --- a/source4/auth/gensec/spnego.c +++ b/source4/auth/gensec/spnego.c @@ -26,6 +26,8 @@ #include "auth/auth.h" #include "auth/gensec/spnego_proto.h" #include "librpc/gen_ndr/ndr_dcerpc.h" +#include "lib/socket/socket.h" +#include "auth/gensec/socket.h" enum spnego_state_position { SPNEGO_SERVER_START, @@ -199,6 +201,59 @@ static NTSTATUS gensec_spnego_unwrap(struct gensec_security *gensec_security, mem_ctx, in, out); } +static NTSTATUS gensec_spnego_wrap_packets(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out, + size_t *len_processed) +{ + struct spnego_state *spnego_state = gensec_security->private_data; + + if (spnego_state->state_position != SPNEGO_DONE + && spnego_state->state_position != SPNEGO_FALLBACK) { + DEBUG(1, ("gensec_spnego_wrap: wrong state for wrap\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_wrap_packets(spnego_state->sub_sec_security, + mem_ctx, in, out, + len_processed); +} + +static NTSTATUS gensec_spnego_packet_full_request(struct gensec_security *gensec_security, + DATA_BLOB blob, size_t *size) +{ + struct spnego_state *spnego_state = gensec_security->private_data; + + if (spnego_state->state_position != SPNEGO_DONE + && spnego_state->state_position != SPNEGO_FALLBACK) { + DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_packet_full_request(spnego_state->sub_sec_security, + blob, size); +} + +static NTSTATUS gensec_spnego_unwrap_packets(struct gensec_security *gensec_security, + TALLOC_CTX *mem_ctx, + const DATA_BLOB *in, + DATA_BLOB *out, + size_t *len_processed) +{ + struct spnego_state *spnego_state = gensec_security->private_data; + + if (spnego_state->state_position != SPNEGO_DONE + && spnego_state->state_position != SPNEGO_FALLBACK) { + DEBUG(1, ("gensec_spnego_unwrap: wrong state for unwrap\n")); + return NT_STATUS_INVALID_PARAMETER; + } + + return gensec_unwrap_packets(spnego_state->sub_sec_security, + mem_ctx, in, out, + len_processed); +} + static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security, size_t data_size) { struct spnego_state *spnego_state = gensec_security->private_data; @@ -976,8 +1031,11 @@ static const struct gensec_security_ops gensec_spnego_security_ops = { .max_input_size = gensec_spnego_max_input_size, .check_packet = gensec_spnego_check_packet, .unseal_packet = gensec_spnego_unseal_packet, + .packet_full_request = gensec_spnego_packet_full_request, .wrap = gensec_spnego_wrap, .unwrap = gensec_spnego_unwrap, + .wrap_packets = gensec_spnego_wrap_packets, + .unwrap_packets = gensec_spnego_unwrap_packets, .session_key = gensec_spnego_session_key, .session_info = gensec_spnego_session_info, .have_feature = gensec_spnego_have_feature, |