The branch, master has been updated
       via  0f14ac4 s4:pygensec/tests: add test for gensec_set_max_update_size()
       via  891318e s4:auth/gensec/spnego: add support for fragmented spnego 
messages
       via  b3f8f7e s4:pygensec: add set_max_update_size() and 
max_update_size() functions
       via  6eea2c3 auth/gensec: add gensec_*max_update_size()
      from  1798609 s3: Split a line with 1 statements

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 0f14ac40a29bb23bb0a417df4bbeee009400f33e
Author: Stefan Metzmacher <me...@samba.org>
Date:   Wed Jan 11 16:00:59 2012 +0100

    s4:pygensec/tests: add test for gensec_set_max_update_size()
    
    metze
    
    Autobuild-User: Stefan Metzmacher <me...@samba.org>
    Autobuild-Date: Thu Jan 12 14:47:05 CET 2012 on sn-devel-104

commit 891318ee4cc77077525e698d21398c6db82f0a1a
Author: Stefan Metzmacher <me...@samba.org>
Date:   Sat Dec 24 00:27:45 2011 +0100

    s4:auth/gensec/spnego: add support for fragmented spnego messages
    
    metze

commit b3f8f7e8a3c28bc74f252534b1c45c9ed52d8ebe
Author: Stefan Metzmacher <me...@samba.org>
Date:   Wed Jan 11 14:53:52 2012 +0100

    s4:pygensec: add set_max_update_size() and max_update_size() functions
    
    metze

commit 6eea2c33c797065f7b189d32648d2cfde5d2e3b9
Author: Stefan Metzmacher <me...@samba.org>
Date:   Sat Dec 24 01:14:26 2011 +0100

    auth/gensec: add gensec_*max_update_size()
    
    This is only a hint for the backend, which may want to fragment
    update tokens.
    
    metze

-----------------------------------------------------------------------

Summary of changes:
 auth/gensec/gensec.c                           |   15 ++
 auth/gensec/gensec.h                           |    4 +
 auth/gensec/gensec_start.c                     |    3 +
 source4/auth/gensec/pygensec.c                 |   25 +++
 source4/auth/gensec/spnego.c                   |  208 +++++++++++++++++++++++-
 source4/scripting/python/samba/tests/gensec.py |   54 ++++++
 6 files changed, 306 insertions(+), 3 deletions(-)


Changeset truncated at 500 lines:

diff --git a/auth/gensec/gensec.c b/auth/gensec/gensec.c
index ec104a7..d1dcc75 100644
--- a/auth/gensec/gensec.c
+++ b/auth/gensec/gensec.c
@@ -185,6 +185,21 @@ _PUBLIC_ NTSTATUS gensec_session_info(struct 
gensec_security *gensec_security,
        return gensec_security->ops->session_info(gensec_security, mem_ctx, 
session_info);
 }
 
+void gensec_set_max_update_size(struct gensec_security *gensec_security,
+                               uint32_t max_update_size)
+{
+       gensec_security->max_update_size = max_update_size;
+}
+
+size_t gensec_max_update_size(struct gensec_security *gensec_security)
+{
+       if (gensec_security->max_update_size == 0) {
+               return UINT32_MAX;
+       }
+
+       return gensec_security->max_update_size;
+}
+
 /**
  * Next state function for the GENSEC state machine
  *
diff --git a/auth/gensec/gensec.h b/auth/gensec/gensec.h
index a1ae634..9982718 100644
--- a/auth/gensec/gensec.h
+++ b/auth/gensec/gensec.h
@@ -167,6 +167,7 @@ struct gensec_security {
        enum gensec_role gensec_role;
        bool subcontext;
        uint32_t want_features;
+       uint32_t max_update_size;
        uint8_t dcerpc_auth_level;
        struct tsocket_address *local_addr, *remote_addr;
        struct gensec_settings *settings;
@@ -223,6 +224,9 @@ NTSTATUS gensec_start_mech_by_ops(struct gensec_security 
*gensec_security,
                                  const struct gensec_security_ops *ops);
 NTSTATUS gensec_start_mech_by_sasl_list(struct gensec_security 
*gensec_security,
                                                 const char **sasl_names);
+void gensec_set_max_update_size(struct gensec_security *gensec_security,
+                               uint32_t max_update_size);
+size_t gensec_max_update_size(struct gensec_security *gensec_security);
 NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX 
*out_mem_ctx,
                       struct tevent_context *ev,
                       const DATA_BLOB in, DATA_BLOB *out);
diff --git a/auth/gensec/gensec_start.c b/auth/gensec/gensec_start.c
index 9576e53..016967a 100644
--- a/auth/gensec/gensec_start.c
+++ b/auth/gensec/gensec_start.c
@@ -518,6 +518,8 @@ static NTSTATUS gensec_start(TALLOC_CTX *mem_ctx,
        (*gensec_security) = talloc_zero(mem_ctx, struct gensec_security);
        NT_STATUS_HAVE_NO_MEMORY(*gensec_security);
 
+       (*gensec_security)->max_update_size = 0;
+
        SMB_ASSERT(settings->lp_ctx != NULL);
        (*gensec_security)->settings = talloc_reference(*gensec_security, 
settings);
 
@@ -550,6 +552,7 @@ _PUBLIC_ NTSTATUS gensec_subcontext_start(TALLOC_CTX 
*mem_ctx,
 
        (*gensec_security)->subcontext = true;
        (*gensec_security)->want_features = parent->want_features;
+       (*gensec_security)->max_update_size = parent->max_update_size;
        (*gensec_security)->dcerpc_auth_level = parent->dcerpc_auth_level;
        (*gensec_security)->auth_context = talloc_reference(*gensec_security, 
parent->auth_context);
        (*gensec_security)->settings = talloc_reference(*gensec_security, 
parent->settings);
diff --git a/source4/auth/gensec/pygensec.c b/source4/auth/gensec/pygensec.c
index a683daf..acbad5f 100644
--- a/source4/auth/gensec/pygensec.c
+++ b/source4/auth/gensec/pygensec.c
@@ -371,6 +371,27 @@ static PyObject *py_gensec_have_feature(PyObject *self, 
PyObject *args)
        return Py_False;
 }
 
+static PyObject *py_gensec_set_max_update_size(PyObject *self, PyObject *args)
+{
+       struct gensec_security *security = pytalloc_get_type(self, struct 
gensec_security);
+       unsigned int max_update_size = 0;
+
+       if (!PyArg_ParseTuple(args, "I", &max_update_size))
+               return NULL;
+
+       gensec_set_max_update_size(security, max_update_size);
+
+       Py_RETURN_NONE;
+}
+
+static PyObject *py_gensec_max_update_size(PyObject *self)
+{
+       struct gensec_security *security = pytalloc_get_type(self, struct 
gensec_security);
+       unsigned int max_update_size = gensec_max_update_size(security);
+
+       return PyInt_FromLong(max_update_size);
+}
+
 static PyObject *py_gensec_update(PyObject *self, PyObject *args)
 {
        NTSTATUS status;
@@ -512,6 +533,10 @@ static PyMethodDef py_gensec_security_methods[] = {
          "S.want_feature(feature)\n Request that GENSEC negotiate a particular 
feature." },
        { "have_feature", (PyCFunction)py_gensec_have_feature, METH_VARARGS,
          "S.have_feature()\n Return True if GENSEC negotiated a particular 
feature." },
+       { "set_max_update_size",  (PyCFunction)py_gensec_set_max_update_size, 
METH_VARARGS,
+               "S.set_max_update_size(max_size) \n Some mechs can fragment 
update packets, needs to be use before the mech is started." },
+       { "max_update_size",  (PyCFunction)py_gensec_max_update_size, 0,
+               "S.max_update_size() \n Return the current max_update_size." },
        { "update",  (PyCFunction)py_gensec_update, METH_VARARGS,
                "S.update(blob_in) -> (finished, blob_out)\nPerform one step in 
a GENSEC dance.  Repeat with new packets until finished is true or exception." 
},
        { "wrap",  (PyCFunction)py_gensec_wrap, METH_VARARGS,
diff --git a/source4/auth/gensec/spnego.c b/source4/auth/gensec/spnego.c
index fae32d8..fa20c45 100644
--- a/source4/auth/gensec/spnego.c
+++ b/source4/auth/gensec/spnego.c
@@ -30,6 +30,7 @@
 #include "auth/gensec/gensec_proto.h"
 #include "auth/gensec/gensec_toplevel_proto.h"
 #include "param/param.h"
+#include "lib/util/asn1.h"
 
 _PUBLIC_ NTSTATUS gensec_spnego_init(void);
 
@@ -51,6 +52,16 @@ struct spnego_state {
        const char *neg_oid;
 
        DATA_BLOB mech_types;
+
+       /*
+        * The following is used to implement
+        * the update token fragmentation
+        */
+       size_t in_needed;
+       DATA_BLOB in_frag;
+       size_t out_max_length;
+       DATA_BLOB out_frag;
+       NTSTATUS out_status;
 };
 
 
@@ -58,7 +69,7 @@ static NTSTATUS gensec_spnego_client_start(struct 
gensec_security *gensec_securi
 {
        struct spnego_state *spnego_state;
 
-       spnego_state = talloc(gensec_security, struct spnego_state);
+       spnego_state = talloc_zero(gensec_security, struct spnego_state);
        if (!spnego_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -68,6 +79,8 @@ static NTSTATUS gensec_spnego_client_start(struct 
gensec_security *gensec_securi
        spnego_state->sub_sec_security = NULL;
        spnego_state->no_response_expected = false;
        spnego_state->mech_types = data_blob(NULL, 0);
+       spnego_state->out_max_length = gensec_max_update_size(gensec_security);
+       spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
 
        gensec_security->private_data = spnego_state;
        return NT_STATUS_OK;
@@ -77,7 +90,7 @@ static NTSTATUS gensec_spnego_server_start(struct 
gensec_security *gensec_securi
 {
        struct spnego_state *spnego_state;
 
-       spnego_state = talloc(gensec_security, struct spnego_state);            
+       spnego_state = talloc_zero(gensec_security, struct spnego_state);
        if (!spnego_state) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -87,6 +100,8 @@ static NTSTATUS gensec_spnego_server_start(struct 
gensec_security *gensec_securi
        spnego_state->sub_sec_security = NULL;
        spnego_state->no_response_expected = false;
        spnego_state->mech_types = data_blob(NULL, 0);
+       spnego_state->out_max_length = gensec_max_update_size(gensec_security);
+       spnego_state->out_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
 
        gensec_security->private_data = spnego_state;
        return NT_STATUS_OK;
@@ -1130,6 +1145,193 @@ static NTSTATUS gensec_spnego_update(struct 
gensec_security *gensec_security, TA
        return NT_STATUS_INVALID_PARAMETER;
 }
 
+static NTSTATUS gensec_spnego_update_in(struct gensec_security 
*gensec_security,
+                                       const DATA_BLOB in, DATA_BLOB *full_in)
+{
+       struct spnego_state *spnego_state = (struct spnego_state 
*)gensec_security->private_data;
+       size_t expected;
+       uint8_t *buf;
+       NTSTATUS status;
+       bool ok;
+
+       *full_in = data_blob_null;
+
+       if (spnego_state->in_needed == 0) {
+               size_t size = 0;
+
+               /*
+                * try to work out the size of the full
+                * input token, it might be fragmented
+                */
+               status = asn1_peek_full_tag(in,  ASN1_APPLICATION(0), &size);
+               if (!NT_STATUS_IS_OK(status) &&
+                   !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+                       status = asn1_peek_full_tag(in, ASN1_CONTEXT(1), &size);
+               }
+
+               if (NT_STATUS_IS_OK(status) ||
+                   NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+                       spnego_state->in_needed = size;
+               } else {
+                       /*
+                        * If it is not an asn1 message
+                        * just call the next layer.
+                        */
+                       spnego_state->in_needed = in.length;
+               }
+       }
+
+       if (spnego_state->in_needed > UINT16_MAX) {
+               /*
+                * limit the incoming message to 0xFFFF
+                * to avoid DoS attacks.
+                */
+               return NT_STATUS_INVALID_BUFFER_SIZE;
+       }
+
+       if ((spnego_state->in_needed > 0) && (in.length == 0)) {
+               /*
+                * If we reach this, we know we got at least
+                * part of an asn1 message, getting 0 means
+                * the remote peer wants us to spin.
+                */
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       expected = spnego_state->in_needed - spnego_state->in_frag.length;
+       if (in.length > expected) {
+               /*
+                * we got more than expected
+                */
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (in.length == spnego_state->in_needed) {
+               /*
+                * if the in.length contains the full blob
+                * we are done.
+                *
+                * Note: this implies spnego_state->in_frag.length == 0,
+                *       but we do not need to check this explicitly
+                *       because we already know that we did not get
+                *       more than expected.
+                */
+               *full_in = in;
+               return NT_STATUS_OK;
+       }
+
+       ok = data_blob_append(spnego_state, &spnego_state->in_frag,
+                             in.data, in.length);
+       if (!ok) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (spnego_state->in_needed > spnego_state->in_frag.length) {
+               return NT_STATUS_MORE_PROCESSING_REQUIRED;
+       }
+
+       *full_in = spnego_state->in_frag;
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS gensec_spnego_update_out(struct gensec_security 
*gensec_security,
+                                        TALLOC_CTX *out_mem_ctx,
+                                        DATA_BLOB *_out)
+{
+       struct spnego_state *spnego_state = (struct spnego_state 
*)gensec_security->private_data;
+       size_t new_length;
+       uint8_t *buf;
+       DATA_BLOB out = data_blob_null;
+
+       *_out = data_blob_null;
+
+       if (spnego_state->out_frag.length == 0) {
+               return spnego_state->out_status;
+       }
+
+       /*
+        * There is still more data to be delivered
+        * to the remote peer.
+        */
+
+       if (spnego_state->out_frag.length <= spnego_state->out_max_length) {
+               /*
+                * Fast path, we can deliver everything
+                */
+
+               *_out = spnego_state->out_frag;
+               talloc_steal(out_mem_ctx, _out->data);
+               spnego_state->out_frag = data_blob_null;
+               return spnego_state->out_status;
+       }
+
+       out = spnego_state->out_frag;
+
+       /*
+        * copy the remaining bytes
+        */
+       spnego_state->out_frag = data_blob_talloc(spnego_state,
+                                       out.data + spnego_state->out_max_length,
+                                       out.length - 
spnego_state->out_max_length);
+       if (spnego_state->out_frag.data == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /*
+        * truncate the buffer
+        */
+       data_blob_realloc(spnego_state, &out, spnego_state->out_max_length);
+
+       talloc_steal(out_mem_ctx, out.data);
+       *_out = out;
+       return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static NTSTATUS gensec_spnego_update_wrapper(struct gensec_security 
*gensec_security,
+                                            TALLOC_CTX *out_mem_ctx,
+                                            struct tevent_context *ev,
+                                            const DATA_BLOB in, DATA_BLOB *out)
+{
+       struct spnego_state *spnego_state = (struct spnego_state 
*)gensec_security->private_data;
+       DATA_BLOB full_in = data_blob_null;
+       NTSTATUS status;
+
+       *out = data_blob_null;
+
+       if (spnego_state->out_frag.length > 0) {
+               if (in.length > 0) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               return gensec_spnego_update_out(gensec_security,
+                                               out_mem_ctx,
+                                               out);
+       }
+
+       status = gensec_spnego_update_in(gensec_security,
+                                        in, &full_in);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = gensec_spnego_update(gensec_security,
+                                     spnego_state, ev,
+                                     full_in,
+                                     &spnego_state->out_frag);
+       data_blob_free(&spnego_state->in_frag);
+       spnego_state->in_needed = 0;
+       if (!NT_STATUS_IS_OK(status) &&
+           !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               return status;
+       }
+
+       spnego_state->out_status = status;
+
+       return gensec_spnego_update_out(gensec_security,
+                                       out_mem_ctx,
+                                       out);
+}
+
 static void gensec_spnego_want_feature(struct gensec_security *gensec_security,
                                       uint32_t feature)
 {
@@ -1168,7 +1370,7 @@ static const struct gensec_security_ops 
gensec_spnego_security_ops = {
        .oid              = gensec_spnego_oids,
        .client_start     = gensec_spnego_client_start,
        .server_start     = gensec_spnego_server_start,
-       .update           = gensec_spnego_update,
+       .update           = gensec_spnego_update_wrapper,
        .seal_packet      = gensec_spnego_seal_packet,
        .sign_packet      = gensec_spnego_sign_packet,
        .sig_size         = gensec_spnego_sig_size,
diff --git a/source4/scripting/python/samba/tests/gensec.py 
b/source4/scripting/python/samba/tests/gensec.py
index ab38d18..d08022e 100644
--- a/source4/scripting/python/samba/tests/gensec.py
+++ b/source4/scripting/python/samba/tests/gensec.py
@@ -92,3 +92,57 @@ class GensecTests(samba.tests.TestCase):
         client_session_key = self.gensec_client.session_key()
         server_session_key = self.gensec_server.session_key()
         self.assertEqual(client_session_key, server_session_key)
+
+    def test_max_update_size(self):
+        """Test GENSEC by doing an exchange with ourselves using GSSAPI 
against a KDC"""
+
+        """Start up a client and server GENSEC instance to test things with"""
+
+        self.gensec_client = gensec.Security.start_client(self.settings)
+        self.gensec_client.set_credentials(self.get_credentials())
+        self.gensec_client.want_feature(gensec.FEATURE_SIGN)
+        self.gensec_client.set_max_update_size(5)
+        self.gensec_client.start_mech_by_name("spnego")
+
+        self.gensec_server = 
gensec.Security.start_server(settings=self.settings,
+                                                          
auth_context=auth.AuthContext(lp_ctx=self.lp_ctx))
+        creds = Credentials()
+        creds.guess(self.lp_ctx)
+        creds.set_machine_account(self.lp_ctx)
+        self.gensec_server.set_credentials(creds)
+        self.gensec_server.want_feature(gensec.FEATURE_SIGN)
+        self.gensec_server.set_max_update_size(5)
+        self.gensec_server.start_mech_by_name("spnego")
+
+        client_finished = False
+        server_finished = False
+        server_to_client = ""
+
+        """Run the actual call loop"""
+        i = 0
+        while client_finished == False or server_finished == False:
+            i += 1
+            if not client_finished:
+                print "running client gensec_update: %d: %r" % 
(len(server_to_client), server_to_client)
+                (client_finished, client_to_server) = 
self.gensec_client.update(server_to_client)
+            if not server_finished:
+                print "running server gensec_update: %d: %r" % 
(len(client_to_server), client_to_server)
+                (server_finished, server_to_client) = 
self.gensec_server.update(client_to_server)
+
+        """Here we expect a lot more than the typical 1 or 2 roundtrips"""
+        self.assertTrue(i > 10)
+
+        session_info = self.gensec_server.session_info()
+
+        test_string = "Hello Server"
+        test_wrapped = self.gensec_client.wrap(test_string)
+        test_unwrapped = self.gensec_server.unwrap(test_wrapped)
+        self.assertEqual(test_string, test_unwrapped)
+        test_string = "Hello Client"
+        test_wrapped = self.gensec_server.wrap(test_string)
+        test_unwrapped = self.gensec_client.unwrap(test_wrapped)
+        self.assertEqual(test_string, test_unwrapped)
+
+        client_session_key = self.gensec_client.session_key()
+        server_session_key = self.gensec_server.session_key()
+        self.assertEqual(client_session_key, server_session_key)


-- 
Samba Shared Repository

Reply via email to