r18068: This splits the handling of multiple SASL packets between the GENSEC
authorAndrew Bartlett <abartlet@samba.org>
Tue, 5 Sep 2006 09:42:54 +0000 (09:42 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:17:11 +0000 (14:17 -0500)
backend (if it chooses to implement it), or the GENSEC socket code.

This is to allow us to handle DIGEST-MD5 across to cyrus-sasl.

Andrew Bartlett
(This used to be commit 0a098006b431f4aa48632a27ca08e9adca8d9609)

source4/auth/gensec/gensec.c
source4/auth/gensec/gensec.h
source4/auth/gensec/socket.c
source4/auth/gensec/socket.h
source4/auth/gensec/spnego.c

index 7825949bdc309289e1d394ffe8d4c88866c7e99c..839b538eebacfc4f7399415d69ea88edb4ca9569 100644 (file)
@@ -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) 
index b154619edfdf43384a25291d1c11b8622c5ea494..8156866962e6f0261b56380a57da89cf034ad526 100644 (file)
@@ -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); 
index 92f2382882689f6195969af67bf08cfc605caaea..592535d8dcff6becff720d689f68261f747aa2b9 100644 (file)
@@ -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);
 
index a70b728e3f21ddb1fb2706cac9bd5cf7bb16243f..53773c5e74945d2a66f0e999bc6d9a5cbe5accd8 100644 (file)
@@ -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);
+
index a57e8cc8469b7fe35923b0f14dba9ed7257bef82..fa15176e779d098a4b171fb2c1aa0b634607c0dd 100644 (file)
@@ -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,