r1294: A nice, large, commit...
authorAndrew Bartlett <abartlet@samba.org>
Tue, 29 Jun 2004 09:40:10 +0000 (09:40 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 17:56:49 +0000 (12:56 -0500)
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)

33 files changed:
source4/auth/auth.h
source4/auth/auth_ntlmssp.c [deleted file]
source4/auth/auth_util.c
source4/auth/config.m4
source4/auth/config.mk
source4/libcli/auth/gensec.c
source4/libcli/auth/gensec.h
source4/libcli/auth/gensec_ntlmssp.c
source4/libcli/auth/ntlmssp_sign.c
source4/libcli/auth/spnego.c
source4/libcli/auth/spnego.h
source4/libcli/config.m4
source4/librpc/ndr/ndr.c
source4/librpc/rpc/dcerpc.c
source4/librpc/rpc/dcerpc.h
source4/librpc/rpc/dcerpc_auth.c
source4/librpc/rpc/dcerpc_ntlm.c
source4/librpc/rpc/dcerpc_schannel.c
source4/librpc/rpc/dcerpc_util.c
source4/ntvfs/ipc/vfs_ipc.c
source4/rpc_server/config.m4
source4/rpc_server/config.mk
source4/rpc_server/dcerpc_server.c
source4/rpc_server/dcerpc_server.h
source4/rpc_server/dcesrv_auth.c
source4/rpc_server/dcesrv_crypto.c [deleted file]
source4/rpc_server/dcesrv_crypto_ntlmssp.c [deleted file]
source4/rpc_server/dcesrv_crypto_schannel.c [deleted file]
source4/rpc_server/netlogon/dcerpc_netlogon.c
source4/rpc_server/samr/samr_password.c
source4/smb_server/password.c
source4/torture/rpc/schannel.c
source4/utils/ntlm_auth.c

index c20b8dbf6f794d07a43e26a0df414f8db338c767..0c8f71d8596f7734d416bf640437975745f76ed1 100644 (file)
@@ -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 (file)
index 183363a..0000000
+++ /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;
-}
index 097f504538ece4dcfcbc736240be65cdf5042a86..06947999b3ac1277d48815c70ffb3edf050576b7 100644 (file)
@@ -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
index 01e4574d940e3b3ebb17522d737e1559857a6642..3c4f86eceabaac7b0269f256a6aacc4ea49fcb30 100644 (file)
@@ -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])
index c9b47e745b20201b1f60aa8d86d8da965e81cb39..b4082cb9e54f96ab7e039abce41c2c26cbdc1afc 100644 (file)
@@ -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
index 138c4af35cbec738f3ffe8706fc76d5007d121b1..f6d6db9e627a755ef2635ce911b8f62903f112e3 100644 (file)
 
 #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;
+}
index 2a469e0f57ccaa76a08c5b189b8456168e7d07eb..463b484a7f0410cee633dc156398c8e2c2f94fea 100644 (file)
@@ -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;
+};
+
+
+       
index f7e9dddd2feddae07d363a248b07895961690eb8..9f7c4c6f866b2beabf92b5bf93e524408231f808 100644 (file)
 
 #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;
+}
index d680da9495afeae12eff4e97e4129424b531496b..80ce1cccc06457dc45ccac63ead981e5e0d06ea5 100644 (file)
@@ -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);
index 321b13afdc07e630fb2a2ead8f03750b5619a4d5..bb9d2504ac1522ba0534c845a11f296f9d83532e 100644 (file)
 #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;
+}
index 890301314bb6a5a1ad972cd00cd7451a159abf6a..60ef4c1d3647dad07adc9781ed9d253f4e2c3255 100644 (file)
 
 #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
index 992f84005d76c7596f747c1f2b8d59daf10e1da6..9e194990033b7970483996e89e45b971aaea7416 100644 (file)
@@ -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
index 6b89cb4cd270959f0b47acc55e95a2661b559f3d..d2e85f6aec28b221c0a17a05bbac2893b000e35c 100644 (file)
@@ -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;
index 5d5469da7f807a73a878f91f1a6546e5d003b89f..8afc5565287448ffa3c04b0d59e2ed41f7c0efe5 100644 (file)
@@ -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:
index a513b72a161159d27d8020f10f5bd3f1a3ecabdd..4f50b261e2c805e1c1aafd93de27687bfae61ad1 100644 (file)
@@ -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 {
index e5fad1f0824efb820d05388beb642e3945cece3f..07601e47246638ca4ac2803ae584be6f73c22337 100644 (file)
@@ -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;
index 398e3f1aa325d103c6d5df4d6bc985abd426015a..0f02669eb11b17db26553d8ad6b5bc9739625fc6 100644 (file)
@@ -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;
 }
index b43dd0788ace9198336255d707c13246cbae4496..ffe60b1bae6af336e755d56cf5521eb4c63043c6 100644 (file)
 
 #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;
 }
index 82aa5aa1f3d61cbc501a1ef5e46bd9143f4cf21e..d5cd2ab6fe4745700d80f0b186d577534f11412c 100644 (file)
@@ -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);
index cf8b49ebb823bc59b4c35515348afd56f9baa1ef..f6a0015f1dc61a7ec39da06234f09cc41a9a83a1 100644 (file)
@@ -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;
        }
 
index 3f64cdcf4bdb1ce3c2af1de0c7a0d15fc60f2592..73cae6645688ec1246e38722f15f5c96f2dcc93e 100644 (file)
@@ -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)
index 9d9f12d9aaffb6a97d2220d7e629d1c15d283b7b..dbe8b8344e98468ccaa34701faa96a80be4d1cfc 100644 (file)
@@ -19,11 +19,21 @@ 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]
@@ -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
 ################################################
index 90ebaf285cda7c354eedcff7b6abd25e494e3cc3..e5c4c120a5359a41189e1f3931827ac1ffeb53d0 100644 (file)
@@ -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;
        
index 3ad768b32e34aec8d9710b73d22e8d8227b2f5d0..b1754dd4a3d893adfdc19f518802603f4d1426b2 100644 (file)
@@ -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;
 };
 
index 26053b47b9e6c03e20d9b955c38c80a5243f4b3a..84a5460d6887b55ab4da711ebc3e8878582cd997 100644 (file)
@@ -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
 
 #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 
@@ -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 (file)
index 7765815..0000000
+++ /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 (file)
index 35029a0..0000000
+++ /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 (file)
index 5da1a17..0000000
+++ /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;
-}
index 80bbb6b583723f6678941ea060d8210241463076..7eb4c0e815b2524e5a3f70856d14e07ad07bfea4 100644 (file)
@@ -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;
index 988c52e4ee33eb6c2eb3000b0fa19f60a5379f61..f1947022a277ea0b6dff9cb310154b72df44638a 100644 (file)
@@ -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;
index 499023374fbde79fe8d0193b30083470da578d82..6132e9f84f114d3db49e119cd495e0ed94039e83 100644 (file)
@@ -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);
 
index e120c0d2adce9494af3867f14953372cf8caf8d5..f6c94b145adadd619105bb2ef8f874dbeaf4e8af 100644 (file)
@@ -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;
index 7690a549f72d17cbdfdc793f0e9c85eb4a62b95c..1ae9075fbab55689a6dcb49aeac2ce6279b5c555 100644 (file)
@@ -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);
        }
 }