summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2004-06-29 09:40:10 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:56:49 -0500
commitdc9f55dbec5f892b39d924d5fd033b5eec1e14e4 (patch)
treedd6932fb92fef55787b9a20671dd8c8f71ef3b6d
parenta440e8f3b518d25c5fb9c9fa896cb7704974f346 (diff)
downloadsamba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.tar.gz
samba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.tar.bz2
samba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.zip
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up to the standards of a full subsystem. This means that use of the subsystem is by gensec_* functions, not function pointers in structures (this is internal). This causes changes in all the existing gensec users. Our RPC server no longer contains it's own generalised security scheme, and now calls gensec directly. Gensec has also taken over the role of auth/auth_ntlmssp.c An important part of gensec, is the output of the 'session_info' struct. This is now reference counted, so that we can correctly free it when a pipe is closed, no matter if it was inherited, or created by per-pipe authentication. The schannel code is reworked, to be in the same file for client and server. ntlm_auth is reworked to use gensec. The major problem with this code is the way it relies on subsystem auto-initialisation. The primary reason for this commit now.is to allow these problems to be looked at, and fixed. There are problems with the new code: - I've tested it with smbtorture, but currently don't have VMware and valgrind working (this I'll fix soon). - The SPNEGO code is client-only at this point. - We still do not do kerberos. Andrew Bartlett (This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
-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);
}
}