summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/auth/auth.h16
-rw-r--r--source4/auth/auth_ntlmssp.c238
-rw-r--r--source4/auth/auth_util.c17
-rw-r--r--source4/auth/config.m42
-rw-r--r--source4/auth/config.mk3
-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
-rw-r--r--source4/libcli/config.m43
-rw-r--r--source4/librpc/ndr/ndr.c2
-rw-r--r--source4/librpc/rpc/dcerpc.c58
-rw-r--r--source4/librpc/rpc/dcerpc.h2
-rw-r--r--source4/librpc/rpc/dcerpc_auth.c27
-rw-r--r--source4/librpc/rpc/dcerpc_ntlm.c41
-rw-r--r--source4/librpc/rpc/dcerpc_schannel.c378
-rw-r--r--source4/librpc/rpc/dcerpc_util.c6
-rw-r--r--source4/ntvfs/ipc/vfs_ipc.c6
-rw-r--r--source4/rpc_server/config.m41
-rw-r--r--source4/rpc_server/config.mk20
-rw-r--r--source4/rpc_server/dcerpc_server.c20
-rw-r--r--source4/rpc_server/dcerpc_server.h23
-rw-r--r--source4/rpc_server/dcesrv_auth.c130
-rw-r--r--source4/rpc_server/dcesrv_crypto.c148
-rw-r--r--source4/rpc_server/dcesrv_crypto_ntlmssp.c159
-rw-r--r--source4/rpc_server/dcesrv_crypto_schannel.c239
-rw-r--r--source4/rpc_server/netlogon/dcerpc_netlogon.c14
-rw-r--r--source4/rpc_server/samr/samr_password.c11
-rw-r--r--source4/smb_server/password.c2
-rw-r--r--source4/torture/rpc/schannel.c5
-rw-r--r--source4/utils/ntlm_auth.c416
33 files changed, 1569 insertions, 1397 deletions
diff --git a/source4/auth/auth.h b/source4/auth/auth.h
index c20b8dbf6f..0c8f71d859 100644
--- a/source4/auth/auth.h
+++ b/source4/auth/auth.h
@@ -96,6 +96,8 @@ struct auth_serversupplied_info
struct auth_session_info
{
TALLOC_CTX *mem_ctx;
+
+ int refcount;
/* NT group information taken from the info3 structure */
NT_USER_TOKEN *nt_user_token;
@@ -117,7 +119,8 @@ struct auth_context {
BOOL challenge_may_be_modified;
struct auth_methods *challenge_set_method;
- /* What order are the various methods in? Try to stop it changing under us */
+
+ /* methods, in the order they should be called */
struct auth_methods *auth_method_list;
TALLOC_CTX *mem_ctx;
@@ -165,15 +168,6 @@ struct auth_init_function_entry {
struct auth_init_function_entry *prev, *next;
};
-struct auth_ntlmssp_state
-{
- TALLOC_CTX *mem_ctx;
- struct auth_context *auth_context;
- struct auth_serversupplied_info *server_info;
- struct ntlmssp_state *ntlmssp_state;
-};
-
-#define auth_ops __XXX_ERROR_BLA
struct auth_operations {
/* the name of the backend */
const char *name;
@@ -188,11 +182,9 @@ struct auth_critical_sizes {
int sizeof_auth_operations;
int sizeof_auth_methods;
int sizeof_auth_context;
- int sizeof_auth_ntlmssp_state;
int sizeof_auth_usersupplied_info;
int sizeof_auth_serversupplied_info;
int sizeof_auth_str;
- int sizeof_auth_unistr;
};
#endif /* _SMBAUTH_H_ */
diff --git a/source4/auth/auth_ntlmssp.c b/source4/auth/auth_ntlmssp.c
deleted file mode 100644
index 183363a363..0000000000
--- a/source4/auth/auth_ntlmssp.c
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 3.0
- handle NLTMSSP, server side
-
- Copyright (C) Andrew Tridgell 2001
- Copyright (C) Andrew Bartlett 2001-2003
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "includes.h"
-
-/**
- * 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 auth_ntlmssp_state *auth_ntlmssp_state = ntlmssp_state->auth_context;
-
- return auth_ntlmssp_state->auth_context->get_ntlm_challenge(auth_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 auth_ntlmssp_state *auth_ntlmssp_state = ntlmssp_state->auth_context;
-
- return auth_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 auth_ntlmssp_state *auth_ntlmssp_state = ntlmssp_state->auth_context;
- struct auth_context *auth_context = auth_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 auth_ntlmssp_state *auth_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(auth_ntlmssp_state->ntlmssp_state->workstation, True);
-
- /* setup the string used by %U */
- /* sub_set_smb_name checks for weird internally */
- sub_set_smb_name(auth_ntlmssp_state->ntlmssp_state->user);
-
- reload_services(True);
-
-#endif
- nt_status = make_user_info_map(&user_info,
- auth_ntlmssp_state->ntlmssp_state->user,
- auth_ntlmssp_state->ntlmssp_state->domain,
- auth_ntlmssp_state->ntlmssp_state->workstation,
- auth_ntlmssp_state->ntlmssp_state->lm_resp.data ? &auth_ntlmssp_state->ntlmssp_state->lm_resp : NULL,
- auth_ntlmssp_state->ntlmssp_state->nt_resp.data ? &auth_ntlmssp_state->ntlmssp_state->nt_resp : NULL,
- NULL, NULL, NULL,
- True);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- nt_status = auth_ntlmssp_state->auth_context->check_ntlm_password(auth_ntlmssp_state->auth_context,
- user_info, &auth_ntlmssp_state->server_info);
-
- free_user_info(&user_info);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
- if (auth_ntlmssp_state->server_info->user_session_key.length) {
- DEBUG(10, ("Got NT session key of length %u\n", auth_ntlmssp_state->server_info->user_session_key.length));
- *user_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
- auth_ntlmssp_state->server_info->user_session_key.data,
- auth_ntlmssp_state->server_info->user_session_key.length);
- }
- if (auth_ntlmssp_state->server_info->lm_session_key.length) {
- DEBUG(10, ("Got LM session key of length %u\n", auth_ntlmssp_state->server_info->lm_session_key.length));
- *lm_session_key = data_blob_talloc(ntlmssp_state->mem_ctx,
- auth_ntlmssp_state->server_info->lm_session_key.data,
- auth_ntlmssp_state->server_info->lm_session_key.length);
- }
- return nt_status;
-}
-
-NTSTATUS auth_ntlmssp_start(struct auth_ntlmssp_state **auth_ntlmssp_state)
-{
- NTSTATUS nt_status;
- TALLOC_CTX *mem_ctx;
-
- mem_ctx = talloc_init("AUTH NTLMSSP context");
-
- *auth_ntlmssp_state = talloc_zero(mem_ctx, sizeof(**auth_ntlmssp_state));
- if (!*auth_ntlmssp_state) {
- DEBUG(0,("auth_ntlmssp_start: talloc failed!\n"));
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
- }
-
- ZERO_STRUCTP(*auth_ntlmssp_state);
-
- (*auth_ntlmssp_state)->mem_ctx = mem_ctx;
-
- if (!NT_STATUS_IS_OK(nt_status = ntlmssp_server_start(&(*auth_ntlmssp_state)->ntlmssp_state))) {
- return nt_status;
- }
-
- if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*auth_ntlmssp_state)->auth_context))) {
- return nt_status;
- }
-
- (*auth_ntlmssp_state)->ntlmssp_state->auth_context = (*auth_ntlmssp_state);
- (*auth_ntlmssp_state)->ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge;
- (*auth_ntlmssp_state)->ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge;
- (*auth_ntlmssp_state)->ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge;
- (*auth_ntlmssp_state)->ntlmssp_state->check_password = auth_ntlmssp_check_password;
- (*auth_ntlmssp_state)->ntlmssp_state->server_role = lp_server_role();
-
- return NT_STATUS_OK;
-}
-
-void auth_ntlmssp_end(struct auth_ntlmssp_state **auth_ntlmssp_state)
-{
- TALLOC_CTX *mem_ctx = (*auth_ntlmssp_state)->mem_ctx;
-
- if ((*auth_ntlmssp_state)->ntlmssp_state) {
- ntlmssp_end(&(*auth_ntlmssp_state)->ntlmssp_state);
- }
- if ((*auth_ntlmssp_state)->auth_context) {
- free_auth_context(&(*auth_ntlmssp_state)->auth_context);
- }
- if ((*auth_ntlmssp_state)->server_info) {
- free_server_info(&(*auth_ntlmssp_state)->server_info);
- }
- talloc_destroy(mem_ctx);
- *auth_ntlmssp_state = NULL;
-}
-
-
-/**
- * Next state function for the wrapped NTLMSSP state machine
- *
- * @param auth_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.
- */
-
-NTSTATUS auth_ntlmssp_update(struct auth_ntlmssp_state *auth_ntlmssp_state,
- TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB in, DATA_BLOB *out)
-{
- return ntlmssp_update(auth_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.
- *
- */
-
-NTSTATUS auth_ntlmssp_get_session_info(struct auth_ntlmssp_state *auth_ntlmssp_state,
- struct auth_session_info **session_info)
-{
- NTSTATUS nt_status;
- nt_status = make_session_info(auth_ntlmssp_state->server_info, session_info);
-
- if (!NT_STATUS_IS_OK(nt_status)) {
- return nt_status;
- }
-
- /* the session_info owns this now */
- auth_ntlmssp_state->server_info = NULL;
-
- (*session_info)->session_key = data_blob_talloc((*session_info)->mem_ctx,
- auth_ntlmssp_state->ntlmssp_state->session_key.data,
- auth_ntlmssp_state->ntlmssp_state->session_key.length);
-
- (*session_info)->workstation = talloc_strdup((*session_info)->mem_ctx,
- auth_ntlmssp_state->ntlmssp_state->workstation);
-
- return NT_STATUS_OK;
-}
diff --git a/source4/auth/auth_util.c b/source4/auth/auth_util.c
index 097f504538..06947999b3 100644
--- a/source4/auth/auth_util.c
+++ b/source4/auth/auth_util.c
@@ -590,6 +590,7 @@ NTSTATUS make_session_info(struct auth_serversupplied_info *server_info,
return NT_STATUS_NO_MEMORY;
}
+ (*session_info)->refcount = 1;
(*session_info)->mem_ctx = server_info->mem_ctx;
server_info->mem_ctx = NULL; /* make sure not to accidentily destory it,
and this information is now constant */
@@ -611,6 +612,22 @@ NTSTATUS make_session_info(struct auth_serversupplied_info *server_info,
return nt_status;
}
+/***************************************************************************
+ Clear out a server_info struct that has been allocated
+***************************************************************************/
+
+void free_session_info(struct auth_session_info **session_info)
+{
+ DEBUG(5,("attempting to free a session_info structure\n"));
+ if (!*session_info) {
+ (*session_info)->refcount--;
+ if ((*session_info)->refcount <= 0) {
+ talloc_destroy((*session_info)->mem_ctx);
+ }
+ }
+ *session_info = NULL;
+}
+
/**
* Squash an NT_STATUS in line with security requirements.
* In an attempt to avoid giving the whole game away when users
diff --git a/source4/auth/config.m4 b/source4/auth/config.m4
index 01e4574d94..3c4f86ecea 100644
--- a/source4/auth/config.m4
+++ b/source4/auth/config.m4
@@ -3,4 +3,4 @@ dnl # AUTH Server subsystem
SMB_MODULE_MK(auth_sam,AUTH,STATIC,auth/config.mk)
SMB_MODULE_MK(auth_builtin,AUTH,STATIC,auth/config.mk)
-SMB_SUBSYSTEM_MK(AUTH,auth/config.mk)
+SMB_SUBSYSTEM_MK(AUTH,auth/config.mk,[],[],[SAMDB])
diff --git a/source4/auth/config.mk b/source4/auth/config.mk
index c9b47e745b..b4082cb9e5 100644
--- a/source4/auth/config.mk
+++ b/source4/auth/config.mk
@@ -5,6 +5,8 @@
[MODULE::auth_sam]
INIT_OBJ_FILES = \
auth/auth_sam.o
+REQUIRED_SUBSYSTEMS = \
+ SAMDB
# End MODULE auth_sam
#######################
@@ -22,7 +24,6 @@ INIT_OBJ_FILES = \
INIT_OBJ_FILES = \
auth/auth.o
ADD_OBJ_FILES = \
- auth/auth_ntlmssp.o \
auth/auth_util.o \
auth/pampass.o \
auth/pass_check.o
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
diff --git a/source4/libcli/config.m4 b/source4/libcli/config.m4
index 992f84005d..9e19499003 100644
--- a/source4/libcli/config.m4
+++ b/source4/libcli/config.m4
@@ -54,7 +54,8 @@ SMB_SUBSYSTEM(LIBCLI_AUTH,[],
libcli/auth/kerberos_verify.o
libcli/auth/clikrb5.o
libcli/auth/gensec.o
- libcli/auth/gensec_ntlmssp.o])
+ libcli/auth/gensec_ntlmssp.o],
+ [], [AUTH SCHANNELDB])
SMB_SUBSYSTEM(LIBCLI_NMB,[],
[libcli/unexpected.o
diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c
index 6b89cb4cd2..d2e85f6aec 100644
--- a/source4/librpc/ndr/ndr.c
+++ b/source4/librpc/ndr/ndr.c
@@ -741,7 +741,7 @@ NTSTATUS ndr_pull_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, uint32_t leve
/*
pull a struct from a blob using NDR
*/
-NTSTATUS ndr_pull_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+NTSTATUS ndr_pull_struct_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
NTSTATUS (*fn)(struct ndr_pull *, int , void *))
{
struct ndr_pull *ndr;
diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c
index 5d5469da7f..8afc556528 100644
--- a/source4/librpc/rpc/dcerpc.c
+++ b/source4/librpc/rpc/dcerpc.c
@@ -42,9 +42,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(void)
p->mem_ctx = mem_ctx;
p->call_id = 1;
p->security_state.auth_info = NULL;
- ZERO_STRUCT(p->security_state.generic_state.user);
- p->security_state.generic_state.private_data = NULL;
- p->security_state.generic_state.ops = NULL;
+ p->security_state.generic_state = NULL;
p->binding_string = NULL;
p->flags = 0;
p->srv_max_xmit_frag = 0;
@@ -60,8 +58,8 @@ void dcerpc_pipe_close(struct dcerpc_pipe *p)
if (!p) return;
p->reference_count--;
if (p->reference_count <= 0) {
- if (p->security_state.generic_state.ops) {
- p->security_state.generic_state.ops->end(&p->security_state.generic_state);
+ if (p->security_state.generic_state) {
+ gensec_end(&p->security_state.generic_state);
}
p->transport.shutdown_pipe(p);
talloc_destroy(p->mem_ctx);
@@ -132,7 +130,7 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
DATA_BLOB auth_blob;
/* non-signed packets are simpler */
- if (!p->security_state.auth_info || !p->security_state.generic_state.ops) {
+ if (!p->security_state.auth_info || !p->security_state.generic_state) {
return dcerpc_pull(blob, mem_ctx, pkt);
}
@@ -186,21 +184,19 @@ static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
/* check signature or unseal the packet */
switch (p->security_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
- status = p->security_state
- .generic_state.ops->unseal(&p->security_state.generic_state,
- mem_ctx,
- pkt->u.response.stub_and_verifier.data,
- pkt->u.response.stub_and_verifier.length,
- &auth.credentials);
+ status = gensec_unseal_packet(p->security_state.generic_state,
+ mem_ctx,
+ pkt->u.response.stub_and_verifier.data,
+ pkt->u.response.stub_and_verifier.length,
+ &auth.credentials);
break;
-
+
case DCERPC_AUTH_LEVEL_INTEGRITY:
- status = p->security_state
- .generic_state.ops->check_sig(&p->security_state.generic_state,
- mem_ctx,
- pkt->u.response.stub_and_verifier.data,
- pkt->u.response.stub_and_verifier.length,
- &auth.credentials);
+ status = gensec_check_packet(p->security_state.generic_state,
+ mem_ctx,
+ pkt->u.response.stub_and_verifier.data,
+ pkt->u.response.stub_and_verifier.length,
+ &auth.credentials);
break;
case DCERPC_AUTH_LEVEL_NONE:
@@ -232,7 +228,7 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
struct ndr_push *ndr;
/* non-signed packets are simpler */
- if (!p->security_state.auth_info || !p->security_state.generic_state.ops) {
+ if (!p->security_state.auth_info || !p->security_state.generic_state) {
return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
}
@@ -257,21 +253,19 @@ static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
/* sign or seal the packet */
switch (p->security_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
- status = p->security_state
- .generic_state.ops->seal(&p->security_state.generic_state,
- mem_ctx,
- ndr->data + DCERPC_REQUEST_LENGTH,
- ndr->offset - DCERPC_REQUEST_LENGTH,
- &p->security_state.auth_info->credentials);
+ status = gensec_seal_packet(p->security_state.generic_state,
+ mem_ctx,
+ ndr->data + DCERPC_REQUEST_LENGTH,
+ ndr->offset - DCERPC_REQUEST_LENGTH,
+ &p->security_state.auth_info->credentials);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
- status = p->security_state
- .generic_state.ops->sign(&p->security_state.generic_state,
- mem_ctx,
- ndr->data + DCERPC_REQUEST_LENGTH,
- ndr->offset - DCERPC_REQUEST_LENGTH,
- &p->security_state.auth_info->credentials);
+ status = gensec_sign_packet(p->security_state.generic_state,
+ mem_ctx,
+ ndr->data + DCERPC_REQUEST_LENGTH,
+ ndr->offset - DCERPC_REQUEST_LENGTH,
+ &p->security_state.auth_info->credentials);
break;
case DCERPC_AUTH_LEVEL_NONE:
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index a513b72a16..4f50b261e2 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -28,7 +28,7 @@ enum dcerpc_transport_t {NCACN_NP, NCACN_IP_TCP};
struct dcerpc_pipe;
struct dcerpc_security {
struct dcerpc_auth *auth_info;
- struct gensec_security generic_state;
+ struct gensec_security *generic_state;
};
struct dcerpc_pipe {
diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index e5fad1f082..07601e4724 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -56,15 +56,14 @@ NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type,
return NT_STATUS_NO_MEMORY;
}
- if (!p->security_state.generic_state.ops) {
-
- p->security_state.generic_state.ops = gensec_security_by_authtype(auth_type);
- if (!p->security_state.generic_state.ops) {
- status = NT_STATUS_INVALID_PARAMETER;
- goto done;
+ if (!p->security_state.generic_state) {
+ status = gensec_client_start(&p->security_state.generic_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- status = p->security_state.generic_state.ops->client_start(&p->security_state.generic_state);
+ status = gensec_start_mech_by_authtype(p->security_state.generic_state, auth_type);
+
if (!NT_STATUS_IS_OK(status)) {
return status;
}
@@ -90,10 +89,10 @@ NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type,
p->security_state.auth_info->auth_level = DCERPC_AUTH_LEVEL_NONE;
}
- status = p->security_state.generic_state.ops->update(&p->security_state.generic_state, mem_ctx,
- p->security_state.auth_info->credentials,
- &credentials);
-
+ status = gensec_update(p->security_state.generic_state, mem_ctx,
+ p->security_state.auth_info->credentials,
+ &credentials);
+
if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
goto done;
}
@@ -105,9 +104,9 @@ NTSTATUS dcerpc_bind_auth(struct dcerpc_pipe *p, uint8_t auth_type,
goto done;
}
- status = p->security_state.generic_state.ops->update(&p->security_state.generic_state, mem_ctx,
- p->security_state.auth_info->credentials,
- &credentials);
+ status = gensec_update(p->security_state.generic_state, mem_ctx,
+ p->security_state.auth_info->credentials,
+ &credentials);
if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
goto done;
diff --git a/source4/librpc/rpc/dcerpc_ntlm.c b/source4/librpc/rpc/dcerpc_ntlm.c
index 398e3f1aa3..0f02669eb1 100644
--- a/source4/librpc/rpc/dcerpc_ntlm.c
+++ b/source4/librpc/rpc/dcerpc_ntlm.c
@@ -33,12 +33,47 @@ NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p,
{
NTSTATUS status;
- p->security_state.generic_state.user.domain = domain;
- p->security_state.generic_state.user.name = username;
- p->security_state.generic_state.user.password = password;
+ status = gensec_client_start(&p->security_state.generic_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start GENSEC client mode: %s\n", nt_errstr(status)));
+ return status;
+ }
+ status = gensec_set_domain(p->security_state.generic_state, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
+ domain, nt_errstr(status)));
+ return status;
+ }
+
+ status = gensec_set_username(p->security_state.generic_state, username);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
+ username, nt_errstr(status)));
+ return status;
+ }
+
+ status = gensec_set_password(p->security_state.generic_state, password);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ status = gensec_start_mech_by_authtype(p->security_state.generic_state, DCERPC_AUTH_TYPE_NTLMSSP);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client NTLMSSP mechanism: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_NTLMSSP,
uuid, version);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(2, ("Failed to bind to pipe with NTLMSSP: %s\n", nt_errstr(status)));
+ return status;
+ }
+
return status;
}
diff --git a/source4/librpc/rpc/dcerpc_schannel.c b/source4/librpc/rpc/dcerpc_schannel.c
index b43dd0788a..ffe60b1bae 100644
--- a/source4/librpc/rpc/dcerpc_schannel.c
+++ b/source4/librpc/rpc/dcerpc_schannel.c
@@ -22,21 +22,24 @@
#include "includes.h"
-#define DCERPC_SCHANNEL_STATE_START 0
-#define DCERPC_SCHANNEL_STATE_UPDATE_1 1
+enum schannel_position {
+ DCERPC_SCHANNEL_STATE_START = 0,
+ DCERPC_SCHANNEL_STATE_UPDATE_1
+};
struct dcerpc_schannel_state {
TALLOC_CTX *mem_ctx;
- uint8_t state;
- struct schannel_bind bind_schannel;
+ enum schannel_position state;
struct schannel_state *schannel_state;
+ struct creds_CredentialState creds;
+ char *account_name;
};
static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
- const char *domain,
- const char *username,
- const char *password,
- int chan_type,
+ const char *domain,
+ const char *username,
+ const char *password,
+ int chan_type,
uint8_t new_session_key[16]);
/*
@@ -45,39 +48,39 @@ static NTSTATUS dcerpc_schannel_key(struct dcerpc_pipe *p,
These will become static again, when we get dynamic registration, and
decrpc_schannel_security_ops come back here.
*/
-static NTSTATUS dcerpc_schannel_unseal(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
+static NTSTATUS dcerpc_schannel_unseal_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length, DATA_BLOB *sig)
{
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
-
+
return schannel_unseal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig);
}
-static NTSTATUS dcerpc_schannel_check_sig(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const uint8_t *data, size_t length,
- const DATA_BLOB *sig)
+static NTSTATUS dcerpc_schannel_check_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *data, size_t length,
+ const DATA_BLOB *sig)
{
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
return schannel_check_packet(dce_schan_state->schannel_state, data, length, sig);
}
-static NTSTATUS dcerpc_schannel_seal(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- uint8_t *data, size_t length,
- DATA_BLOB *sig)
+static NTSTATUS dcerpc_schannel_seal_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ uint8_t *data, size_t length,
+ DATA_BLOB *sig)
{
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
return schannel_seal_packet(dce_schan_state->schannel_state, mem_ctx, data, length, sig);
}
-static NTSTATUS dcerpc_schannel_sign(struct gensec_security *gensec_security,
- TALLOC_CTX *mem_ctx,
- const uint8_t *data, size_t length,
- DATA_BLOB *sig)
+static NTSTATUS dcerpc_schannel_sign_packet(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ const uint8_t *data, size_t length,
+ DATA_BLOB *sig)
{
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
@@ -85,47 +88,233 @@ static NTSTATUS dcerpc_schannel_sign(struct gensec_security *gensec_security,
}
static NTSTATUS dcerpc_schannel_session_key(struct gensec_security *gensec_security,
- DATA_BLOB *session_key)
+ DATA_BLOB *session_key)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS dcerpc_schannel_update(struct gensec_security *gensec_security, TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB in, DATA_BLOB *out)
+ const DATA_BLOB in, DATA_BLOB *out)
{
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
NTSTATUS status;
struct schannel_bind bind_schannel;
+ struct schannel_bind_ack bind_schannel_ack;
+ const char *account_name;
+
+ switch (gensec_security->gensec_role) {
+ case GENSEC_CLIENT:
+ if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) {
+ /* we could parse the bind ack, but we don't know what it is yet */
+ return NT_STATUS_OK;
+ }
+
+ bind_schannel.unknown1 = 0;
+#if 0
+ /* to support this we'd need to have access to the full domain name */
+ bind_schannel.bind_type = 23;
+ bind_schannel.u.info23.domain = gensec_security->user.domain;
+ bind_schannel.u.info23.account_name = gensec_security->user.name;
+ bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(out_mem_ctx, fulldomainname);
+ bind_schannel.u.info23.workstation = str_format_nbt_domain(out_mem_ctx, gensec_security->user.name);
+#else
+ bind_schannel.bind_type = 3;
+ bind_schannel.u.info3.domain = gensec_security->user.domain;
+ bind_schannel.u.info3.account_name = gensec_security->user.name;
+#endif
+
+ status = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel,
+ (ndr_push_flags_fn_t)ndr_push_schannel_bind);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not create schannel bind: %s\n",
+ nt_errstr(status)));
+ return status;
+ }
+
+ dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ case GENSEC_SERVER:
+
+ if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) {
+ /* no third leg on this protocol */
+ return NT_STATUS_OK;
+ }
+
+ /* parse the schannel startup blob */
+ status = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel,
+ (ndr_pull_flags_fn_t)ndr_pull_schannel_bind);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ if (bind_schannel.bind_type == 23) {
+ account_name = bind_schannel.u.info23.account_name;
+ } else {
+ account_name = bind_schannel.u.info3.account_name;
+ }
+
+ /* pull the session key for this client */
+ status = schannel_fetch_session_key(out_mem_ctx, account_name, &dce_schan_state->creds);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not find session key for attempted schannel connection on %s: %s\n",
+ account_name, nt_errstr(status)));
+ return status;
+ }
+
+ dce_schan_state->account_name = talloc_strdup(dce_schan_state->mem_ctx, account_name);
+
+ /* start up the schannel server code */
+ status = schannel_start(&dce_schan_state->schannel_state,
+ dce_schan_state->creds.session_key, False);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not initialise schannel state for account %s: %s\n",
+ account_name, nt_errstr(status)));
+ return status;
+ }
+
+ bind_schannel_ack.unknown1 = 1;
+ bind_schannel_ack.unknown2 = 0;
+ bind_schannel_ack.unknown3 = 0x6c0000;
+
+ status = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack,
+ (ndr_push_flags_fn_t)ndr_push_schannel_bind_ack);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not return schannel bind ack for account %s: %s\n",
+ account_name, nt_errstr(status)));
+ return status;
+ }
+
+ dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1;
+
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+ return NT_STATUS_INVALID_PARAMETER;
+}
+
+/**
+ * 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.
+ *
+ */
+
+NTSTATUS dcerpc_schannel_session_info(struct gensec_security *gensec_security,
+ struct auth_session_info **session_info)
+{
+ struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
+ TALLOC_CTX *mem_ctx;
+ mem_ctx = talloc_init("dcerpc_schannel_start");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
- if (dce_schan_state->state != DCERPC_SCHANNEL_STATE_START) {
- return NT_STATUS_OK;
+ (*session_info) = talloc_p(mem_ctx, struct auth_session_info);
+ if (*session_info == NULL) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
}
- dce_schan_state->state = DCERPC_SCHANNEL_STATE_UPDATE_1;
+ ZERO_STRUCTP(*session_info);
+ (*session_info)->mem_ctx = mem_ctx;
+ (*session_info)->refcount = 1;
+
+ (*session_info)->workstation = talloc_strdup(mem_ctx, dce_schan_state->account_name);
+ if ((*session_info)->workstation == NULL) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+
+/**
+ * Return the struct creds_CredentialState.
+ *
+ * Make sure not to call this unless gensec is using schannel...
+ */
+
+NTSTATUS dcerpc_schannel_creds(struct gensec_security *gensec_security,
+ TALLOC_CTX *mem_ctx,
+ struct creds_CredentialState **creds)
+{
+ struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
- bind_schannel.unknown1 = 0;
-#if 0
- /* to support this we'd need to have access to the full domain name */
- bind_schannel.bind_type = 23;
- bind_schannel.u.info23.domain = gensec_security->user.domain;
- bind_schannel.u.info23.account_name = gensec_security->user.name;
- bind_schannel.u.info23.dnsdomain = str_format_nbt_domain(dce_schan_state->mem_ctx, fulldomainname);
- bind_schannel.u.info23.workstation = str_format_nbt_domain(dce_schan_state->mem_ctx, gensec_security->user.name);
-#else
- bind_schannel.bind_type = 3;
- bind_schannel.u.info3.domain = gensec_security->user.domain;
- bind_schannel.u.info3.account_name = gensec_security->user.name;
-#endif
+ *creds = talloc_p(mem_ctx, struct creds_CredentialState);
+ if (*creds) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ **creds = dce_schan_state->creds;
+ return NT_STATUS_OK;
+}
+
+
+static NTSTATUS dcerpc_schannel_start(struct gensec_security *gensec_security)
+{
+ struct dcerpc_schannel_state *dce_schan_state;
+ TALLOC_CTX *mem_ctx;
+ mem_ctx = talloc_init("dcerpc_schannel_start");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dce_schan_state = talloc_p(mem_ctx, struct dcerpc_schannel_state);
+ if (!dce_schan_state) {
+ talloc_destroy(mem_ctx);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ dce_schan_state->mem_ctx = mem_ctx;
+ dce_schan_state->state = DCERPC_SCHANNEL_STATE_START;
+
+
+ gensec_security->private_data = dce_schan_state;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS dcerpc_schannel_server_start(struct gensec_security *gensec_security)
+{
+ NTSTATUS status;
+
+ status = dcerpc_schannel_start(gensec_security);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS dcerpc_schannel_client_start(struct gensec_security *gensec_security)
+{
+ NTSTATUS status;
+ struct dcerpc_schannel_state *dce_schan_state;
+
+ status = dcerpc_schannel_start(gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ dce_schan_state = gensec_security->private_data;
- status = ndr_push_struct_blob(out, dce_schan_state->mem_ctx, &bind_schannel,
- (ndr_push_flags_fn_t)ndr_push_schannel_bind);
+ status = schannel_start(&dce_schan_state->schannel_state,
+ gensec_security->user.schan_session_key,
+ True);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start schannel client\n"));
return status;
}
- return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ dump_data_pw("session key:\n", dce_schan_state->schannel_state->session_key, 16);
+ return NT_STATUS_OK;
}
+/*
+ end crypto state
+*/
static void dcerpc_schannel_end(struct gensec_security *gensec_security)
{
struct dcerpc_schannel_state *dce_schan_state = gensec_security->private_data;
@@ -138,18 +327,6 @@ static void dcerpc_schannel_end(struct gensec_security *gensec_security)
}
-static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops = {
- .name = "dcerpc_schannel",
- .auth_type = DCERPC_AUTH_TYPE_SCHANNEL,
- .update = dcerpc_schannel_update,
- .seal = dcerpc_schannel_seal,
- .sign = dcerpc_schannel_sign,
- .check_sig = dcerpc_schannel_check_sig,
- .unseal = dcerpc_schannel_unseal,
- .session_key = dcerpc_schannel_session_key,
- .end = dcerpc_schannel_end
-};
-
/*
get a schannel key using a netlogon challenge on a secondary pipe
*/
@@ -251,11 +428,13 @@ NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
const char *password)
{
NTSTATUS status;
- struct dcerpc_schannel_state *dce_schan_state;
- TALLOC_CTX *mem_ctx;
- uint8_t session_key[16];
int chan_type = 0;
+ status = gensec_client_start(&p->security_state.generic_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
if (p->flags & DCERPC_SCHANNEL_BDC) {
chan_type = SEC_CHAN_BDC;
} else if (p->flags & DCERPC_SCHANNEL_WORKSTATION) {
@@ -265,44 +444,75 @@ NTSTATUS dcerpc_bind_auth_schannel(struct dcerpc_pipe *p,
}
status = dcerpc_schannel_key(p, domain,
- username,
- password,
- chan_type, session_key);
+ username,
+ password,
+ chan_type,
+ p->security_state.generic_state->user.schan_session_key);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to fetch schannel session key: %s\n", nt_errstr(status)));
+ gensec_end(&p->security_state.generic_state);
return status;
}
-
- mem_ctx = talloc_init("dcerpc_schannel_start");
- if (!mem_ctx) {
- return NT_STATUS_NO_MEMORY;
+
+ status = gensec_set_username(p->security_state.generic_state, username);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to set schannel username to %s: %s\n", username, nt_errstr(status)));
+ gensec_end(&p->security_state.generic_state);
+ return status;
+ }
+
+ status = gensec_set_domain(p->security_state.generic_state, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to set schannel domain to %s: %s\n", domain, nt_errstr(status)));
+ gensec_end(&p->security_state.generic_state);
+ return status;
}
+
+ status = gensec_start_mech_by_authtype(p->security_state.generic_state, DCERPC_AUTH_TYPE_SCHANNEL);
- dce_schan_state = talloc_p(mem_ctx, struct dcerpc_schannel_state);
- if (!dce_schan_state) {
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start SCHANNEL GENSEC backend: %s\n", nt_errstr(status)));
+ gensec_end(&p->security_state.generic_state);
+ return status;
}
- dce_schan_state->mem_ctx = mem_ctx;
+ status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL,
+ uuid, version);
- status = schannel_start(&dce_schan_state->schannel_state, session_key, True);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to bind to pipe with SCHANNEL: %s\n", nt_errstr(status)));
+ gensec_end(&p->security_state.generic_state);
return status;
}
- dce_schan_state->state = DCERPC_SCHANNEL_STATE_START;
-
- p->security_state.generic_state.user.domain = domain;
- p->security_state.generic_state.user.name = username;
- p->security_state.generic_state.user.password = password;
+ return NT_STATUS_OK;
+}
- p->security_state.generic_state.ops = &gensec_dcerpc_schannel_security_ops;
- p->security_state.generic_state.private_data = dce_schan_state;
- dump_data_pw("session key:\n", dce_schan_state->schannel_state->session_key, 16);
+static const struct gensec_security_ops gensec_dcerpc_schannel_security_ops = {
+ .name = "dcerpc_schannel",
+ .auth_type = DCERPC_AUTH_TYPE_SCHANNEL,
+ .client_start = dcerpc_schannel_client_start,
+ .server_start = dcerpc_schannel_server_start,
+ .update = dcerpc_schannel_update,
+ .seal_packet = dcerpc_schannel_seal_packet,
+ .sign_packet = dcerpc_schannel_sign_packet,
+ .check_packet = dcerpc_schannel_check_packet,
+ .unseal_packet = dcerpc_schannel_unseal_packet,
+ .session_key = dcerpc_schannel_session_key,
+ .session_info = dcerpc_schannel_session_info,
+ .end = dcerpc_schannel_end
+};
- status = dcerpc_bind_auth(p, DCERPC_AUTH_TYPE_SCHANNEL,
- uuid, version);
+NTSTATUS gensec_dcerpc_schannel_init(void)
+{
+ NTSTATUS ret;
+ ret = register_backend("gensec", &gensec_dcerpc_schannel_security_ops);
+ if (!NT_STATUS_IS_OK(ret)) {
+ DEBUG(0,("Failed to register '%s' gensec backend!\n",
+ gensec_dcerpc_schannel_security_ops.name));
+ return ret;
+ }
- return status;
+ return ret;
}
diff --git a/source4/librpc/rpc/dcerpc_util.c b/source4/librpc/rpc/dcerpc_util.c
index 82aa5aa1f3..d5cd2ab6fe 100644
--- a/source4/librpc/rpc/dcerpc_util.c
+++ b/source4/librpc/rpc/dcerpc_util.c
@@ -503,6 +503,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_np(struct dcerpc_pipe **p,
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("Failed to bind to uuid %s - %s\n", pipe_uuid, nt_errstr(status)));
dcerpc_pipe_close(*p);
+ *p = NULL;
return status;
}
@@ -569,6 +570,7 @@ static NTSTATUS dcerpc_pipe_connect_ncacn_ip_tcp(struct dcerpc_pipe **p,
DEBUG(0,("Failed to bind to uuid %s - %s\n",
pipe_uuid, nt_errstr(status)));
dcerpc_pipe_close(*p);
+ *p = NULL;
return status;
}
@@ -697,8 +699,8 @@ NTSTATUS dcerpc_fetch_session_key(struct dcerpc_pipe *p,
{
struct cli_tree *tree;
- if (p->security_state.generic_state.ops) {
- return p->security_state.generic_state.ops->session_key(&p->security_state.generic_state, session_key);
+ if (p->security_state.generic_state) {
+ return gensec_session_key(p->security_state.generic_state, session_key);
}
tree = dcerpc_smb_tree(p);
diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c
index cf8b49ebb8..f6a0015f1d 100644
--- a/source4/ntvfs/ipc/vfs_ipc.c
+++ b/source4/ntvfs/ipc/vfs_ipc.c
@@ -243,9 +243,9 @@ static NTSTATUS ipc_open_generic(struct smbsrv_request *req, const char *fname,
/* tell the RPC layer the session_info */
if (req->user_ctx->vuser) {
- /*
- * TODO: we need to reference count the entire session_info
- */
+ /* The session info is refcount-increased in the
+ dcesrv_endpoint_search_connect() function */
+
session_info = req->user_ctx->vuser->session_info;
}
diff --git a/source4/rpc_server/config.m4 b/source4/rpc_server/config.m4
index 3f64cdcf4b..73cae66456 100644
--- a/source4/rpc_server/config.m4
+++ b/source4/rpc_server/config.m4
@@ -3,6 +3,7 @@ dnl # DCERPC Server subsystem
SMB_SUBSYSTEM_MK(DCERPC_COMMON,rpc_server/config.mk)
SMB_SUBSYSTEM_MK(SAMDB,rpc_server/config.mk)
+SMB_SUBSYSTEM_MK(SCHANNELDB,rpc_server/config.mk)
SMB_MODULE_MK(dcerpc_rpcecho,DCERPC,STATIC,rpc_server/config.mk)
SMB_MODULE_MK(dcerpc_epmapper,DCERPC,STATIC,rpc_server/config.mk)
diff --git a/source4/rpc_server/config.mk b/source4/rpc_server/config.mk
index 9d9f12d9aa..dbe8b8344e 100644
--- a/source4/rpc_server/config.mk
+++ b/source4/rpc_server/config.mk
@@ -19,12 +19,22 @@ INIT_OBJ_FILES = \
ADD_OBJ_FILES = \
rpc_server/samr/samr_utils.o
REQUIRED_SUBSYSTEMS = \
+ DCERPC_COMMON \
LIBLDB
#
# End SUBSYSTEM SAMDB
################################################
################################################
+# Start SUBSYSTEM SCHANNELDB
+[SUBSYSTEM::SCHANNELDB]
+INIT_OBJ_FILES = \
+ rpc_server/netlogon/schannel_state.o
+#
+# End SUBSYSTEM SCHANNELDB
+################################################
+
+################################################
# Start MODULE dcerpc_rpcecho
[MODULE::dcerpc_rpcecho]
INIT_OBJ_FILES = \
@@ -98,10 +108,9 @@ REQUIRED_SUBSYSTEMS = \
[MODULE::dcerpc_netlogon]
INIT_OBJ_FILES = \
rpc_server/netlogon/dcerpc_netlogon.o
-ADD_OBJ_FILES = \
- rpc_server/netlogon/schannel_state.o
REQUIRED_SUBSYSTEMS = \
- DCERPC_COMMON
+ DCERPC_COMMON \
+ SCHANNELDB
# End MODULE dcerpc_netlogon
################################################
@@ -135,10 +144,9 @@ INIT_OBJ_FILES = \
ADD_OBJ_FILES = \
rpc_server/dcerpc_tcp.o \
rpc_server/dcesrv_auth.o \
- rpc_server/dcesrv_crypto.o \
- rpc_server/dcesrv_crypto_ntlmssp.o \
- rpc_server/dcesrv_crypto_schannel.o \
rpc_server/handles.o
+REQUIRED_SUBSYSTEMS = \
+ LIBCLI_AUTH
#
# End SUBSYSTEM DCERPC
################################################
diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c
index 90ebaf285c..e5c4c120a5 100644
--- a/source4/rpc_server/dcerpc_server.c
+++ b/source4/rpc_server/dcerpc_server.c
@@ -146,9 +146,9 @@ static struct dcesrv_call_state *dcesrv_find_call(struct dcesrv_connection *dce_
register an interface on an endpoint
*/
NTSTATUS dcesrv_interface_register(struct dcesrv_context *dce_ctx,
- const char *ep_name,
- const struct dcesrv_interface *iface,
- const struct security_descriptor *sd)
+ const char *ep_name,
+ const struct dcesrv_interface *iface,
+ const struct security_descriptor *sd)
{
struct dcesrv_ep_description ep_description;
struct dcesrv_endpoint *ep;
@@ -269,8 +269,7 @@ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx,
(*p)->handles = NULL;
(*p)->partial_input = data_blob(NULL, 0);
(*p)->auth_state.auth_info = NULL;
- (*p)->auth_state.crypto_ctx.private_data = NULL;
- (*p)->auth_state.crypto_ctx.ops = NULL;
+ (*p)->auth_state.gensec_security = NULL;
(*p)->auth_state.session_info = NULL;
return NT_STATUS_OK;
@@ -298,6 +297,7 @@ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx,
return status;
}
+ session_info->refcount++;
(*dce_conn_p)->auth_state.session_info = session_info;
/* TODO: check security descriptor of the endpoint here
@@ -323,8 +323,12 @@ void dcesrv_endpoint_disconnect(struct dcesrv_connection *p)
dcesrv_handle_destroy(p, p->handles);
}
- if (p->auth_state.crypto_ctx.ops) {
- p->auth_state.crypto_ctx.ops->end(&p->auth_state);
+ if (p->auth_state.gensec_security) {
+ gensec_end(&p->auth_state.gensec_security);
+ }
+
+ if (p->auth_state.session_info) {
+ free_session_info(&p->auth_state.session_info);
}
talloc_destroy(p->mem_ctx);
@@ -1027,7 +1031,7 @@ static int num_ep_servers;
The 'type' is used to specify whether this is for a disk, printer or IPC$ share
*/
-static NTSTATUS dcerpc_register_ep_server(void *_ep_server)
+static NTSTATUS dcerpc_register_ep_server(const void *_ep_server)
{
const struct dcesrv_endpoint_server *ep_server = _ep_server;
diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h
index 3ad768b32e..b1754dd4a3 100644
--- a/source4/rpc_server/dcerpc_server.h
+++ b/source4/rpc_server/dcerpc_server.h
@@ -94,31 +94,10 @@ struct dcesrv_handle {
void (*destroy)(struct dcesrv_connection *, struct dcesrv_handle *);
};
-struct dcesrv_crypto_ops {
- const char *name;
- uint8 auth_type;
- NTSTATUS (*start)(struct dcesrv_auth *auth, DATA_BLOB *auth_blob);
- NTSTATUS (*update)(struct dcesrv_auth *auth, TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB in, DATA_BLOB *out);
- NTSTATUS (*seal)(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig);
- NTSTATUS (*sign)(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, DATA_BLOB *sig);
- NTSTATUS (*check_sig)(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, const DATA_BLOB *sig);
- NTSTATUS (*unseal)(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig);
- NTSTATUS (*session_key)(struct dcesrv_auth *auth, uint8_t session_key[16]);
- void (*end)(struct dcesrv_auth *auth);
-};
-
/* hold the authentication state information */
struct dcesrv_auth {
struct dcerpc_auth *auth_info;
- struct {
- void *private_data;
- const struct dcesrv_crypto_ops *ops;
- } crypto_ctx;
+ struct gensec_security *gensec_security;
struct auth_session_info *session_info;
};
diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c
index 26053b47b9..84a5460d68 100644
--- a/source4/rpc_server/dcesrv_auth.c
+++ b/source4/rpc_server/dcesrv_auth.c
@@ -4,6 +4,7 @@
server side dcerpc authentication code
Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Stefan (metze) Metzmacher 2004
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,6 +24,48 @@
#include "includes.h"
/*
+ startup the cryptographic side of an authenticated dcerpc server
+*/
+NTSTATUS dcesrv_crypto_select_type(struct dcesrv_connection *dce_conn,
+ struct dcesrv_auth *auth)
+{
+ NTSTATUS status;
+ if (auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
+ auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
+ DEBUG(2,("auth_level %d not supported in dcesrv auth\n",
+ auth->auth_info->auth_level));
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (auth->gensec_security != NULL) {
+ /* TODO:
+ * this this function should not be called
+ * twice per dcesrv_connection!
+ *
+ * so we need to find out the right
+ * dcerpc error to return
+ */
+ }
+
+ status = gensec_server_start(&auth->gensec_security);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
+ return status;
+ }
+
+ status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start GENSEC mech-specific server code (%d): %s\n",
+ (int)auth->auth_info->auth_type,
+ nt_errstr(status)));
+ return status;
+ }
+
+ return status;
+}
+
+/*
parse any auth information from a dcerpc bind request
return False if we can't handle the auth request for some
reason (in which case we send a bind_nak)
@@ -56,40 +99,43 @@ BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
return False;
}
- status = dcesrv_crypto_start(&dce_conn->auth_state, &dce_conn->auth_state.auth_info->credentials);
- if (!NT_STATUS_IS_OK(status)) {
- return False;
- }
-
return True;
}
/*
- add any auth information needed in a bind ack
+ add any auth information needed in a bind ack, and process the authentication
+ information found in the bind.
*/
BOOL dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct dcerpc_packet *pkt)
{
struct dcesrv_connection *dce_conn = call->conn;
NTSTATUS status;
- if (!call->conn->auth_state.crypto_ctx.ops) {
+ if (!call->conn->auth_state.gensec_security) {
return True;
}
- status = dcesrv_crypto_update(&dce_conn->auth_state,
- call->mem_ctx,
- dce_conn->auth_state.auth_info->credentials,
- &dce_conn->auth_state.auth_info->credentials);
- if (!NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = gensec_update(dce_conn->auth_state.gensec_security,
+ call->mem_ctx,
+ dce_conn->auth_state.auth_info->credentials,
+ &dce_conn->auth_state.auth_info->credentials);
+
+ if (NT_STATUS_IS_OK(status)) {
+ status = gensec_session_info(dce_conn->auth_state.gensec_security,
+ &dce_conn->auth_state.session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
+ return False;
+ }
+ return True;
+ } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ dce_conn->auth_state.auth_info->auth_pad_length = 0;
+ dce_conn->auth_state.auth_info->auth_reserved = 0;
+ return True;
+ } else {
DEBUG(2, ("Failed to start dcesrv auth negotiate: %s\n", nt_errstr(status)));
return False;
}
-
- dce_conn->auth_state.auth_info->auth_pad_length = 0;
- dce_conn->auth_state.auth_info->auth_reserved = 0;
-
- return True;
}
@@ -103,7 +149,7 @@ BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
NTSTATUS status;
if (!dce_conn->auth_state.auth_info ||
- !dce_conn->auth_state.crypto_ctx.ops ||
+ !dce_conn->auth_state.gensec_security ||
pkt->u.auth.auth_info.length == 0) {
return False;
}
@@ -116,11 +162,19 @@ BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
return False;
}
- status = dcesrv_crypto_update(&dce_conn->auth_state,
- call->mem_ctx,
- dce_conn->auth_state.auth_info->credentials,
- &dce_conn->auth_state.auth_info->credentials);
- if (!NT_STATUS_IS_OK(status)) {
+ status = gensec_update(dce_conn->auth_state.gensec_security,
+ call->mem_ctx,
+ dce_conn->auth_state.auth_info->credentials,
+ &dce_conn->auth_state.auth_info->credentials);
+ if (NT_STATUS_IS_OK(status)) {
+ status = gensec_session_info(dce_conn->auth_state.gensec_security,
+ &dce_conn->auth_state.session_info);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
+ return False;
+ }
+ return True;
+ } else {
DEBUG(4, ("dcesrv_auth_auth3: failed to authenticate: %s\n",
nt_errstr(status)));
return False;
@@ -143,7 +197,7 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
NTSTATUS status;
if (!dce_conn->auth_state.auth_info ||
- !dce_conn->auth_state.crypto_ctx.ops) {
+ !dce_conn->auth_state.gensec_security) {
return True;
}
@@ -177,7 +231,7 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
/* check signature or unseal the packet */
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
- status = dcesrv_crypto_unseal(&dce_conn->auth_state,
+ status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
call->mem_ctx,
pkt->u.request.stub_and_verifier.data,
pkt->u.request.stub_and_verifier.length,
@@ -185,11 +239,11 @@ BOOL dcesrv_auth_request(struct dcesrv_call_state *call)
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
- status = dcesrv_crypto_check_sig(&dce_conn->auth_state,
- call->mem_ctx,
- pkt->u.request.stub_and_verifier.data,
- pkt->u.request.stub_and_verifier.length,
- &auth.credentials);
+ status = gensec_check_packet(dce_conn->auth_state.gensec_security,
+ call->mem_ctx,
+ pkt->u.request.stub_and_verifier.data,
+ pkt->u.request.stub_and_verifier.length,
+ &auth.credentials);
break;
default:
@@ -218,7 +272,7 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
struct ndr_push *ndr;
/* non-signed packets are simple */
- if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.crypto_ctx.ops) {
+ if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) {
status = dcerpc_push_auth(blob, call->mem_ctx, pkt, NULL);
return NT_STATUS_IS_OK(status);
}
@@ -244,15 +298,15 @@ BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
/* sign or seal the packet */
switch (dce_conn->auth_state.auth_info->auth_level) {
case DCERPC_AUTH_LEVEL_PRIVACY:
- status = dcesrv_crypto_seal(&dce_conn->auth_state,
- call->mem_ctx,
- ndr->data + DCERPC_REQUEST_LENGTH,
- ndr->offset - DCERPC_REQUEST_LENGTH,
- &dce_conn->auth_state.auth_info->credentials);
+ status = gensec_seal_packet(dce_conn->auth_state.gensec_security,
+ call->mem_ctx,
+ ndr->data + DCERPC_REQUEST_LENGTH,
+ ndr->offset - DCERPC_REQUEST_LENGTH,
+ &dce_conn->auth_state.auth_info->credentials);
break;
case DCERPC_AUTH_LEVEL_INTEGRITY:
- status = dcesrv_crypto_sign(&dce_conn->auth_state,
+ status = gensec_sign_packet(dce_conn->auth_state.gensec_security,
call->mem_ctx,
ndr->data + DCERPC_REQUEST_LENGTH,
ndr->offset - DCERPC_REQUEST_LENGTH,
diff --git a/source4/rpc_server/dcesrv_crypto.c b/source4/rpc_server/dcesrv_crypto.c
deleted file mode 100644
index 7765815f3b..0000000000
--- a/source4/rpc_server/dcesrv_crypto.c
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- server side dcerpc authentication code - crypto support
-
- Copyright (C) Andrew Tridgell 2004
- Copyright (C) Stefan (metze) Metzmacher 2004
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/*
- this provides a crypto interface to the various backends (such as
- NTLMSSP and SCHANNEL) for the rpc server code
-*/
-
-#include "includes.h"
-
-/*
- startup the cryptographic side of an authenticated dcerpc server
-*/
-NTSTATUS dcesrv_crypto_select_type(struct dcesrv_connection *dce_conn,
- struct dcesrv_auth *auth)
-{
- if (auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
- auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
- DEBUG(2,("auth_level %d not supported in dcesrv auth\n",
- auth->auth_info->auth_level));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (auth->crypto_ctx.ops != NULL) {
- /* TODO:
- * this this function should not be called
- * twice per dcesrv_connection!
- *
- * so we need to find out the right
- * dcerpc error to return
- */
- }
-
- /*
- * TODO:
- * maybe a dcesrv_crypto_find_backend_by_type() whould be better here
- * to make thinks more generic
- */
- auth->crypto_ctx.ops = dcesrv_crypto_backend_bytype(auth->auth_info->auth_type);
- if (auth->crypto_ctx.ops == NULL) {
- DEBUG(2,("dcesrv auth_type %d not supported\n", auth->auth_info->auth_type));
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- return NT_STATUS_OK;
-}
-
-/*
- start crypto state
-*/
-NTSTATUS dcesrv_crypto_start(struct dcesrv_auth *auth, DATA_BLOB *auth_blob)
-{
- return auth->crypto_ctx.ops->start(auth, auth_blob);
-}
-
-/*
- update crypto state
-*/
-NTSTATUS dcesrv_crypto_update(struct dcesrv_auth *auth,
- TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB in, DATA_BLOB *out)
-{
- return auth->crypto_ctx.ops->update(auth, out_mem_ctx, in, out);
-}
-
-/*
- seal a packet
-*/
-NTSTATUS dcesrv_crypto_seal(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- return auth->crypto_ctx.ops->seal(auth, sig_mem_ctx, data, length, sig);
-}
-
-/*
- sign a packet
-*/
-NTSTATUS dcesrv_crypto_sign(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- return auth->crypto_ctx.ops->sign(auth, sig_mem_ctx, data, length, sig);
-}
-
-/*
- check a packet signature
-*/
-NTSTATUS dcesrv_crypto_check_sig(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, const DATA_BLOB *sig)
-{
- return auth->crypto_ctx.ops->check_sig(auth, sig_mem_ctx, data, length, sig);
-}
-
-/*
- unseal a packet
-*/
-NTSTATUS dcesrv_crypto_unseal(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- return auth->crypto_ctx.ops->unseal(auth, sig_mem_ctx, data, length, sig);
-}
-
-/*
- get the negotiated session key
-*/
-NTSTATUS dcesrv_crypto_session_key(struct dcesrv_auth *auth, uint8_t session_key[16])
-{
- return auth->crypto_ctx.ops->session_key(auth, session_key);
-}
-
-/*
- end crypto state
-*/
-void dcesrv_crypto_end(struct dcesrv_auth *auth)
-{
- auth->crypto_ctx.ops->end(auth);
-}
-
-const struct dcesrv_crypto_ops *dcesrv_crypto_backend_bytype(uint8_t auth_type)
-{
- switch (auth_type) {
- case DCERPC_AUTH_TYPE_SCHANNEL:
- return dcesrv_crypto_schannel_get_ops();
- case DCERPC_AUTH_TYPE_NTLMSSP:
- return dcesrv_crypto_ntlmssp_get_ops();
- }
-
- return NULL;
-}
diff --git a/source4/rpc_server/dcesrv_crypto_ntlmssp.c b/source4/rpc_server/dcesrv_crypto_ntlmssp.c
deleted file mode 100644
index 35029a0fee..0000000000
--- a/source4/rpc_server/dcesrv_crypto_ntlmssp.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- server side dcerpc authentication code - NTLMSSP auth/crypto code
-
- Copyright (C) Andrew Tridgell 2004
- Copyright (C) Stefan (metze) Metzmacher 2004
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/*
- this provides the NTLMSSP backend for server side rpc
-*/
-
-#include "includes.h"
-
-
-/*
- start crypto state
-*/
-static NTSTATUS dcesrv_crypto_ntlmssp_start(struct dcesrv_auth *auth, DATA_BLOB *auth_blob)
-{
- struct auth_ntlmssp_state *ntlmssp = NULL;
- NTSTATUS status;
-
- /* the auth_blob is ignored here, and is handled in the call
- to auth_ntlmssp_update() */
-
- status = auth_ntlmssp_start(&ntlmssp);
-
- auth->crypto_ctx.private_data = ntlmssp;
-
- return status;
-}
-
-/*
- update crypto state
-*/
-static NTSTATUS dcesrv_crypto_ntlmssp_update(struct dcesrv_auth *auth, TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB in, DATA_BLOB *out)
-{
- struct auth_ntlmssp_state *auth_ntlmssp_state = auth->crypto_ctx.private_data;
- NTSTATUS status;
-
- status = auth_ntlmssp_update(auth_ntlmssp_state, out_mem_ctx, in, out);
- if (NT_STATUS_IS_OK(status)) {
- /* TODO: what is when the session_info is already set */
- return auth_ntlmssp_get_session_info(auth_ntlmssp_state, &auth->session_info);
- }
-
- return status;
-}
-
-/*
- seal a packet
-*/
-static NTSTATUS dcesrv_crypto_ntlmssp_seal(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- struct auth_ntlmssp_state *auth_ntlmssp_state = auth->crypto_ctx.private_data;
-
- return ntlmssp_seal_packet(auth_ntlmssp_state->ntlmssp_state, sig_mem_ctx, data, length, sig);
-}
-
-/*
- sign a packet
-*/
-static NTSTATUS dcesrv_crypto_ntlmssp_sign(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- struct auth_ntlmssp_state *auth_ntlmssp_state = auth->crypto_ctx.private_data;
-
- return ntlmssp_sign_packet(auth_ntlmssp_state->ntlmssp_state, sig_mem_ctx, data, length, sig);
-}
-
-/*
- check a packet signature
-*/
-static NTSTATUS dcesrv_crypto_ntlmssp_check_sig(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, const DATA_BLOB *sig)
-{
- struct auth_ntlmssp_state *auth_ntlmssp_state = auth->crypto_ctx.private_data;
-
- return ntlmssp_check_packet(auth_ntlmssp_state->ntlmssp_state, sig_mem_ctx, data, length, sig);
-}
-
-/*
- unseal a packet
-*/
-static NTSTATUS dcesrv_crypto_ntlmssp_unseal(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- struct auth_ntlmssp_state *auth_ntlmssp_state = auth->crypto_ctx.private_data;
-
- return ntlmssp_unseal_packet(auth_ntlmssp_state->ntlmssp_state, sig_mem_ctx, data, length, sig);
-}
-
-/*
- get the session key
-*/
-static NTSTATUS dcesrv_crypto_ntlmssp_session_key(struct dcesrv_auth *auth, uint8_t session_key[16])
-{
- struct auth_ntlmssp_state *auth_ntlmssp_state = auth->crypto_ctx.private_data;
-
- if (auth_ntlmssp_state->ntlmssp_state->session_key.length != 16) {
- return NT_STATUS_NO_USER_SESSION_KEY;
- }
- memcpy(session_key, auth_ntlmssp_state->ntlmssp_state->session_key.data, 16);
-
- return NT_STATUS_OK;
-}
-
-/*
- end crypto state
-*/
-static void dcesrv_crypto_ntlmssp_end(struct dcesrv_auth *auth)
-{
- struct auth_ntlmssp_state *auth_ntlmssp_state = auth->crypto_ctx.private_data;
-
- auth->crypto_ctx.private_data = NULL;
-
- auth_ntlmssp_end(&auth_ntlmssp_state);
-
- return;
-}
-
-static const struct dcesrv_crypto_ops dcesrv_crypto_ntlmssp_ops = {
- .name = "ntlmssp",
- .auth_type = DCERPC_AUTH_TYPE_NTLMSSP,
- .start = dcesrv_crypto_ntlmssp_start,
- .update = dcesrv_crypto_ntlmssp_update,
- .seal = dcesrv_crypto_ntlmssp_seal,
- .sign = dcesrv_crypto_ntlmssp_sign,
- .check_sig = dcesrv_crypto_ntlmssp_check_sig,
- .unseal = dcesrv_crypto_ntlmssp_unseal,
- .session_key = dcesrv_crypto_ntlmssp_session_key,
- .end = dcesrv_crypto_ntlmssp_end
-};
-
-/*
- startup the cryptographic side of an authenticated dcerpc server
-*/
-const struct dcesrv_crypto_ops *dcesrv_crypto_ntlmssp_get_ops(void)
-{
- return &dcesrv_crypto_ntlmssp_ops;
-}
diff --git a/source4/rpc_server/dcesrv_crypto_schannel.c b/source4/rpc_server/dcesrv_crypto_schannel.c
deleted file mode 100644
index 5da1a171f9..0000000000
--- a/source4/rpc_server/dcesrv_crypto_schannel.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
-
- server side dcerpc authentication code - schannel auth/crypto code
-
- Copyright (C) Andrew Tridgell 2004
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "includes.h"
-
-struct srv_schannel_state {
- TALLOC_CTX *mem_ctx;
- struct schannel_bind bind_info;
- struct schannel_state *state;
-};
-
-static NTSTATUS schannel_setup_session_info(struct srv_schannel_state *schannel,
- const char *account_name,
- struct auth_session_info **session_info)
-{
- TALLOC_CTX *mem_ctx;
-
- mem_ctx = talloc_init("schannel_setup");
- if (mem_ctx == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- (*session_info) = talloc_p(mem_ctx, struct auth_session_info);
- if (*session_info == NULL) {
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
- }
-
- ZERO_STRUCTP(*session_info);
-
- (*session_info)->workstation = talloc_strdup(mem_ctx, account_name);
- if ((*session_info)->workstation == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- /* TODO: fill in the rest of the session_info structure */
-
- return NT_STATUS_OK;
-}
-
-
-/*
- start crypto state
-*/
-static NTSTATUS dcesrv_crypto_schannel_start(struct dcesrv_auth *auth, DATA_BLOB *auth_blob)
-{
- struct srv_schannel_state *schannel = NULL;
- NTSTATUS status;
- TALLOC_CTX *mem_ctx;
- const char *account_name;
- struct schannel_bind_ack ack;
- struct creds_CredentialState creds;
-
- mem_ctx = talloc_init("schannel_start");
- if (!mem_ctx) {
- return NT_STATUS_NO_MEMORY;
- }
-
- schannel = talloc_p(mem_ctx, struct srv_schannel_state);
- if (!schannel) {
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
- }
-
- schannel->mem_ctx = mem_ctx;
-
- /* parse the schannel startup blob */
- status = ndr_pull_struct_blob(auth_blob, mem_ctx, &schannel->bind_info,
- (ndr_pull_flags_fn_t)ndr_pull_schannel_bind);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_destroy(mem_ctx);
- return status;
- }
-
- if (schannel->bind_info.bind_type == 23) {
- account_name = schannel->bind_info.u.info23.account_name;
- } else {
- account_name = schannel->bind_info.u.info3.account_name;
- }
-
- /* pull the session key for this client */
- status = schannel_fetch_session_key(mem_ctx, account_name, &creds);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_destroy(mem_ctx);
- return status;
- }
-
- /* start up the schannel server code */
- status = schannel_start(&schannel->state, creds.session_key, False);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_destroy(mem_ctx);
- return status;
- }
-
- status = schannel_setup_session_info(schannel, account_name,
- &auth->session_info);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_destroy(mem_ctx);
- return status;
- }
-
- auth->crypto_ctx.private_data = schannel;
-
- ack.unknown1 = 1;
- ack.unknown2 = 0;
- ack.unknown3 = 0x6c0000;
-
- status = ndr_push_struct_blob(auth_blob, mem_ctx, &ack,
- (ndr_push_flags_fn_t)ndr_push_schannel_bind_ack);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_destroy(mem_ctx);
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- return status;
-}
-
-/*
- update crypto state
-*/
-static NTSTATUS dcesrv_crypto_schannel_update(struct dcesrv_auth *auth, TALLOC_CTX *out_mem_ctx,
- const DATA_BLOB in, DATA_BLOB *out)
-{
- return NT_STATUS_OK;
-}
-
-/*
- seal a packet
-*/
-static NTSTATUS dcesrv_crypto_schannel_seal(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
-
- return schannel_seal_packet(srv_schannel_state->state, sig_mem_ctx, data, length, sig);
-}
-
-/*
- sign a packet
-*/
-static NTSTATUS dcesrv_crypto_schannel_sign(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
-
- return schannel_sign_packet(srv_schannel_state->state, sig_mem_ctx, data, length, sig);
-}
-
-/*
- check a packet signature
-*/
-static NTSTATUS dcesrv_crypto_schannel_check_sig(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- const uint8_t *data, size_t length, const DATA_BLOB *sig)
-{
- struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
-
- return schannel_check_packet(srv_schannel_state->state, data, length, sig);
-}
-
-/*
- unseal a packet
-*/
-static NTSTATUS dcesrv_crypto_schannel_unseal(struct dcesrv_auth *auth, TALLOC_CTX *sig_mem_ctx,
- uint8_t *data, size_t length, DATA_BLOB *sig)
-{
- struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
-
- return schannel_unseal_packet(srv_schannel_state->state, sig_mem_ctx, data, length, sig);
-}
-
-/*
- get the session key
-*/
-static NTSTATUS dcesrv_crypto_schannel_session_key(struct dcesrv_auth *auth, uint8_t session_key[16])
-{
- struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
-
- memcpy(session_key, srv_schannel_state->state->session_key, 16);
-
- return NT_STATUS_OK;
-}
-
-/*
- end crypto state
-*/
-static void dcesrv_crypto_schannel_end(struct dcesrv_auth *auth)
-{
- struct srv_schannel_state *srv_schannel_state = auth->crypto_ctx.private_data;
-
- if (srv_schannel_state == NULL) {
- return;
- }
-
- schannel_end(&srv_schannel_state->state);
-
- talloc_destroy(srv_schannel_state->mem_ctx);
-
- auth->crypto_ctx.private_data = NULL;
-}
-
-static const struct dcesrv_crypto_ops dcesrv_crypto_schannel_ops = {
- .name = "schannel",
- .auth_type = DCERPC_AUTH_TYPE_SCHANNEL,
- .start = dcesrv_crypto_schannel_start,
- .update = dcesrv_crypto_schannel_update,
- .seal = dcesrv_crypto_schannel_seal,
- .sign = dcesrv_crypto_schannel_sign,
- .check_sig = dcesrv_crypto_schannel_check_sig,
- .unseal = dcesrv_crypto_schannel_unseal,
- .session_key = dcesrv_crypto_schannel_session_key,
- .end = dcesrv_crypto_schannel_end
-};
-
-/*
- startup the cryptographic side of an authenticated dcerpc server
-*/
-const struct dcesrv_crypto_ops *dcesrv_crypto_schannel_get_ops(void)
-{
- return &dcesrv_crypto_schannel_ops;
-}
diff --git a/source4/rpc_server/netlogon/dcerpc_netlogon.c b/source4/rpc_server/netlogon/dcerpc_netlogon.c
index 80bbb6b583..7eb4c0e815 100644
--- a/source4/rpc_server/netlogon/dcerpc_netlogon.c
+++ b/source4/rpc_server/netlogon/dcerpc_netlogon.c
@@ -58,21 +58,15 @@ static NTSTATUS netlogon_schannel_setup(struct dcesrv_call_state *dce_call)
state->mem_ctx = mem_ctx;
state->authenticated = True;
- state->creds = talloc_p(mem_ctx, struct creds_CredentialState);
- if (state->creds == NULL) {
- talloc_destroy(mem_ctx);
- return NT_STATUS_NO_MEMORY;
- }
- ZERO_STRUCTP(state->creds);
-
if (dce_call->conn->auth_state.session_info == NULL) {
talloc_destroy(mem_ctx);
return NT_STATUS_NO_USER_SESSION_KEY;
}
- status = schannel_fetch_session_key(mem_ctx,
- dce_call->conn->auth_state.session_info->workstation,
- state->creds);
+ status = dcerpc_schannel_creds(dce_call->conn->auth_state.gensec_security,
+ mem_ctx,
+ &state->creds);
+
if (!NT_STATUS_IS_OK(status)) {
talloc_destroy(mem_ctx);
return status;
diff --git a/source4/rpc_server/samr/samr_password.c b/source4/rpc_server/samr/samr_password.c
index 988c52e4ee..f1947022a2 100644
--- a/source4/rpc_server/samr/samr_password.c
+++ b/source4/rpc_server/samr/samr_password.c
@@ -693,7 +693,7 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
{
char new_pass[512];
uint32_t new_pass_len;
- DATA_BLOB session_key;
+ DATA_BLOB session_key = data_blob(NULL, 0);
session_key = data_blob(NULL,0);
@@ -703,7 +703,7 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
if (session_key.length == 0) {
DEBUG(3,("Bad session key in samr_set_password\n"));
- return NT_STATUS_WRONG_PASSWORD;
+ return NT_STATUS_NO_USER_SESSION_KEY;
}
arcfour_crypt_blob(pwbuf->data, 516, &session_key);
@@ -740,7 +740,7 @@ NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
char new_pass[512];
uint32_t new_pass_len;
DATA_BLOB co_session_key;
- DATA_BLOB session_key;
+ DATA_BLOB session_key = data_blob(NULL, 0);
struct MD5Context ctx;
session_key = data_blob(NULL,0);
@@ -749,6 +749,11 @@ NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
session_key = dce_call->conn->auth_state.session_info->session_key;
}
+ if (session_key.length == 0) {
+ DEBUG(3,("Bad session key in samr_set_password\n"));
+ return NT_STATUS_NO_USER_SESSION_KEY;
+ }
+
co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
if (!co_session_key.data) {
return NT_STATUS_NO_MEMORY;
diff --git a/source4/smb_server/password.c b/source4/smb_server/password.c
index 499023374f..6132e9f84f 100644
--- a/source4/smb_server/password.c
+++ b/source4/smb_server/password.c
@@ -58,7 +58,7 @@ void invalidate_vuid(struct smbsrv_connection *smb, uint16_t vuid)
session_yield(vuser);
- talloc_destroy(vuser->session_info->mem_ctx);
+ free_session_info(&vuser->session_info);
DLIST_REMOVE(smb->users.validated_users, vuser);
diff --git a/source4/torture/rpc/schannel.c b/source4/torture/rpc/schannel.c
index e120c0d2ad..f6c94b145a 100644
--- a/source4/torture/rpc/schannel.c
+++ b/source4/torture/rpc/schannel.c
@@ -92,7 +92,10 @@ static BOOL test_schannel(TALLOC_CTX *mem_ctx,
goto failed;
}
- test_samr_ops(p, mem_ctx);
+ if (!test_samr_ops(p, mem_ctx)) {
+ printf("Failed to process schannel secured ops\n");
+ goto failed;
+ }
torture_leave_domain(join_ctx);
return True;
diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c
index 7690a549f7..1ae9075fba 100644
--- a/source4/utils/ntlm_auth.c
+++ b/source4/utils/ntlm_auth.c
@@ -35,6 +35,7 @@ enum stdio_helper_mode {
SQUID_2_5_NTLMSSP,
NTLMSSP_CLIENT_1,
GSS_SPNEGO_CLIENT,
+ GSS_SPNEGO_SERVER,
NTLM_SERVER_1,
NUM_HELPER_MODES
};
@@ -44,19 +45,19 @@ enum stdio_helper_mode {
typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+ char *buf, int length, void **private);
static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+ char *buf, int length, void **private);
-static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
-
-static void manage_gensec_client_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+static void manage_gensec_request (enum stdio_helper_mode stdio_helper_mode,
+ char *buf, int length, void **private);
static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+ char *buf, int length, void **private);
+
+static void manage_squid_request(enum stdio_helper_mode helper_mode,
+ stdio_helper_function fn, void *private);
static const struct {
enum stdio_helper_mode mode;
@@ -65,9 +66,10 @@ static const struct {
} stdio_helper_protocols[] = {
{ SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
{ SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
- { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
- { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_gensec_client_request},
- { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gensec_client_request},
+ { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_gensec_request},
+ { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gensec_request},
+ { GSS_SPNEGO_SERVER, "gss-spnego-server", manage_gensec_request},
+ { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_gensec_request},
{ NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
{ NUM_HELPER_MODES, NULL, NULL}
};
@@ -172,149 +174,8 @@ static NTSTATUS local_pw_check_specified(const char *username,
}
-static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
-{
- NTSTATUS nt_status;
- uint8 lm_pw[16], nt_pw[16];
- uint8_t *lm_pwd, *nt_pwd;
-
- E_md4hash(opt_password, nt_pw);
- if (E_deshash(opt_password, lm_pw)) {
- lm_pwd = lm_pw;
- } else {
- lm_pwd = NULL;
- }
- nt_pwd = nt_pw;
-
- nt_status = ntlm_password_check(ntlmssp_state->mem_ctx,
- &ntlmssp_state->chal,
- &ntlmssp_state->lm_resp,
- &ntlmssp_state->nt_resp,
- NULL, NULL,
- ntlmssp_state->user,
- ntlmssp_state->user,
- ntlmssp_state->domain,
- lm_pwd, nt_pwd, user_session_key, lm_session_key);
-
- if (NT_STATUS_IS_OK(nt_status)) {
- ntlmssp_state->auth_context = talloc_asprintf(ntlmssp_state->mem_ctx,
- "%s%c%s", ntlmssp_state->domain,
- *lp_winbind_separator(),
- ntlmssp_state->user);
- } else {
- DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
- ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation,
- nt_errstr(nt_status)));
- ntlmssp_state->auth_context = NULL;
- }
- return nt_status;
-}
-
-static NTSTATUS ntlm_auth_start_ntlmssp_server(struct ntlmssp_state **ntlmssp_state)
-{
- NTSTATUS status = ntlmssp_server_start(ntlmssp_state);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Could not start NTLMSSP client: %s\n",
- nt_errstr(status)));
- return status;
- }
-
- /* Have we been given a local password, or should we ask winbind? */
- if (opt_password) {
- (*ntlmssp_state)->check_password = local_pw_check;
- (*ntlmssp_state)->get_domain = lp_workgroup;
- (*ntlmssp_state)->get_global_myname = global_myname;
- } else {
- DEBUG(0, ("Winbind not supported in Samba4 ntlm_auth yet, specify --password\n"));
- exit(1);
- }
- return NT_STATUS_OK;
-}
-
-static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
-{
- static struct ntlmssp_state *ntlmssp_state = NULL;
- DATA_BLOB request, reply;
- NTSTATUS nt_status;
-
- if (strlen(buf) < 2) {
- DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
- x_fprintf(x_stdout, "BH\n");
- return;
- }
-
- if (strlen(buf) > 3) {
- request = base64_decode_data_blob(buf + 3);
- } else {
- request = data_blob(NULL, 0);
- }
-
- if ((strncmp(buf, "PW ", 3) == 0)) {
- /* The calling application wants us to use a local password (rather than winbindd) */
-
- opt_password = strndup((const char *)request.data, request.length);
-
- if (opt_password == NULL) {
- DEBUG(1, ("Out of memory\n"));
- x_fprintf(x_stdout, "BH\n");
- data_blob_free(&request);
- return;
- }
-
- x_fprintf(x_stdout, "OK\n");
- data_blob_free(&request);
- return;
- }
-
- if (strncmp(buf, "YR", 2) == 0) {
- if (ntlmssp_state)
- ntlmssp_end(&ntlmssp_state);
- } else if (strncmp(buf, "KK", 2) == 0) {
-
- } else {
- DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
- x_fprintf(x_stdout, "BH\n");
- return;
- }
-
- if (!ntlmssp_state) {
- if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
- x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
- return;
- }
- }
-
- DEBUG(10, ("got NTLMSSP packet:\n"));
- dump_data(10, (const char *)request.data, request.length);
-
- nt_status = ntlmssp_update(ntlmssp_state, NULL, request, &reply);
-
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- char *reply_base64 = base64_encode_data_blob(reply);
- x_fprintf(x_stdout, "TT %s\n", reply_base64);
- SAFE_FREE(reply_base64);
- data_blob_free(&reply);
- DEBUG(10, ("NTLMSSP challenge\n"));
- } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
- x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
- DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
-
- ntlmssp_end(&ntlmssp_state);
- } else if (!NT_STATUS_IS_OK(nt_status)) {
- x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
- DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
- } else {
- x_fprintf(x_stdout, "AF %s\n", (char *)ntlmssp_state->auth_context);
- DEBUG(10, ("NTLMSSP OK!\n"));
- }
-
- data_blob_free(&request);
-}
-
static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+ char *buf, int length, void **private)
{
char *user, *pass;
user=buf;
@@ -340,16 +201,14 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
}
}
-static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+/* This is a bit hairy, but the basic idea is to do a password callback
+ to the calling application. The callback comes from within gensec */
+
+static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
+ char *buf, int length, void **private)
{
DATA_BLOB in;
- DATA_BLOB out;
- char *out_base64;
- static struct gensec_security gensec_state;
- NTSTATUS nt_status;
- BOOL first = False;
-
+ struct gensec_security **gensec_state = (struct gensec_security **)private;
if (strlen(buf) < 2) {
DEBUG(1, ("query [%s] invalid", buf));
x_fprintf(x_stdout, "BH\n");
@@ -364,11 +223,10 @@ static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mod
if (strncmp(buf, "PW ", 3) == 0) {
- /* We asked for a password and obviously got it :-) */
-
- opt_password = strndup((const char *)in.data, in.length);
+ (*gensec_state)->password_callback_private = talloc_strndup((*gensec_state)->mem_ctx,
+ (const char *)in.data, in.length);
- if (opt_password == NULL) {
+ if ((*gensec_state)->password_callback_private == NULL) {
DEBUG(1, ("Out of memory\n"));
x_fprintf(x_stdout, "BH\n");
data_blob_free(&in);
@@ -379,39 +237,124 @@ static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mod
data_blob_free(&in);
return;
}
+ DEBUG(1, ("Asked for (and expected) a password\n"));
+ x_fprintf(x_stdout, "BH\n");
+ data_blob_free(&in);
+}
+
+/*
+ * Callback for gensec, to ask the calling application for a password. Uses the above function
+ * for the stdio part of this.
+ */
+
+static NTSTATUS get_password(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx,
+ char **password)
+{
+ *password = NULL;
+
+ /* Ask for a password */
+ x_fprintf(x_stdout, "PW\n");
+ gensec_security->password_callback_private = NULL;
+
+ manage_squid_request(NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, &gensec_security);
+ *password = (char *)gensec_security->password_callback_private;
+ if (*password) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+}
+
+static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ char *buf, int length, void **private)
+{
+ DATA_BLOB in;
+ DATA_BLOB out = data_blob(NULL, 0);
+ char *out_base64 = NULL;
+ const char *reply_arg = NULL;
+ struct gensec_security **gensec_state = (struct gensec_security **)private;
+ NTSTATUS nt_status;
+ BOOL first = False;
+ const char *reply_code;
+
+ if (strlen(buf) < 2) {
+ DEBUG(1, ("query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
+ if (strlen(buf) > 3) {
+ in = base64_decode_data_blob(buf + 3);
+ } else {
+ in = data_blob(NULL, 0);
+ }
+
if (strncmp(buf, "YR", 2) == 0) {
- if (gensec_state.ops) {
- gensec_state.ops->end(&gensec_state);
- gensec_state.ops = NULL;
+ if (gensec_state && *gensec_state) {
+ gensec_end(gensec_state);
+ *gensec_state = NULL;
}
+ } else if ( (strncmp(buf, "OK", 2) == 0)) {
+ /* do nothing */
+ data_blob_free(&in);
+ return;
} else if ( (strncmp(buf, "TT ", 3) != 0) &&
- (strncmp(buf, "AF ", 3) != 0) &&
- (strncmp(buf, "NA ", 3) != 0) ) {
+ (strncmp(buf, "KK ", 3) != 0) &&
+ (strncmp(buf, "AF ", 3) != 0) &&
+ (strncmp(buf, "NA ", 3) != 0) &&
+ (strncmp(buf, "PW ", 3) != 0)) {
DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
x_fprintf(x_stdout, "BH\n");
data_blob_free(&in);
return;
}
- if (!opt_password) {
- x_fprintf(x_stdout, "PW\n");
- data_blob_free(&in);
- return;
- }
-
/* setup gensec */
- if (!gensec_state.ops) {
- if (stdio_helper_mode == GSS_SPNEGO_CLIENT) {
- gensec_state.ops = gensec_security_by_oid(OID_SPNEGO);
- } else if (stdio_helper_mode == NTLMSSP_CLIENT_1) {
- gensec_state.ops = gensec_security_by_oid(OID_NTLMSSP);
- } else {
- exit(1);
+ if (!(gensec_state && *gensec_state)) {
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_CLIENT:
+ case NTLMSSP_CLIENT_1:
+ /* setup the client side */
+
+ if (!NT_STATUS_IS_OK(gensec_client_start(gensec_state))) {
+ exit(1);
+ }
+ gensec_set_username(*gensec_state, opt_username);
+ gensec_set_domain(*gensec_state, opt_domain);
+ if (opt_password) {
+ if (!NT_STATUS_IS_OK(gensec_set_password(*gensec_state, opt_password))) {
+ DEBUG(1, ("Out of memory\n"));
+ x_fprintf(x_stdout, "BH\n");
+ data_blob_free(&in);
+ return;
+ }
+ } else {
+ gensec_set_password_callback(*gensec_state, get_password, NULL);
+ }
+
+ break;
+ case GSS_SPNEGO_SERVER:
+ case SQUID_2_5_NTLMSSP:
+ if (!NT_STATUS_IS_OK(gensec_server_start(gensec_state))) {
+ exit(1);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_CLIENT:
+ case GSS_SPNEGO_SERVER:
+ nt_status = gensec_start_mech_by_oid(*gensec_state, OID_SPNEGO);
+ break;
+ case NTLMSSP_CLIENT_1:
+ case SQUID_2_5_NTLMSSP:
+ nt_status = gensec_start_mech_by_oid(*gensec_state, OID_NTLMSSP);
+ break;
+ default:
+ abort();
}
- gensec_state.user.name = opt_username;
- gensec_state.user.domain = opt_domain;
- gensec_state.user.password = opt_password;
- nt_status = gensec_state.ops->client_start(&gensec_state);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("SPENGO login failed to initialise: %s\n", nt_errstr(nt_status)));
@@ -423,33 +366,104 @@ static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mod
}
}
+ if (strncmp(buf, "PW ", 3) == 0) {
+
+ if (!NT_STATUS_IS_OK(gensec_set_password(*gensec_state,
+ talloc_strndup((*gensec_state)->mem_ctx,
+ (const char *)in.data,
+ in.length)))) {
+ DEBUG(1, ("Out of memory\n"));
+ x_fprintf(x_stdout, "BH\n");
+ data_blob_free(&in);
+ return;
+ }
+
+ x_fprintf(x_stdout, "OK\n");
+ data_blob_free(&in);
+ return;
+ }
+
/* update */
- nt_status = gensec_state.ops->update(&gensec_state, NULL, in, &out);
+ nt_status = gensec_update(*gensec_state, NULL, in, &out);
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ /* don't leak 'bad password'/'no such user' info to the network client */
+ nt_status = nt_status_squash(nt_status);
+ if (out.length) {
out_base64 = base64_encode_data_blob(out);
+ } else {
+ out_base64 = NULL;
+ }
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ reply_arg = "*";
if (first) {
- x_fprintf(x_stdout, "YR %s\n", out_base64);
- } else {
- x_fprintf(x_stdout, "KK %s\n", out_base64);
+ reply_code = "YR";
+ } else if ((*gensec_state)->gensec_role == GENSEC_CLIENT) {
+ reply_code = "KK";
+ } else if ((*gensec_state)->gensec_role == GENSEC_SERVER) {
+ reply_code = "TT";
+ } else {
+ abort();
}
- SAFE_FREE(out_base64);
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
} else if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(1, ("SPENGO login failed: %s\n", nt_errstr(nt_status)));
- x_fprintf(x_stdout, "BH\n");
+ reply_code = "NA";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
+ } else if /* OK */ ((*gensec_state)->gensec_role == GENSEC_SERVER) {
+ struct auth_session_info *session_info;
+
+ nt_status = gensec_session_info(*gensec_state, &session_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC failed to retreive the session info: %s\n", nt_errstr(nt_status)));
+ } else {
+
+ reply_code = "AF";
+ reply_arg = talloc_asprintf((*gensec_state)->mem_ctx,
+ "%s%s%s", session_info->server_info->domain,
+ lp_winbind_separator(), session_info->server_info->account_name);
+ talloc_destroy(session_info->mem_ctx);
+ }
+ } else if ((*gensec_state)->gensec_role == GENSEC_SERVER) {
+ reply_code = "AF";
+ reply_arg = NULL;
} else {
- x_fprintf(x_stdout, "AF\n");
+ abort();
}
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_SERVER:
+ if (out_base64) {
+ x_fprintf(x_stdout, "%s %s %s\n", reply_code, out_base64, reply_arg);
+ } else {
+ x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg);
+ }
+ default:
+ if (out_base64) {
+ x_fprintf(x_stdout, "%s %s\n", reply_code, out_base64);
+ } else {
+ x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg);
+ }
+ }
+
+ SAFE_FREE(out_base64);
return;
}
static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+ char *buf, int length, void **private)
{
char *request, *parameter;
static DATA_BLOB challenge;
@@ -643,7 +657,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod
}
}
-static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn)
+static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn, void *private)
{
char buf[SQUID_BUFFER_SIZE+1];
int length;
@@ -684,16 +698,16 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helpe
return;
}
- fn(helper_mode, buf, length);
+ fn(helper_mode, buf, length, private);
}
-
static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
/* initialize FDescs */
x_setbuf(x_stdout, NULL);
x_setbuf(x_stderr, NULL);
+ void *private = NULL;
while(1) {
- manage_squid_request(stdio_mode, fn);
+ manage_squid_request(stdio_mode, fn, &private);
}
}