Updates to our NTLMSSP code:
authorAndrew Bartlett <abartlet@samba.org>
Mon, 13 Jan 2003 12:48:37 +0000 (12:48 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Mon, 13 Jan 2003 12:48:37 +0000 (12:48 +0000)
This tries to extract our server-side code out of sessetup.c, and into a more
general lib.  I hope this is only a temporay resting place - I indend to
refactor it again into an auth-subsystem independent lib, using callbacks.

Move some of our our NTLMSSP #defines into a new file, and add two that I found
in the COMsource docs - we seem to have a double-up, but I've verified from
traces that the NTLMSSP_TARGET_TYPE_{DOMAIN,SERVER} is real.

This code also copes with ASCII clients - not that we will ever see any here,
but I hope to use this for HTTP, were we can get them.  Win2k authenticates
fine under forced ASCII, btw.

Tested with Win2k, NTLMv2 and Samba's smbclient.

Andrew Bartlett
(This used to be commit b6641badcbb2fb3bfec9d00a6466318203ea33e1)

source3/Makefile.in
source3/auth/auth.c
source3/auth/auth_ntlmssp.c [new file with mode: 0644]
source3/include/includes.h
source3/include/ntlmssp.h [new file with mode: 0644]
source3/include/rpc_dce.h
source3/libsmb/asn1.c
source3/libsmb/cliconnect.c
source3/libsmb/clispnego.c
source3/smbd/sesssetup.c

index bf870b0c76e48c7e499465204c9b9858988483b1..884c041ddb9cdc7dfaecc6067b4ea51f43c6e4fc 100644 (file)
@@ -267,7 +267,7 @@ UNIGRP_OBJ = libsmb/netlogon_unigrp.o
 
 AUTH_OBJ = auth/auth.o auth/auth_sam.o auth/auth_server.o auth/auth_domain.o \
           auth/auth_rhosts.o auth/auth_unix.o auth/auth_util.o auth/auth_winbind.o \
-          auth/auth_builtin.o auth/auth_compat.o \
+          auth/auth_builtin.o auth/auth_compat.o auth/auth_ntlmssp.o \
           $(PLAINTEXT_AUTH_OBJ) $(UNIGRP_OBJ)
 
 MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o
index 3c4448445ab98bab840cba57c46bbe6938c712ed..5d56603b9fd57092a6fa5d80fe598bc22e63b4f2 100644 (file)
@@ -57,7 +57,8 @@ static const uint8 *get_ntlm_challenge(struct auth_context *auth_context)
        TALLOC_CTX *mem_ctx;
 
        if (auth_context->challenge.length) {
-               DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge (normal)\n"));
+               DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", 
+                         auth_context->challenge_set_by));
                return auth_context->challenge.data;
        }
 
@@ -190,6 +191,12 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context,
 
        DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
                  user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str));
+
+       if (auth_context->challenge.length != 8) {
+               DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
        if (auth_context->challenge_set_by)
                DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
                                        auth_context->challenge_set_by));
@@ -441,6 +448,7 @@ NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[
        }
        
        (*auth_context)->challenge = data_blob(chal, 8);
+       (*auth_context)->challenge_set_by = "fixed";
        return nt_status;
 }
 
diff --git a/source3/auth/auth_ntlmssp.c b/source3/auth/auth_ntlmssp.c
new file mode 100644 (file)
index 0000000..f5e5c98
--- /dev/null
@@ -0,0 +1,284 @@
+/* 
+   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"
+
+NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
+{
+       NTSTATUS nt_status;
+       TALLOC_CTX *mem_ctx;
+
+       mem_ctx = talloc_init("NTLMSSP context");
+       
+       *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
+       if (!*ntlmssp_state) {
+               DEBUG(0,("ntlmssp_start: talloc failed!\n"));
+               talloc_destroy(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       ZERO_STRUCTP(*ntlmssp_state);
+
+       (*ntlmssp_state)->mem_ctx = mem_ctx;
+
+       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&(*ntlmssp_state)->auth_context))) {
+               return nt_status;
+       }
+       return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
+{
+       TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
+       if ((*ntlmssp_state)->auth_context) {
+               ((*ntlmssp_state)->auth_context->free)(&(*ntlmssp_state)->auth_context);
+       }
+       if ((*ntlmssp_state)->server_info) {
+               free_server_info(&(*ntlmssp_state)->server_info);
+       }
+
+       talloc_destroy(mem_ctx);
+       return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, 
+                              DATA_BLOB request, DATA_BLOB *reply) 
+{
+       uint32 ntlmssp_command;
+               
+       if (!msrpc_parse(&request, "Cd",
+                        "NTLMSSP",
+                        &ntlmssp_command)) {
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
+               return ntlmssp_negotiate(ntlmssp_state, request, reply);
+       } else if (ntlmssp_command == NTLMSSP_AUTH) {
+               return ntlmssp_auth(ntlmssp_state, request, reply);
+       } else {
+               return NT_STATUS_LOGON_FAILURE;
+       }
+}
+
+static const char *ntlmssp_target_name(uint32 neg_flags, uint32 *chal_flags) 
+{
+       if (neg_flags & NTLMSSP_REQUEST_TARGET) {
+               if (lp_server_role() == ROLE_STANDALONE) {
+                       *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
+                       return global_myname();
+               } else {
+                       *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
+                       return lp_workgroup();
+               };
+       } else {
+               return "";
+       }
+}
+
+NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state, 
+                          DATA_BLOB request, DATA_BLOB *reply) 
+{
+       DATA_BLOB struct_blob;
+       fstring dnsname, dnsdomname;
+       uint32 ntlmssp_command, neg_flags, chal_flags;
+       char *cliname=NULL, *domname=NULL;
+       const uint8 *cryptkey;
+       const char *target_name;
+
+       /* parse the NTLMSSP packet */
+#if 0
+       file_save("ntlmssp_negotiate.dat", request.data, request.length);
+#endif
+
+       if (!msrpc_parse(&request, "CddAA",
+                        "NTLMSSP",
+                        &ntlmssp_command,
+                        &neg_flags,
+                        &cliname,
+                        &domname)) {
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       SAFE_FREE(cliname);
+       SAFE_FREE(domname);
+  
+       debug_ntlmssp_flags(neg_flags);
+
+       cryptkey = ntlmssp_state->auth_context->get_ntlm_challenge(ntlmssp_state->auth_context);
+
+       /* Give them the challenge. For now, ignore neg_flags and just
+          return the flags we want. Obviously this is not correct */
+       
+       chal_flags = 
+               NTLMSSP_NEGOTIATE_128 | 
+               NTLMSSP_NEGOTIATE_NTLM |
+               NTLMSSP_CHAL_TARGET_INFO;
+       
+       if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+               chal_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+               ntlmssp_state->unicode = True;
+       } else {
+               chal_flags |= NTLMSSP_NEGOTIATE_OEM;
+       }
+
+       target_name = ntlmssp_target_name(neg_flags, &chal_flags); 
+
+       dnsdomname[0] = '\0';
+       get_mydomname(dnsdomname);
+       strlower(dnsdomname);
+       
+       dnsname[0] = '\0';
+       get_myfullname(dnsname);
+       strlower(dnsname);
+       
+       /* the numbers here are the string type flags */
+       msrpc_gen(&struct_blob, "aaaaa",
+                 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, lp_workgroup(),
+                 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, global_myname(),
+                 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsname,
+                 ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
+                 ntlmssp_state->unicode, 0, "");
+
+       {
+               const char *gen_string;
+               if (ntlmssp_state->unicode) {
+                       gen_string = "CdUdbddB";
+               } else {
+                       gen_string = "CdAdbddB";
+               }
+               
+               msrpc_gen(reply, gen_string,
+                         "NTLMSSP", 
+                         NTLMSSP_CHALLENGE,
+                         target_name,
+                         chal_flags,
+                         cryptkey, 8,
+                         0, 0,
+                         struct_blob.data, struct_blob.length);
+       }
+               
+       data_blob_free(&struct_blob);
+
+       return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state, 
+                     DATA_BLOB request, DATA_BLOB *reply) 
+{
+       char *workgroup = NULL, *user = NULL, *machine = NULL;
+       DATA_BLOB lmhash, nthash, sess_key;
+       DATA_BLOB plaintext_password = data_blob(NULL, 0);
+       uint32 ntlmssp_command, neg_flags;
+       NTSTATUS nt_status;
+       uint32 auth_flags = AUTH_FLAG_NONE;
+       auth_usersupplied_info *user_info = NULL;
+
+       const char *parse_string;
+
+       /* parse the NTLMSSP packet */
+#if 0
+       file_save("ntlmssp_auth.dat", request.data, request.length);
+#endif
+
+       if (ntlmssp_state->unicode) {
+               parse_string = "CdBBUUUBd";
+       } else {
+               parse_string = "CdBBAAABd";
+       }
+
+       /* now the NTLMSSP encoded auth hashes */
+       if (!msrpc_parse(&request, parse_string,
+                        "NTLMSSP", 
+                        &ntlmssp_command, 
+                        &lmhash,
+                        &nthash,
+                        &workgroup, 
+                        &user, 
+                        &machine,
+                        &sess_key,
+                        &neg_flags)) {
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       data_blob_free(&sess_key);
+       
+       DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
+                user, workgroup, machine, lmhash.length, nthash.length));
+
+       /* 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(machine);
+
+       /* setup the string used by %U */
+       sub_set_smb_name(user);
+
+       reload_services(True);
+
+#if 0
+       file_save("nthash1.dat", nthash.data, nthash.length);
+       file_save("lmhash1.dat", lmhash.data, lmhash.length);
+#endif
+
+       if (lmhash.length) {
+               auth_flags |= AUTH_FLAG_LM_RESP;
+       }
+
+       if (nthash.length == 24) {
+               auth_flags |= AUTH_FLAG_NTLM_RESP;
+       } else if (nthash.length > 24) {
+               auth_flags |= AUTH_FLAG_NTLMv2_RESP;
+       };
+
+       
+
+       nt_status = make_user_info_map(&user_info, user, workgroup, machine, 
+                                      lmhash, nthash, plaintext_password, 
+                                      auth_flags, True);
+
+       ntlmssp_state->orig_user = talloc_strdup(ntlmssp_state->mem_ctx, user);
+       ntlmssp_state->orig_domain = talloc_strdup(ntlmssp_state->mem_ctx, workgroup);
+
+       SAFE_FREE(user);
+       SAFE_FREE(workgroup);
+       SAFE_FREE(machine);
+
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
+       }
+
+       nt_status = ntlmssp_state->auth_context->check_ntlm_password(ntlmssp_state->auth_context, user_info, &ntlmssp_state->server_info); 
+                       
+       (ntlmssp_state->auth_context->free)(&ntlmssp_state->auth_context);
+
+       free_user_info(&user_info);
+       
+       data_blob_free(&lmhash);
+       
+       data_blob_free(&nthash);
+
+       *reply = data_blob(NULL, 0);
+
+       return nt_status;
+}
index 29580a919229a370fff5301a4990bcaa9c1c0330..160d5bb8e5ff623416fc2626af65a5c642783877 100644 (file)
@@ -754,6 +754,8 @@ extern int errno;
 #include "md5.h"
 #include "hmacmd5.h"
 
+#include "ntlmssp.h"
+
 #include "auth.h"
 
 #include "passdb.h"
diff --git a/source3/include/ntlmssp.h b/source3/include/ntlmssp.h
new file mode 100644 (file)
index 0000000..673be83
--- /dev/null
@@ -0,0 +1,79 @@
+/* 
+   Unix SMB/CIFS implementation.
+   SMB parameters and setup
+   Copyright (C) Andrew Tridgell 1992-1997
+   Copyright (C) Luke Kenneth Casson Leighton 1996-1997
+   Copyright (C) Paul Ashton 1997
+   
+   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.
+*/
+
+/* NTLMSSP mode */
+enum NTLMSSP_ROLE
+{
+       NTLMSSP_SERVER,
+       NTLMSSP_CLIENT
+};
+
+/* NTLMSSP message types */
+enum NTLM_MESSAGE_TYPE
+{
+       NTLMSSP_NEGOTIATE = 1,
+       NTLMSSP_CHALLENGE = 2,
+       NTLMSSP_AUTH      = 3,
+       NTLMSSP_UNKNOWN   = 4
+};
+
+/* NTLMSSP negotiation flags */
+#define NTLMSSP_NEGOTIATE_UNICODE          0x00000001
+#define NTLMSSP_NEGOTIATE_OEM              0x00000002
+#define NTLMSSP_REQUEST_TARGET             0x00000004
+#define NTLMSSP_NEGOTIATE_SIGN             0x00000010 /* Message integrity */
+#define NTLMSSP_NEGOTIATE_SEAL             0x00000020 /* Message confidentiality */
+#define NTLMSSP_NEGOTIATE_DATAGRAM_STYLE   0x00000040
+#define NTLMSSP_NEGOTIATE_LM_KEY           0x00000080
+#define NTLMSSP_NEGOTIATE_NETWARE          0x00000100
+#define NTLMSSP_NEGOTIATE_NTLM             0x00000200
+#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED  0x00001000
+#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000
+#define NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL  0x00004000
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN      0x00008000
+#define NTLMSSP_TARGET_TYPE_DOMAIN            0x10000
+#define NTLMSSP_TARGET_TYPE_SERVER            0x20000
+#define NTLMSSP_CHAL_INIT_RESPONSE         0x00010000
+
+#define NTLMSSP_CHAL_ACCEPT_RESPONSE       0x00020000
+#define NTLMSSP_CHAL_NON_NT_SESSION_KEY    0x00040000
+#define NTLMSSP_NEGOTIATE_NTLM2            0x00080000
+#define NTLMSSP_CHAL_TARGET_INFO           0x00800000
+#define NTLMSSP_NEGOTIATE_128              0x20000000 /* 128-bit encryption */
+#define NTLMSSP_NEGOTIATE_KEY_EXCH         0x40000000
+#define NTLMSSP_NEGOTIATE_080000000        0x80000000
+
+#define NTLMSSP_NAME_TYPE_DOMAIN      0x01
+#define NTLMSSP_NAME_TYPE_SERVER      0x02
+#define NTLMSSP_NAME_TYPE_DOMAIN_DNS  0x03
+#define NTLMSSP_NAME_TYPE_SERVER_DNS  0x04
+
+typedef struct ntlmssp_state 
+{
+       TALLOC_CTX *mem_ctx;
+       enum NTLMSSP_ROLE role;
+       struct auth_context *auth_context;
+       struct auth_serversupplied_info *server_info;
+       BOOL unicode;
+       char *orig_user;
+       char *orig_domain;
+} NTLMSSP_STATE;
index 031f7de6d730cd95ba59f6a53e02bbf0abfe20b7..6a8c6506509698b02ee026bf38dd61087e71d55f 100644 (file)
@@ -46,38 +46,6 @@ enum RPC_PKT_TYPE
 #define RPC_FLG_LAST  0x02
 #define RPC_FLG_NOCALL 0x20
 
-/* NTLMSSP message types */
-enum NTLM_MESSAGE_TYPE
-{
-       NTLMSSP_NEGOTIATE = 1,
-       NTLMSSP_CHALLENGE = 2,
-       NTLMSSP_AUTH      = 3,
-       NTLMSSP_UNKNOWN   = 4
-};
-
-/* NTLMSSP negotiation flags */
-#define NTLMSSP_NEGOTIATE_UNICODE          0x00000001
-#define NTLMSSP_NEGOTIATE_OEM              0x00000002
-#define NTLMSSP_REQUEST_TARGET             0x00000004
-#define NTLMSSP_NEGOTIATE_SIGN             0x00000010 /* Message integrity */
-#define NTLMSSP_NEGOTIATE_SEAL             0x00000020 /* Message confidentiality */
-#define NTLMSSP_NEGOTIATE_DATAGRAM_STYLE   0x00000040
-#define NTLMSSP_NEGOTIATE_LM_KEY           0x00000080
-#define NTLMSSP_NEGOTIATE_NETWARE          0x00000100
-#define NTLMSSP_NEGOTIATE_NTLM             0x00000200
-#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED  0x00001000
-#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000
-#define NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL  0x00004000
-#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN      0x00008000
-#define NTLMSSP_CHAL_INIT_RESPONSE         0x00010000
-#define NTLMSSP_CHAL_ACCEPT_RESPONSE       0x00020000
-#define NTLMSSP_CHAL_NON_NT_SESSION_KEY    0x00040000
-#define NTLMSSP_NEGOTIATE_NTLM2            0x00080000
-#define NTLMSSP_CHAL_TARGET_INFO           0x00800000
-#define NTLMSSP_NEGOTIATE_128              0x20000000 /* 128-bit encryption */
-#define NTLMSSP_NEGOTIATE_KEY_EXCH         0x40000000
-#define NTLMSSP_NEGOTIATE_080000000        0x80000000
-
 #define SMBD_NTLMSSP_NEG_FLAGS 0x000082b1 /* ALWAYS_SIGN|NEG_NTLM|NEG_LM|NEG_SEAL|NEG_SIGN|NEG_UNICODE */
 
 /* NTLMSSP signature version */
index b967927871604dbd7b4e0bfc117cb575b7beab56..333d15790526c1d263442d7502bbaad936b9fab5 100644 (file)
@@ -407,7 +407,7 @@ BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
        return !data->has_error && (v == b);
 }
 
-/* check a enumarted value is correct */
+/* write an enumarted value to the stream */
 BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
 {
        if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
index b758af41c46e36393937e81210515b55c016c8a1..cc3aaf92be6f59489d16d5bc16e9734f09908b6a 100644 (file)
@@ -476,8 +476,8 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user,
                  "NTLMSSP",
                  NTLMSSP_NEGOTIATE,
                  neg_flags,
-                 workgroup, strlen(workgroup),
-                 cli->calling.name, strlen(cli->calling.name) + 1);
+                 workgroup, 
+                 cli->calling.name);
        DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n",
                  neg_flags, workgroup, cli->calling.name));
        /* and wrap it in a SPNEGO wrapper */
index 55f49c5987111af4c1e8f1f9eb1fda6691b1a2c0..6a5f6c00ae9b4a91ed69e2b27dcbfe6378c57b8c 100644 (file)
@@ -485,7 +485,7 @@ BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth)
 /*
   generate a minimal SPNEGO NTLMSSP response packet.  Doesn't contain much.
 */
-DATA_BLOB spnego_gen_auth_response(void)
+DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply)
 {
        ASN1_DATA data;
        DATA_BLOB ret;
@@ -495,8 +495,13 @@ DATA_BLOB spnego_gen_auth_response(void)
        asn1_push_tag(&data, ASN1_CONTEXT(1));
        asn1_push_tag(&data, ASN1_SEQUENCE(0));
        asn1_push_tag(&data, ASN1_CONTEXT(0));
-       asn1_write_enumerated(&data, 0);        
+       asn1_write_enumerated(&data, ntlmssp_reply->length ? 1 : 0);
        asn1_pop_tag(&data);
+       if (ntlmssp_reply->length) {
+               asn1_push_tag(&data,ASN1_CONTEXT(2));
+               asn1_write_OctetString(&data, ntlmssp_reply->data, ntlmssp_reply->length);
+               asn1_pop_tag(&data);
+       }
        asn1_pop_tag(&data);
        asn1_pop_tag(&data);
 
@@ -514,8 +519,9 @@ DATA_BLOB spnego_gen_auth_response(void)
   format specifiers are:
 
   U = unicode string (input is unix string)
-  a = address (1 byte type, 1 byte length, unicode string, all inline)
-  A = ASCII string (pointer + length) Actually same as B
+  a = address (input is BOOL unicode, char *unix_string)
+      (1 byte type, 1 byte length, unicode/ASCII string, all inline)
+  A = ASCII string (input is unix string)
   B = data blob (pointer + length)
   b = data blob in header (pointer + length)
   D
@@ -531,6 +537,7 @@ BOOL msrpc_gen(DATA_BLOB *blob,
        uint8 *b;
        int head_size=0, data_size=0;
        int head_ofs, data_ofs;
+       BOOL unicode;
 
        /* first scan the format to work out the header and body size */
        va_start(ap, format);
@@ -541,12 +548,21 @@ BOOL msrpc_gen(DATA_BLOB *blob,
                        head_size += 8;
                        data_size += str_charnum(s) * 2;
                        break;
+               case 'A':
+                       s = va_arg(ap, char *);
+                       head_size += 8;
+                       data_size += str_ascii_charnum(s);
+                       break;
                case 'a':
+                       unicode = va_arg(ap, BOOL);
                        n = va_arg(ap, int);
                        s = va_arg(ap, char *);
-                       data_size += (str_charnum(s) * 2) + 4;
+                       if (unicode) {
+                               data_size += (str_charnum(s) * 2) + 4;
+                       } else {
+                               data_size += (str_ascii_charnum(s)) + 4;
+                       }
                        break;
-               case 'A':
                case 'B':
                        b = va_arg(ap, uint8 *);
                        head_size += 8;
@@ -586,20 +602,39 @@ BOOL msrpc_gen(DATA_BLOB *blob,
                        push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN);
                        data_ofs += n*2;
                        break;
+               case 'A':
+                       s = va_arg(ap, char *);
+                       n = str_ascii_charnum(s);
+                       SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+                       SSVAL(blob->data, head_ofs, n); head_ofs += 2;
+                       SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4;
+                       push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN);
+                       data_ofs += n;
+                       break;
                case 'a':
+                       unicode = va_arg(ap, BOOL);
                        n = va_arg(ap, int);
                        SSVAL(blob->data, data_ofs, n); data_ofs += 2;
                        s = va_arg(ap, char *);
-                       n = str_charnum(s);
-                       SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
-                       if (0 < n) {
-                               push_string(NULL, blob->data+data_ofs, s, n*2,
-                                           STR_UNICODE|STR_NOALIGN);
+                       if (unicode) {
+                               n = str_charnum(s);
+                               SSVAL(blob->data, data_ofs, n*2); data_ofs += 2;
+                               if (0 < n) {
+                                       push_string(NULL, blob->data+data_ofs, s, n*2,
+                                                   STR_UNICODE|STR_NOALIGN);
+                               }
+                               data_ofs += n*2;
+                       } else {
+                               n = str_ascii_charnum(s);
+                               SSVAL(blob->data, data_ofs, n); data_ofs += 2;
+                               if (0 < n) {
+                                       push_string(NULL, blob->data+data_ofs, s, n,
+                                                   STR_ASCII|STR_NOALIGN);
+                               }
+                               data_ofs += n;
                        }
-                       data_ofs += n*2;
                        break;
 
-               case 'A':
                case 'B':
                        b = va_arg(ap, uint8 *);
                        n = va_arg(ap, int);
index f689893faba2354b30596e0c525592abf4740596..ed2d5976aa07a6c5b19edfbbce8641ef75c68719 100644 (file)
@@ -23,7 +23,8 @@
 #include "includes.h"
 
 uint32 global_client_caps = 0;
-static struct auth_context *ntlmssp_auth_context = NULL;
+
+static struct ntlmssp_state *global_ntlmssp_state;
 
 /*
   on a logon error possibly map the error to success if "map to guest"
@@ -212,7 +213,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
 send a security blob via a session setup reply
 ****************************************************************************/
 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
-                                DATA_BLOB blob, uint32 errcode)
+                                DATA_BLOB blob, NTSTATUS errcode)
 {
        char *p;
 
@@ -221,7 +222,7 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
        /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
           that we aren't finished yet */
 
-       SIVAL(outbuf, smb_rcls, errcode);
+       SIVAL(outbuf, smb_rcls, NT_STATUS_V(errcode));
        SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
        SSVAL(outbuf, smb_vwv3, blob.length);
        p = smb_buf(outbuf);
@@ -235,6 +236,42 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
        return send_smb(smbd_server_fd(),outbuf);
 }
 
+static BOOL reply_spnego_ntlmssp_blob(connection_struct *conn, char *outbuf,
+                                        DATA_BLOB *ntlmssp_blob, NTSTATUS errcode) 
+{
+       DATA_BLOB response;
+        response = spnego_gen_auth_response(ntlmssp_blob);
+       reply_sesssetup_blob(conn, outbuf, response, errcode);
+       data_blob_free(&response);
+       return True;
+}
+
+static BOOL reply_spnego_ntlmssp_ok(connection_struct *conn, char *outbuf,
+                                     NTLMSSP_STATE *ntlmssp_state) 
+{
+       int sess_vuid;
+       DATA_BLOB null_blob = data_blob(NULL, 0);
+
+       sess_vuid = register_vuid(ntlmssp_state->server_info, ntlmssp_state->orig_user /* check this for weird */);
+
+       if (sess_vuid == -1) {
+               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+       }
+
+       set_message(outbuf,4,0,True);
+       SSVAL(outbuf, smb_vwv3, 0);
+
+       if (ntlmssp_state->server_info->guest) {
+               SSVAL(outbuf,smb_vwv2,1);
+       }
+
+       add_signature(outbuf);
+       SSVAL(outbuf,smb_uid,sess_vuid);
+       reply_spnego_ntlmssp_blob(conn, outbuf, &null_blob, NT_STATUS_OK);
+       return True;
+}
+
 /****************************************************************************
 reply to a session setup spnego negotiate packet
 ****************************************************************************/
@@ -247,12 +284,9 @@ static int reply_spnego_negotiate(connection_struct *conn,
        char *OIDs[ASN1_MAX_OIDS];
        DATA_BLOB secblob;
        int i;
-       uint32 ntlmssp_command, neg_flags, chal_flags;
        DATA_BLOB chal, spnego_chal;
-       const uint8 *cryptkey;
        BOOL got_kerberos = False;
        NTSTATUS nt_status;
-       char *cliname=NULL, *domname=NULL;
 
        /* parse out the OIDs and the first sec blob */
        if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
@@ -278,96 +312,54 @@ static int reply_spnego_negotiate(connection_struct *conn,
        }
 #endif
 
-       /* parse the NTLMSSP packet */
-#if 0
-       file_save("secblob.dat", secblob.data, secblob.length);
-#endif
-
-       if (!msrpc_parse(&secblob, "CddAA",
-                        "NTLMSSP",
-                        &ntlmssp_command,
-                        &neg_flags,
-                        &cliname,
-                        &domname)) {
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+       if (global_ntlmssp_state) {
+               ntlmssp_server_end(&global_ntlmssp_state);
        }
-       
-       data_blob_free(&secblob);
 
-       if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+       nt_status = ntlmssp_server_start(&global_ntlmssp_state);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return ERROR_NT(nt_status);
        }
 
-       debug_ntlmssp_flags(neg_flags);
+       nt_status = ntlmssp_server_update(global_ntlmssp_state, 
+                                         secblob, &chal);
 
-       if (ntlmssp_auth_context) {
-               (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
-       }
+       data_blob_free(&secblob);
 
-       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&ntlmssp_auth_context))) {
-               return ERROR_NT(nt_status);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               nt_status = do_map_to_guest(nt_status, 
+                                           &global_ntlmssp_state->server_info, 
+                                           global_ntlmssp_state->orig_user, 
+                                           global_ntlmssp_state->orig_domain);
        }
-
-       cryptkey = ntlmssp_auth_context->get_ntlm_challenge(ntlmssp_auth_context);
-
-       /* Give them the challenge. For now, ignore neg_flags and just
-          return the flags we want. Obviously this is not correct */
        
-       chal_flags = NTLMSSP_NEGOTIATE_UNICODE | 
-               NTLMSSP_NEGOTIATE_128 | 
-               NTLMSSP_NEGOTIATE_NTLM |
-               NTLMSSP_CHAL_TARGET_INFO;
-       
-       {
-               DATA_BLOB domain_blob, struct_blob;
-               fstring dnsname, dnsdomname;
+       if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               if (!spnego_gen_challenge(&spnego_chal, &chal, NULL)) {
+                       DEBUG(3,("Failed to generate challenge\n"));
+                       data_blob_free(&chal);
+                       return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+               }
+
+               /* now tell the client to send the auth packet */
+               reply_sesssetup_blob(conn, outbuf, spnego_chal, nt_status);
                
-               msrpc_gen(&domain_blob, 
-                         "U",
-                         lp_workgroup());
-
-               fstrcpy(dnsdomname, (SEC_ADS == lp_security())?lp_realm():"");
-               strlower(dnsdomname);
-
-               fstrcpy(dnsname, global_myname());
-               fstrcat(dnsname, ".");
-               fstrcat(dnsname, dnsdomname);
-               strlower(dnsname);
-
-               msrpc_gen(&struct_blob, "aaaaa",
-                         2, lp_workgroup(),
-                         1, global_myname(),
-                         4, dnsdomname,
-                         3, dnsname,
-                         0, "");
-
-               msrpc_gen(&chal, "CdUdbddB",
-                         "NTLMSSP", 
-                         NTLMSSP_CHALLENGE,
-                         lp_workgroup(),
-                         chal_flags,
-                         cryptkey, 8,
-                         0, 0,
-                         struct_blob.data, struct_blob.length);
-
-               data_blob_free(&domain_blob);
-               data_blob_free(&struct_blob);
-       }
-
-       if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) {
-               DEBUG(3,("Failed to generate challenge\n"));
                data_blob_free(&chal);
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-       }
+               data_blob_free(&spnego_chal);
 
-       /* now tell the client to send the auth packet */
-       reply_sesssetup_blob(conn, outbuf, spnego_chal, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
+               /* and tell smbd that we have already replied to this packet */
+               return -1;
 
-       data_blob_free(&chal);
-       data_blob_free(&spnego_chal);
+       } else if (NT_STATUS_IS_OK(nt_status)) {
+               reply_spnego_ntlmssp_ok(conn, outbuf, 
+                                                global_ntlmssp_state);
+               ntlmssp_server_end(&global_ntlmssp_state);
 
-       /* and tell smbd that we have already replied to this packet */
-       return -1;
+               data_blob_free(&chal);
+               /* and tell smbd that we have already replied to this packet */
+               return -1;
+       } 
+
+       return ERROR_NT(nt_status_squash(nt_status));
 }
 
        
@@ -378,23 +370,8 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
                             int length, int bufsize,
                             DATA_BLOB blob1)
 {
-       DATA_BLOB auth, response;
-       char *workgroup = NULL, *user = NULL, *machine = NULL;
-       DATA_BLOB lmhash, nthash, sess_key;
-       DATA_BLOB plaintext_password = data_blob(NULL, 0);
-       uint32 ntlmssp_command, neg_flags;
+       DATA_BLOB auth, auth_reply;
        NTSTATUS nt_status;
-       int sess_vuid;
-       BOOL as_guest;
-       uint32 auth_flags = AUTH_FLAG_NONE;
-       auth_usersupplied_info *user_info = NULL;
-       auth_serversupplied_info *server_info = NULL;
-
-       /* we must have setup the auth context by now */
-       if (!ntlmssp_auth_context) {
-               DEBUG(2,("ntlmssp_auth_context is NULL in reply_spnego_auth\n"));
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-       }
 
        if (!spnego_parse_auth(blob1, &auth)) {
 #if 0
@@ -403,108 +380,21 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
-       /* now the NTLMSSP encoded auth hashes */
-       if (!msrpc_parse(&auth, "CdBBUUUBd", 
-                        "NTLMSSP", 
-                        &ntlmssp_command, 
-                        &lmhash,
-                        &nthash,
-                        &workgroup, 
-                        &user, 
-                        &machine,
-                        &sess_key,
-                        &neg_flags)) {
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-       }
+       nt_status = ntlmssp_server_update(global_ntlmssp_state, 
+                                         auth, &auth_reply);
 
        data_blob_free(&auth);
-       data_blob_free(&sess_key);
-       
-       DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
-                user, workgroup, machine, lmhash.length, nthash.length));
-
-       /* 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(machine);
-
-       /* setup the string used by %U */
-       sub_set_smb_name(user);
-
-       reload_services(True);
+       data_blob_free(&auth_reply);
 
-#if 0
-       file_save("nthash1.dat", nthash.data, nthash.length);
-       file_save("lmhash1.dat", lmhash.data, lmhash.length);
-#endif
-
-       if (lmhash.length) {
-               auth_flags |= AUTH_FLAG_LM_RESP;
-       }
+       if (NT_STATUS_IS_OK(nt_status)) {
+               reply_spnego_ntlmssp_ok(conn, outbuf, 
+                                       global_ntlmssp_state);
+               ntlmssp_server_end(&global_ntlmssp_state);
 
-       if (nthash.length == 24) {
-               auth_flags |= AUTH_FLAG_NTLM_RESP;
-       } else if (nthash.length > 24) {
-               auth_flags |= AUTH_FLAG_NTLMv2_RESP;
-       };
-
-       nt_status = make_user_info_map(&user_info, user, workgroup, machine, 
-                                      lmhash, nthash, plaintext_password, 
-                                      auth_flags, True);
-
-       /* it looks a bit weird, but this function returns int type... */
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               return ERROR_NT(NT_STATUS_NO_MEMORY);
-       }
-
-       nt_status = ntlmssp_auth_context->check_ntlm_password(ntlmssp_auth_context, user_info, &server_info); 
-
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup);
-       }
-
-       SAFE_FREE(workgroup);
-       SAFE_FREE(machine);
-                       
-       (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
-
-       free_user_info(&user_info);
-       
-       data_blob_free(&lmhash);
-       
-       data_blob_free(&nthash);
-
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               SAFE_FREE(user);
+       } else { /* !NT_STATUS_IS_OK(nt_status) */
                return ERROR_NT(nt_status_squash(nt_status));
        }
 
-       as_guest = server_info->guest;
-
-       sess_vuid = register_vuid(server_info, user);
-       free_server_info(&server_info);
-
-       SAFE_FREE(user);
-  
-       if (sess_vuid == -1) {
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-       }
-
-       set_message(outbuf,4,0,True);
-       SSVAL(outbuf, smb_vwv3, 0);
-
-       if (as_guest) {
-               SSVAL(outbuf,smb_vwv2,1);
-       }
-
-       add_signature(outbuf);
-       SSVAL(outbuf,smb_uid,sess_vuid);
-       SSVAL(inbuf,smb_uid,sess_vuid);
-
-        response = spnego_gen_auth_response();
-       reply_sesssetup_blob(conn, outbuf, response, 0);
-
        /* and tell smbd that we have already replied to this packet */
        return -1;
 }
@@ -786,6 +676,10 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                nt_status = check_guest_password(&server_info);
 
        } else if (doencrypt) {
+               if (!negprot_global_auth_context) {
+                       DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
+                       return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+               }
                nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
                                                         lm_resp, nt_resp);
                if (NT_STATUS_IS_OK(nt_status)) {