summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/auth/gensec/gensec.c34
-rw-r--r--source4/auth/gensec/gensec.h18
-rw-r--r--source4/auth/gensec/socket.c170
-rw-r--r--source4/auth/gensec/socket.h20
-rw-r--r--source4/auth/gensec/spnego.c58
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,