summaryrefslogtreecommitdiff
path: root/source4/libcli/auth/spnego.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli/auth/spnego.c')
-rw-r--r--source4/libcli/auth/spnego.c175
1 files changed, 115 insertions, 60 deletions
diff --git a/source4/libcli/auth/spnego.c b/source4/libcli/auth/spnego.c
index 321b13afdc..bb9d2504ac 100644
--- a/source4/libcli/auth/spnego.c
+++ b/source4/libcli/auth/spnego.c
@@ -27,7 +27,25 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_AUTH
-NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
+enum spnego_state_position {
+ SPNEGO_SERVER_START,
+ SPNEGO_CLIENT_GET_MECHS,
+ SPNEGO_CLIENT_SEND_MECHS,
+ SPNEGO_TARG,
+ SPNEGO_FALLBACK,
+ SPNEGO_DONE
+};
+
+struct spnego_state {
+ TALLOC_CTX *mem_ctx;
+ uint_t ref_count;
+ enum spnego_message_type expected_packet;
+ enum spnego_message_type state_position;
+ negResult_t result;
+ struct gensec_security *sub_sec_security;
+};
+
+static NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
{
struct spnego_state *spnego_state;
TALLOC_CTX *mem_ctx = talloc_init("gensec_spengo_client_start");
@@ -40,11 +58,11 @@ NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
return NT_STATUS_NO_MEMORY;
}
- spnego_state->role = SPNEGO_CLIENT;
spnego_state->expected_packet = SPNEGO_NEG_TOKEN_INIT;
spnego_state->state_position = SPNEGO_CLIENT_GET_MECHS;
spnego_state->result = SPNEGO_ACCEPT_INCOMPLETE;
spnego_state->mem_ctx = mem_ctx;
+ spnego_state->sub_sec_security = NULL;
gensec_security->private_data = spnego_state;
return NT_STATUS_OK;
@@ -53,9 +71,9 @@ NTSTATUS gensec_spnego_client_start(struct gensec_security *gensec_security)
/*
wrappers for the spnego_*() functions
*/
-NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
+static NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length, DATA_BLOB *sig)
{
struct spnego_state *spnego_state = gensec_security->private_data;
@@ -64,11 +82,11 @@ NTSTATUS gensec_spnego_unseal_packet(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
- return spnego_state->sub_sec_security.ops->unseal(&spnego_state->sub_sec_security,
- mem_ctx, data, length, sig);
+ return gensec_unseal_packet(spnego_state->sub_sec_security,
+ mem_ctx, data, length, sig);
}
-NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
const DATA_BLOB *sig)
@@ -81,11 +99,11 @@ NTSTATUS gensec_spnego_check_packet(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
- return spnego_state->sub_sec_security.ops->check_sig(&spnego_state->sub_sec_security,
- mem_ctx, data, length, sig);
+ return gensec_check_packet(spnego_state->sub_sec_security,
+ mem_ctx, data, length, sig);
}
-NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
uint8_t *data, size_t length,
DATA_BLOB *sig)
@@ -98,11 +116,11 @@ NTSTATUS gensec_spnego_seal_packet(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
- return spnego_state->sub_sec_security.ops->seal(&spnego_state->sub_sec_security,
- mem_ctx, data, length, sig);
+ return gensec_seal_packet(spnego_state->sub_sec_security,
+ mem_ctx, data, length, sig);
}
-NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
DATA_BLOB *sig)
@@ -114,11 +132,11 @@ NTSTATUS gensec_spnego_sign_packet(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
- return spnego_state->sub_sec_security.ops->sign(&spnego_state->sub_sec_security,
- mem_ctx, data, length, sig);
+ return gensec_sign_packet(spnego_state->sub_sec_security,
+ mem_ctx, data, length, sig);
}
-NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security,
+static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security,
DATA_BLOB *session_key)
{
struct spnego_state *spnego_state = gensec_security->private_data;
@@ -127,11 +145,11 @@ NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security,
return NT_STATUS_INVALID_PARAMETER;
}
- return spnego_state->sub_sec_security.ops->session_key(&spnego_state->sub_sec_security,
- session_key);
+ return gensec_session_key(spnego_state->sub_sec_security,
+ session_key);
}
-NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
+static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out)
{
struct spnego_state *spnego_state = gensec_security->private_data;
@@ -139,7 +157,6 @@ NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CT
DATA_BLOB unwrapped_out;
struct spnego_data spnego_out;
struct spnego_data spnego;
- const struct gensec_security_ops *op;
ssize_t len;
@@ -148,32 +165,38 @@ NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CT
}
if (spnego_state->state_position == SPNEGO_FALLBACK) {
- return spnego_state->sub_sec_security.ops->update(&spnego_state->sub_sec_security,
- out_mem_ctx, in, out);
+ return gensec_update(spnego_state->sub_sec_security,
+ out_mem_ctx, in, out);
}
len = spnego_read_data(in, &spnego);
if (len == -1 && spnego_state->state_position == SPNEGO_SERVER_START) {
int i;
- const struct gensec_security_ops **all_ops = gensec_security_all();
- for (i=0; all_ops[i]; i++) {
+ int num_ops;
+ const struct gensec_security_ops **all_ops = gensec_security_all(&num_ops);
+ for (i=0; i < num_ops; i++) {
NTSTATUS nt_status;
- op = all_ops[i];
- if (!op->oid) {
+ if (!all_ops[i]->oid) {
continue;
}
- nt_status = op->server_start(&spnego_state->sub_sec_security);
+ nt_status = gensec_server_start(&spnego_state->sub_sec_security);
if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+ nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
+ all_ops[i]->oid);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ gensec_end(&spnego_state->sub_sec_security);
continue;
}
- nt_status = op->update(&spnego_state->sub_sec_security,
- out_mem_ctx, in, out);
+ nt_status = gensec_update(spnego_state->sub_sec_security,
+ out_mem_ctx, in, out);
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
spnego_state->state_position = SPNEGO_FALLBACK;
return nt_status;
}
- op->end(&spnego_state->sub_sec_security);
+ gensec_end(&spnego_state->sub_sec_security);
}
DEBUG(1, ("Failed to parse SPENGO request\n"));
return NT_STATUS_INVALID_PARAMETER;
@@ -196,33 +219,33 @@ NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CT
NTSTATUS nt_status;
for (i=0; mechType[i]; i++) {
- op = gensec_security_by_oid(mechType[i]);
- if (!op) {
- continue;
+ nt_status = gensec_client_start(&spnego_state->sub_sec_security);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ break;
}
- spnego_state->sub_sec_security.ops = op;
- spnego_state->sub_sec_security.user = gensec_security->user;
-
- nt_status = op->client_start(&spnego_state->sub_sec_security);
+ nt_status = gensec_start_mech_by_oid(spnego_state->sub_sec_security,
+ mechType[i]);
if (!NT_STATUS_IS_OK(nt_status)) {
- op->end(&spnego_state->sub_sec_security);
+ gensec_end(&spnego_state->sub_sec_security);
continue;
}
+
if (i == 0) {
- nt_status = op->update(&spnego_state->sub_sec_security,
- out_mem_ctx,
- spnego.negTokenInit.mechToken,
- &unwrapped_out);
+ nt_status = gensec_update(spnego_state->sub_sec_security,
+ out_mem_ctx,
+ spnego.negTokenInit.mechToken,
+ &unwrapped_out);
} else {
/* only get the helping start blob for the first OID */
- nt_status = op->update(&spnego_state->sub_sec_security,
- out_mem_ctx,
- null_data_blob,
- &unwrapped_out);
+ nt_status = gensec_update(spnego_state->sub_sec_security,
+ out_mem_ctx,
+ null_data_blob,
+ &unwrapped_out);
}
if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- DEBUG(1, ("SPENGO(%s) NEG_TOKEN_INIT failed: %s\n", op->name, nt_errstr(nt_status)));
- op->end(&spnego_state->sub_sec_security);
+ DEBUG(1, ("SPENGO(%s) NEG_TOKEN_INIT failed: %s\n",
+ spnego_state->sub_sec_security->ops->name, nt_errstr(nt_status)));
+ gensec_end(&spnego_state->sub_sec_security);
} else {
break;
}
@@ -237,7 +260,7 @@ NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CT
}
/* compose reply */
- my_mechs[0] = op->oid;
+ my_mechs[0] = spnego_state->sub_sec_security->ops->oid;
spnego_out.type = SPNEGO_NEG_TOKEN_INIT;
spnego_out.negTokenInit.mechTypes = my_mechs;
@@ -261,12 +284,11 @@ NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CT
return NT_STATUS_ACCESS_DENIED;
}
- op = spnego_state->sub_sec_security.ops;
if (spnego.negTokenTarg.responseToken.length) {
- nt_status = op->update(&spnego_state->sub_sec_security,
- out_mem_ctx,
- spnego.negTokenTarg.responseToken,
- &unwrapped_out);
+ nt_status = gensec_update(spnego_state->sub_sec_security,
+ out_mem_ctx,
+ spnego.negTokenTarg.responseToken,
+ &unwrapped_out);
} else {
unwrapped_out = data_blob(NULL, 0);
nt_status = NT_STATUS_OK;
@@ -284,7 +306,9 @@ NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CT
/* compose reply */
spnego_out.type = SPNEGO_NEG_TOKEN_TARG;
spnego_out.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
- spnego_out.negTokenTarg.supportedMech = op->oid;
+ spnego_out.negTokenTarg.supportedMech
+ = spnego_state->sub_sec_security->ops->oid;
+;
spnego_out.negTokenTarg.responseToken = unwrapped_out;
spnego_out.negTokenTarg.mechListMIC = null_data_blob;
@@ -296,7 +320,9 @@ NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CT
} else if (NT_STATUS_IS_OK(nt_status)) {
spnego_state->state_position = SPNEGO_DONE;
} else {
- DEBUG(1, ("SPENGO(%s) login failed: %s\n", op->name, nt_errstr(nt_status)));
+ DEBUG(1, ("SPENGO(%s) login failed: %s\n",
+ spnego_state->sub_sec_security->ops->name,
+ nt_errstr(nt_status)));
return nt_status;
}
@@ -309,13 +335,42 @@ NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TALLOC_CT
}
}
-void gensec_spnego_end(struct gensec_security *gensec_security)
+static void gensec_spnego_end(struct gensec_security *gensec_security)
{
struct spnego_state *spnego_state = gensec_security->private_data;
-
- spnego_state->sub_sec_security.ops->end(&spnego_state->sub_sec_security);
+
+ if (spnego_state->sub_sec_security) {
+ gensec_end(&spnego_state->sub_sec_security);
+ }
talloc_destroy(spnego_state->mem_ctx);
gensec_security->private_data = NULL;
}
+
+static const struct gensec_security_ops gensec_spnego_security_ops = {
+ .name = "spnego",
+ .sasl_name = "GSS-SPNEGO",
+ .oid = OID_SPNEGO,
+ .client_start = gensec_spnego_client_start,
+ .update = gensec_spnego_update,
+ .seal_packet = gensec_spnego_seal_packet,
+ .sign_packet = gensec_spnego_sign_packet,
+ .check_packet = gensec_spnego_check_packet,
+ .unseal_packet = gensec_spnego_unseal_packet,
+ .session_key = gensec_spnego_session_key,
+ .end = gensec_spnego_end
+};
+
+NTSTATUS gensec_spengo_init(void)
+{
+ NTSTATUS ret;
+ ret = register_backend("gensec", &gensec_spnego_security_ops);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("Failed to register '%s' gensec backend!\n",
+ gensec_spnego_security_ops.name));
+ return ret;
+ }
+
+ return ret;
+}