summaryrefslogtreecommitdiff
path: root/source4/libcli/auth
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli/auth')
-rw-r--r--source4/libcli/auth/gensec.c405
-rw-r--r--source4/libcli/auth/gensec.h39
-rw-r--r--source4/libcli/auth/gensec_ntlmssp.c333
-rw-r--r--source4/libcli/auth/ntlmssp_sign.c2
-rw-r--r--source4/libcli/auth/spnego.c175
-rw-r--r--source4/libcli/auth/spnego.h25
6 files changed, 811 insertions, 168 deletions
diff --git a/source4/libcli/auth/gensec.c b/source4/libcli/auth/gensec.c
index 138c4af35c..f6d6db9e62 100644
--- a/source4/libcli/auth/gensec.c
+++ b/source4/libcli/auth/gensec.c
@@ -23,46 +23,14 @@
#include "includes.h"
-static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
- .name = "ntlmssp",
- .sasl_name = "NTLM",
- .auth_type = DCERPC_AUTH_TYPE_NTLMSSP,
- .oid = OID_NTLMSSP,
- .client_start = gensec_ntlmssp_client_start,
- .update = gensec_ntlmssp_update,
- .seal = gensec_ntlmssp_seal_packet,
- .sign = gensec_ntlmssp_sign_packet,
- .check_sig = gensec_ntlmssp_check_packet,
- .unseal = gensec_ntlmssp_unseal_packet,
- .session_key = gensec_ntlmssp_session_key,
- .end = gensec_ntlmssp_end
-};
-
-
-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 = gensec_spnego_seal_packet,
- .sign = gensec_spnego_sign_packet,
- .check_sig = gensec_spnego_check_packet,
- .unseal = gensec_spnego_unseal_packet,
- .session_key = gensec_spnego_session_key,
- .end = gensec_spnego_end
-};
-
-static const struct gensec_security_ops *generic_security_ops[] = {
- &gensec_ntlmssp_security_ops,
- &gensec_spnego_security_ops,
- NULL
-};
-
-const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
+/* the list of currently registered GENSEC backends */
+const static struct gensec_security_ops **generic_security_ops;
+static int num_backends;
+
+static const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
{
int i;
- for (i=0; generic_security_ops[i]; i++) {
+ for (i=0; i < num_backends; i++) {
if (generic_security_ops[i]->auth_type == auth_type) {
return generic_security_ops[i];
}
@@ -71,10 +39,10 @@ const struct gensec_security_ops *gensec_security_by_authtype(uint8_t auth_type)
return NULL;
}
-const struct gensec_security_ops *gensec_security_by_oid(const char *oid)
+static const struct gensec_security_ops *gensec_security_by_oid(const char *oid)
{
int i;
- for (i=0; generic_security_ops[i]; i++) {
+ for (i=0; i < num_backends; i++) {
if (generic_security_ops[i]->oid &&
(strcmp(generic_security_ops[i]->oid, oid) == 0)) {
return generic_security_ops[i];
@@ -84,10 +52,10 @@ const struct gensec_security_ops *gensec_security_by_oid(const char *oid)
return NULL;
}
-const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
+static const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_name)
{
int i;
- for (i=0; generic_security_ops[i]; i++) {
+ for (i=0; i < num_backends; i++) {
if (generic_security_ops[i]->sasl_name
&& (strcmp(generic_security_ops[i]->sasl_name, sasl_name) == 0)) {
return generic_security_ops[i];
@@ -97,8 +65,359 @@ const struct gensec_security_ops *gensec_security_by_sasl_name(const char *sasl_
return NULL;
}
-const struct gensec_security_ops **gensec_security_all(void)
+static const struct gensec_security_ops *gensec_security_by_name(const char *name)
+{
+ int i;
+ for (i=0; i < num_backends; i++) {
+ if (generic_security_ops[i]->name
+ && (strcmp(generic_security_ops[i]->name, name) == 0)) {
+ return generic_security_ops[i];
+ }
+ }
+
+ return NULL;
+}
+
+const struct gensec_security_ops **gensec_security_all(int *num_backends_out)
{
+ *num_backends_out = num_backends;
return generic_security_ops;
}
+static NTSTATUS gensec_start(struct gensec_security **gensec_security)
+{
+ TALLOC_CTX *mem_ctx;
+ /* awaiting a correct fix from metze */
+ if (!gensec_init()) {
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ mem_ctx = talloc_init("gensec_security struct");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*gensec_security) = talloc_p(mem_ctx, struct gensec_security);
+ if (!(*gensec_security)) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*gensec_security)->mem_ctx = mem_ctx;
+ (*gensec_security)->ops = NULL;
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS gensec_client_start(struct gensec_security **gensec_security)
+{
+ NTSTATUS status;
+ status = gensec_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ (*gensec_security)->gensec_role = GENSEC_CLIENT;
+ (*gensec_security)->password_callback = NULL;
+
+ ZERO_STRUCT((*gensec_security)->user);
+
+ return status;
+}
+
+NTSTATUS gensec_server_start(struct gensec_security **gensec_security)
+{
+ NTSTATUS status;
+ status = gensec_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ (*gensec_security)->gensec_role = GENSEC_SERVER;
+
+ return status;
+}
+
+static NTSTATUS gensec_start_mech(struct gensec_security *gensec_security)
+{
+ NTSTATUS status;
+ switch (gensec_security->gensec_role) {
+ case GENSEC_CLIENT:
+ if (gensec_security->ops->client_start) {
+ status = gensec_security->ops->client_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Faild to start GENSEC client mech %s: %s\n",
+ gensec_security->ops->name, nt_errstr(status)));
+ }
+ return status;
+ }
+ case GENSEC_SERVER:
+ if (gensec_security->ops->server_start) {
+ status = gensec_security->ops->server_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Faild to start GENSEC server mech %s: %s\n",
+ gensec_security->ops->name, nt_errstr(status)));
+ }
+ return status;
+ }
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+NTSTATUS gensec_start_mech_by_authtype(struct gensec_security *gensec_security,
+ uint8_t authtype)
+{
+ gensec_security->ops = gensec_security_by_authtype(authtype);
+ if (!gensec_security->ops) {
+ DEBUG(1, ("Could not find GENSEC backend for authtype=%d\n", (int)authtype));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ return gensec_start_mech(gensec_security);
+}
+
+NTSTATUS gensec_start_mech_by_oid(struct gensec_security *gensec_security,
+ const char *mech_oid)
+{
+ gensec_security->ops = gensec_security_by_oid(mech_oid);
+ if (!gensec_security->ops) {
+ DEBUG(1, ("Could not find GENSEC backend for oid=%s\n", mech_oid));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ return gensec_start_mech(gensec_security);
+}
+
+NTSTATUS gensec_start_mech_by_sasl_name(struct gensec_security *gensec_security,
+ const char *sasl_name)
+{
+ gensec_security->ops = gensec_security_by_sasl_name(sasl_name);
+ if (!gensec_security->ops) {
+ DEBUG(1, ("Could not find GENSEC backend for sasl_name=%s\n", sasl_name));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ return gensec_start_mech(gensec_security);
+}
+
+/*
+ wrappers for the gensec function pointers
+*/
+NTSTATUS gensec_unseal_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length, DATA_BLOB *sig)
+{
+ return gensec_security->ops->unseal_packet(gensec_security, mem_ctx, data, length, sig);
+}
+
+NTSTATUS gensec_check_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *data, size_t length,
+ const DATA_BLOB *sig)
+{
+ return gensec_security->ops->check_packet(gensec_security, mem_ctx, data, length, sig);
+}
+
+NTSTATUS gensec_seal_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ DATA_BLOB *sig)
+{
+ return gensec_security->ops->seal_packet(gensec_security, mem_ctx, data, length, sig);
+}
+
+NTSTATUS gensec_sign_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *data, size_t length,
+ DATA_BLOB *sig)
+{
+ return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, sig);
+}
+
+NTSTATUS gensec_session_key(struct gensec_security *gensec_security,
+ DATA_BLOB *session_key)
+{
+ return gensec_security->ops->session_key(gensec_security, session_key);
+}
+
+NTSTATUS gensec_session_info(struct gensec_security *gensec_security,
+ struct auth_session_info **session_info)
+{
+ return gensec_security->ops->session_info(gensec_security, session_info);
+}
+
+/**
+ * Next state function for the GENSEC state machine
+ *
+ * @param gensec_security GENSEC State
+ * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
+ * @param in The request, as a DATA_BLOB
+ * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
+ * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
+ * or NT_STATUS_OK if the user is authenticated.
+ */
+
+NTSTATUS gensec_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
+ const DATA_BLOB in, DATA_BLOB *out)
+{
+ return gensec_security->ops->update(gensec_security, out_mem_ctx, in, out);
+}
+
+void gensec_end(struct gensec_security **gensec_security)
+{
+ if ((*gensec_security)->ops) {
+ (*gensec_security)->ops->end(*gensec_security);
+ }
+ (*gensec_security)->private_data = NULL;
+ talloc_destroy((*gensec_security)->mem_ctx);
+
+ gensec_security = NULL;
+}
+
+/**
+ * Set a username on a GENSEC context - ensures it is talloc()ed
+ *
+ */
+
+NTSTATUS gensec_set_username(struct gensec_security *gensec_security, const char *user)
+{
+ gensec_security->user.name = talloc_strdup(gensec_security->mem_ctx, user);
+ if (!gensec_security->user.name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Set a domain on a GENSEC context - ensures it is talloc()ed
+ *
+ */
+
+NTSTATUS gensec_set_domain(struct gensec_security *gensec_security, const char *domain)
+{
+ gensec_security->user.domain = talloc_strdup(gensec_security->mem_ctx, domain);
+ if (!gensec_security->user.domain) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Set the password outright on GENSEC context - ensures it is talloc()ed, and that we will
+ * not do a callback
+ *
+ */
+
+NTSTATUS gensec_set_password(struct gensec_security *gensec_security,
+ const char *password)
+{
+ gensec_security->user.password = talloc_strdup(gensec_security->mem_ctx, password);
+ if (!gensec_security->user.password) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+/**
+ * Set a password callback, if the gensec module we use demands a password
+ */
+
+void gensec_set_password_callback(struct gensec_security *gensec_security,
+ gensec_password_callback callback, void *callback_private_data)
+{
+ gensec_security->password_callback = callback;
+ gensec_security->password_callback_private = callback_private_data;
+}
+
+/**
+ * Get (or call back for) a password.
+ */
+
+NTSTATUS gensec_get_password(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ char **password)
+{
+ if (gensec_security->user.password) {
+ *password = talloc_strdup(mem_ctx, gensec_security->user.password);
+ if (!*password) {
+ return NT_STATUS_NO_MEMORY;
+ } else {
+ return NT_STATUS_OK;
+ }
+ }
+ if (!gensec_security->password_callback) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ return gensec_security->password_callback(gensec_security, mem_ctx, password);
+}
+
+/*
+ register a GENSEC backend.
+
+ The 'name' can be later used by other backends to find the operations
+ structure for this backend.
+*/
+static NTSTATUS gensec_register(const void *_ops)
+{
+ const struct gensec_security_ops *ops = _ops;
+
+ if (gensec_security_by_name(ops->name) != NULL) {
+ /* its already registered! */
+ DEBUG(0,("GENSEC backend '%s' already registered\n",
+ ops->name));
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ generic_security_ops = Realloc(generic_security_ops, sizeof(generic_security_ops[0]) * (num_backends+1));
+ if (!generic_security_ops) {
+ smb_panic("out of memory in gensec_register");
+ }
+
+ generic_security_ops[num_backends] = ops;
+
+ num_backends++;
+
+ DEBUG(3,("GENSEC backend '%s' registered\n",
+ ops->name));
+
+ return NT_STATUS_OK;
+}
+
+/*
+ return the GENSEC interface version, and the size of some critical types
+ This can be used by backends to either detect compilation errors, or provide
+ multiple implementations for different smbd compilation options in one module
+*/
+const struct gensec_critical_sizes *gensec_interface_version(void)
+{
+ static const struct gensec_critical_sizes critical_sizes = {
+ GENSEC_INTERFACE_VERSION,
+ sizeof(struct gensec_security_ops),
+ sizeof(struct gensec_security),
+ };
+
+ return &critical_sizes;
+}
+
+/*
+ initialise the GENSEC subsystem
+*/
+BOOL gensec_init(void)
+{
+ static BOOL initialised;
+ NTSTATUS status;
+
+ /* this is *completly* the wrong way to do this */
+ if (initialised) {
+ return True;
+ }
+
+ status = register_subsystem("gensec", gensec_register);
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ /* FIXME: Perhaps panic if a basic backend, such as NTLMSSP, fails to initialise? */
+ gensec_ntlmssp_init();
+ gensec_spengo_init();
+ gensec_dcerpc_schannel_init();
+
+ initialised = True;
+ DEBUG(3,("GENSEC subsystem version %d initialised\n", GENSEC_INTERFACE_VERSION));
+ return True;
+}
diff --git a/source4/libcli/auth/gensec.h b/source4/libcli/auth/gensec.h
index 2a469e0f57..463b484a7f 100644
--- a/source4/libcli/auth/gensec.h
+++ b/source4/libcli/auth/gensec.h
@@ -27,6 +27,7 @@ struct gensec_user {
const char *domain;
const char *name;
const char *password;
+ char schan_session_key[16];
};
/* GENSEC mode */
enum gensec_role
@@ -38,27 +39,47 @@ enum gensec_role
struct gensec_security_ops {
const char *name;
const char *sasl_name;
- uint8 auth_type;
+ uint8 auth_type; /* 0 if not offered on DCE-RPC */
const char *oid; /* NULL if not offered by SPENGO */
NTSTATUS (*client_start)(struct gensec_security *gensec_security);
NTSTATUS (*server_start)(struct gensec_security *gensec_security);
NTSTATUS (*update)(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out);
- NTSTATUS (*seal)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
+ NTSTATUS (*seal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
uint8_t *data, size_t length, DATA_BLOB *sig);
- NTSTATUS (*sign)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
+ NTSTATUS (*sign_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
const uint8_t *data, size_t length, DATA_BLOB *sig);
- NTSTATUS (*check_sig)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, const DATA_BLOB *sig);
- NTSTATUS (*unseal)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig);
+ NTSTATUS (*check_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
+ const uint8_t *data, size_t length, const DATA_BLOB *sig);
+ NTSTATUS (*unseal_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
+ uint8_t *data, size_t length, DATA_BLOB *sig);
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);
void (*end)(struct gensec_security *gensec_security);
};
+typedef NTSTATUS (*gensec_password_callback)(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx,
+ char **password);
+
+#define GENSEC_INTERFACE_VERSION 0
+
struct gensec_security {
- struct gensec_user user;
- void *private_data;
+ TALLOC_CTX *mem_ctx;
+ gensec_password_callback password_callback;
+ void *password_callback_private;
const struct gensec_security_ops *ops;
+ void *private_data;
+ struct gensec_user user;
+ enum gensec_role gensec_role;
};
+/* this structure is used by backends to determine the size of some critical types */
+struct gensec_critical_sizes {
+ int interface_version;
+ int sizeof_gensec_security_ops;
+ int sizeof_gensec_security;
+};
+
+
+
diff --git a/source4/libcli/auth/gensec_ntlmssp.c b/source4/libcli/auth/gensec_ntlmssp.c
index f7e9dddd2f..9f7c4c6f86 100644
--- a/source4/libcli/auth/gensec_ntlmssp.c
+++ b/source4/libcli/auth/gensec_ntlmssp.c
@@ -23,33 +23,220 @@
#include "includes.h"
+struct gensec_ntlmssp_state {
+ TALLOC_CTX *mem_ctx;
+ struct auth_context *auth_context;
+ struct auth_serversupplied_info *server_info;
+ struct ntlmssp_state *ntlmssp_state;
+};
-NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
+
+/**
+ * Return the challenge as determined by the authentication subsystem
+ * @return an 8 byte random challenge
+ */
+
+static const uint8_t *auth_ntlmssp_get_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
+
+ return gensec_ntlmssp_state->auth_context->get_ntlm_challenge(gensec_ntlmssp_state->auth_context);
+}
+
+/**
+ * Some authentication methods 'fix' the challenge, so we may not be able to set it
+ *
+ * @return If the effective challenge used by the auth subsystem may be modified
+ */
+static BOOL auth_ntlmssp_may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
+
+ return gensec_ntlmssp_state->auth_context->challenge_may_be_modified;
+}
+
+/**
+ * NTLM2 authentication modifies the effective challenge,
+ * @param challenge The new challenge value
+ */
+static NTSTATUS auth_ntlmssp_set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
+ struct auth_context *auth_context = gensec_ntlmssp_state->auth_context;
+
+ SMB_ASSERT(challenge->length == 8);
+
+ auth_context->challenge = data_blob_talloc(auth_context->mem_ctx,
+ challenge->data, challenge->length);
+
+ auth_context->challenge_set_by = "NTLMSSP callback (NTLM2)";
+
+ DEBUG(5, ("auth_context challenge set by %s\n", auth_context->challenge_set_by));
+ DEBUG(5, ("challenge is: \n"));
+ dump_data(5, (const char *)auth_context->challenge.data, auth_context->challenge.length);
+ return NT_STATUS_OK;
+}
+
+/**
+ * Check the password on an NTLMSSP login.
+ *
+ * Return the session keys used on the connection.
+ */
+
+static NTSTATUS auth_ntlmssp_check_password(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = ntlmssp_state->auth_context;
+ struct auth_usersupplied_info *user_info = NULL;
+ NTSTATUS nt_status;
+
+#if 0
+ /* the client has given us its machine name (which we otherwise would not get on port 445).
+ we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+
+ set_remote_machine_name(gensec_ntlmssp_state->ntlmssp_state->workstation, True);
+
+ /* setup the string used by %U */
+ /* sub_set_smb_name checks for weird internally */
+ sub_set_smb_name(gensec_ntlmssp_state->ntlmssp_state->user);
+
+ reload_services(True);
+
+#endif
+ nt_status = make_user_info_map(&user_info,
+ gensec_ntlmssp_state->ntlmssp_state->user,
+ gensec_ntlmssp_state->ntlmssp_state->domain,
+ gensec_ntlmssp_state->ntlmssp_state->workstation,
+ gensec_ntlmssp_state->ntlmssp_state->lm_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->lm_resp : NULL,
+ gensec_ntlmssp_state->ntlmssp_state->nt_resp.data ? &gensec_ntlmssp_state->ntlmssp_state->nt_resp : NULL,
+ NULL, NULL, NULL,
+ True);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ nt_status = gensec_ntlmssp_state->auth_context->check_ntlm_password(gensec_ntlmssp_state->auth_context,
+ user_info, &gensec_ntlmssp_state->server_info);
+
+ free_user_info(&user_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+ if (gensec_ntlmssp_state->server_info->user_session_key.length) {
+ DEBUG(10, ("Got NT session key of length %u\n", gensec_ntlmssp_state->server_info->user_session_key.length));
+ *user_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
+ gensec_ntlmssp_state->server_info->user_session_key.data,
+ gensec_ntlmssp_state->server_info->user_session_key.length);
+ }
+ if (gensec_ntlmssp_state->server_info->lm_session_key.length) {
+ DEBUG(10, ("Got LM session key of length %u\n", gensec_ntlmssp_state->server_info->lm_session_key.length));
+ *lm_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
+ gensec_ntlmssp_state->server_info->lm_session_key.data,
+ gensec_ntlmssp_state->server_info->lm_session_key.length);
+ }
+ return nt_status;
+}
+
+static NTSTATUS gensec_ntlmssp_start(struct gensec_security *gensec_security)
+{
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state;
+
+ TALLOC_CTX *mem_ctx = talloc_init("gensec_ntlmssp");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gensec_ntlmssp_state = talloc_p(mem_ctx, struct gensec_ntlmssp_state);
+ if (!gensec_ntlmssp_state) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ gensec_ntlmssp_state->mem_ctx = mem_ctx;
+ gensec_ntlmssp_state->ntlmssp_state = NULL;
+ gensec_ntlmssp_state->auth_context = NULL;
+ gensec_ntlmssp_state->server_info = NULL;
+
+ gensec_security->private_data = gensec_ntlmssp_state;
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security)
+{
+ NTSTATUS nt_status;
+ NTSTATUS status;
+ struct ntlmssp_state *ntlmssp_state;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state;
+
+ status = gensec_ntlmssp_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ gensec_ntlmssp_state = gensec_security->private_data;
+
+ if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(&gensec_ntlmssp_state->ntlmssp_state))) {
+ return nt_status;
+ }
+
+ ntlmssp_state = gensec_ntlmssp_state->ntlmssp_state;
+ if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&gensec_ntlmssp_state->auth_context))) {
+ return nt_status;
+ }
+
+ ntlmssp_state->auth_context = gensec_ntlmssp_state;
+ ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
+ ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
+ ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
+ ntlmssp_state->check_password = auth_ntlmssp_check_password;
+ ntlmssp_state->server_role = lp_server_role();
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
{
- struct ntlmssp_state *ntlmssp_state = NULL;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state;
+ char *password = NULL;
+
NTSTATUS status;
+ status = gensec_ntlmssp_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
- status = ntlmssp_client_start(&ntlmssp_state);
+ gensec_ntlmssp_state = gensec_security->private_data;
+ status = ntlmssp_client_start(&gensec_ntlmssp_state->ntlmssp_state);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = ntlmssp_set_domain(ntlmssp_state, gensec_security->user.domain);
+ status = ntlmssp_set_domain(gensec_ntlmssp_state->ntlmssp_state,
+ gensec_security->user.domain);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = ntlmssp_set_username(ntlmssp_state, gensec_security->user.name);
+ status = ntlmssp_set_username(gensec_ntlmssp_state->ntlmssp_state,
+ gensec_security->user.name);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- status = ntlmssp_set_password(ntlmssp_state, gensec_security->user.password);
+ status = gensec_get_password(gensec_security, gensec_ntlmssp_state->mem_ctx, &password);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
-
- gensec_security->private_data = ntlmssp_state;
+
+ if (password) {
+ status = ntlmssp_set_password(gensec_ntlmssp_state->ntlmssp_state,
+ password);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
+ gensec_security->private_data = gensec_ntlmssp_state;
return status;
}
@@ -57,66 +244,154 @@ NTSTATUS gensec_ntlmssp_client_start(struct gensec_security *gensec_security)
/*
wrappers for the ntlmssp_*() functions
*/
-NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_unseal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
uint8_t *data, size_t length, DATA_BLOB *sig)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_unseal_packet(ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_unseal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
}
-NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_check_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
const DATA_BLOB *sig)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_check_packet(ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_check_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
}
-NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_seal_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
uint8_t *data, size_t length,
DATA_BLOB *sig)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_seal_packet(ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_seal_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
}
-NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_sign_packet(struct gensec_security *gensec_security,
TALLOC_CTX *mem_ctx,
const uint8_t *data, size_t length,
DATA_BLOB *sig)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_sign_packet(ntlmssp_state, mem_ctx, data, length, sig);
+ return ntlmssp_sign_packet(gensec_ntlmssp_state->ntlmssp_state, mem_ctx, data, length, sig);
}
-NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security,
+static NTSTATUS gensec_ntlmssp_session_key(struct gensec_security *gensec_security,
DATA_BLOB *session_key)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- return ntlmssp_session_key(ntlmssp_state, session_key);
+ return ntlmssp_session_key(gensec_ntlmssp_state->ntlmssp_state, session_key);
}
-NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
+/**
+ * Next state function for the wrapped NTLMSSP state machine
+ *
+ * @param gensec_ntlmssp_state NTLMSSP State
+ * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
+ * @param in The request, as a DATA_BLOB
+ * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
+ * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent,
+ * or NT_STATUS_OK if the user is authenticated.
+ */
+
+static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
const DATA_BLOB in, DATA_BLOB *out)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
+
+ return ntlmssp_update(gensec_ntlmssp_state->ntlmssp_state, out_mem_ctx, in, out);
+}
+
+/**
+ * Return the credentials of a logged on user, including session keys
+ * etc.
+ *
+ * Only valid after a successful authentication
+ *
+ * May only be called once per authentication.
+ *
+ */
+
+static NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security,
+ struct auth_session_info **session_info)
+{
+ NTSTATUS nt_status;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
+ nt_status = make_session_info(gensec_ntlmssp_state->server_info, session_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ return nt_status;
+ }
+
+ /* the session_info owns this now */
+ gensec_ntlmssp_state->server_info = NULL;
+
+ (*session_info)->session_key = data_blob_talloc((*session_info)->mem_ctx,
+ gensec_ntlmssp_state->ntlmssp_state->session_key.data,
+ gensec_ntlmssp_state->ntlmssp_state->session_key.length);
+
+ (*session_info)->workstation = talloc_strdup((*session_info)->mem_ctx,
+ gensec_ntlmssp_state->ntlmssp_state->workstation);
- return ntlmssp_update(ntlmssp_state, out_mem_ctx, in, out);
+ return NT_STATUS_OK;
}
-void gensec_ntlmssp_end(struct gensec_security *gensec_security)
+static void gensec_ntlmssp_end(struct gensec_security *gensec_security)
{
- struct ntlmssp_state *ntlmssp_state = gensec_security->private_data;
+ struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data;
- ntlmssp_end(&ntlmssp_state);
+ if (gensec_ntlmssp_state->ntlmssp_state) {
+ ntlmssp_end(&gensec_ntlmssp_state->ntlmssp_state);
+ }
+ if (gensec_ntlmssp_state->auth_context) {
+ free_auth_context(&gensec_ntlmssp_state->auth_context);
+ }
+ if (gensec_ntlmssp_state->server_info) {
+ free_server_info(&gensec_ntlmssp_state->server_info);
+ }
+ talloc_destroy(gensec_ntlmssp_state->mem_ctx);
gensec_security->private_data = NULL;
}
+
+static const struct gensec_security_ops gensec_ntlmssp_security_ops = {
+ .name = "ntlmssp",
+ .sasl_name = "NTLM",
+ .auth_type = DCERPC_AUTH_TYPE_NTLMSSP,
+ .oid = OID_NTLMSSP,
+ .client_start = gensec_ntlmssp_client_start,
+ .server_start = gensec_ntlmssp_server_start,
+ .update = gensec_ntlmssp_update,
+ .seal_packet = gensec_ntlmssp_seal_packet,
+ .sign_packet = gensec_ntlmssp_sign_packet,
+ .check_packet = gensec_ntlmssp_check_packet,
+ .unseal_packet = gensec_ntlmssp_unseal_packet,
+ .session_key = gensec_ntlmssp_session_key,
+ .session_info = gensec_ntlmssp_session_info,
+ .end = gensec_ntlmssp_end
+};
+
+
+NTSTATUS gensec_ntlmssp_init(void)
+{
+ NTSTATUS ret;
+ ret = register_backend("gensec", &gensec_ntlmssp_security_ops);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("Failed to register '%s' gensec backend!\n",
+ gensec_ntlmssp_security_ops.name));
+ return ret;
+ }
+
+ /* ugly cludge, but we need the auth subsystem for this to work */
+ auth_init();
+
+ return ret;
+}
diff --git a/source4/libcli/auth/ntlmssp_sign.c b/source4/libcli/auth/ntlmssp_sign.c
index d680da9495..80ce1cccc0 100644
--- a/source4/libcli/auth/ntlmssp_sign.c
+++ b/source4/libcli/auth/ntlmssp_sign.c
@@ -160,8 +160,6 @@ static NTSTATUS ntlmssp_make_packet_signature(struct ntlmssp_state *ntlmssp_stat
return NT_STATUS_NO_MEMORY;
}
- dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
- sizeof(ntlmssp_state->ntlmssp_hash));
NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data+4, sig->length-4);
}
dump_data_pw("calculated ntlmssp signature\n", sig->data, sig->length);
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;
+}
diff --git a/source4/libcli/auth/spnego.h b/source4/libcli/auth/spnego.h
index 890301314b..60ef4c1d36 100644
--- a/source4/libcli/auth/spnego.h
+++ b/source4/libcli/auth/spnego.h
@@ -23,12 +23,6 @@
#ifndef SAMBA_SPNEGO_H
#define SAMBA_SPNEGO_H
-/* SPNEGO mode */
-enum spnego_role
-{
- SPNEGO_SERVER,
- SPNEGO_CLIENT
-};
#define SPNEGO_DELEG_FLAG 0x01
#define SPNEGO_MUTUAL_FLAG 0x02
@@ -70,23 +64,4 @@ enum spnego_message_type {
SPNEGO_NEG_TOKEN_TARG = 1,
};
-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_role role;
- enum spnego_message_type expected_packet;
- enum spnego_message_type state_position;
- negResult_t result;
- struct gensec_security sub_sec_security;
-};
-
#endif