[SCM] Samba Shared Repository - branch master updated
Stefan Metzmacher
metze at samba.org
Thu Jan 12 06:48:03 MST 2012
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 <metze at 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 <metze at samba.org>
Autobuild-Date: Thu Jan 12 14:47:05 CET 2012 on sn-devel-104
commit 891318ee4cc77077525e698d21398c6db82f0a1a
Author: Stefan Metzmacher <metze at 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 <metze at 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 <metze at 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
More information about the samba-cvs
mailing list