signed DCERPC over TCP now works !
authorAndrew Tridgell <tridge@samba.org>
Wed, 26 Nov 2003 01:16:41 +0000 (01:16 +0000)
committerAndrew Tridgell <tridge@samba.org>
Wed, 26 Nov 2003 01:16:41 +0000 (01:16 +0000)
 * moved ntlmssp code into libcli/auth/, and updated to latest ntlmssp
   code from samba3 (thanks Andrew! the new interface is great)

 * added signing/ntlmssp support in the dcerpc code

 * added a dcerpc_auth.c module for the various dcerpc auth mechanisms
(This used to be commit c18c9b5585a3e5f7868562820c14f7cb529cdbcd)

25 files changed:
source4/Makefile.in
source4/auth/auth_sam.c
source4/include/includes.h
source4/lib/crc32.c
source4/lib/crypto/crc32.c
source4/lib/data_blob.c
source4/lib/replace.c
source4/lib/util.c
source4/libcli/auth/ntlmssp.c [new file with mode: 0644]
source4/libcli/auth/ntlmssp.h [moved from source4/include/ntlmssp.h with 52% similarity]
source4/libcli/auth/ntlmssp_parse.c [moved from source4/libcli/ntlmssp_parse.c with 80% similarity]
source4/libcli/auth/ntlmssp_sign.c [new file with mode: 0644]
source4/libcli/ntlmssp.c [deleted file]
source4/libcli/util/ntlmssp_sign.c [deleted file]
source4/libcli/util/smbencrypt.c
source4/librpc/idl/dcerpc.idl
source4/librpc/ndr/ndr.c
source4/librpc/ndr/ndr_basic.c
source4/librpc/rpc/dcerpc.c
source4/librpc/rpc/dcerpc.h
source4/librpc/rpc/dcerpc_auth.c [new file with mode: 0644]
source4/librpc/rpc/dcerpc_smb.c
source4/librpc/rpc/dcerpc_tcp.c
source4/torture/rpc/epmapper.c
source4/torture/torture.c

index 35ef305db5864cc4873727f41245f1c9ab67ce61..4f7b20837c6fbf42c63b20845c4a520c2c108eac 100644 (file)
@@ -1,6 +1,6 @@
 #########################################################################
 # Makefile.in for Samba - rewritten for autoconf support
-# Copyright Andrew Tridgell 1992-1998
+# Copyright Andrew Tridgell 1992-2003
 # Copyright (C) 2001 by Martin Pool <mbp@samba.org>
 # Copyright (C) 2002 Andrew Bartlett <abartlet@samba.org>
 # Copyright (C) 2003 Anthony Liguori <aliguor@us.ibm.com>
@@ -179,7 +179,7 @@ SECRETS_OBJ = passdb/secrets.o
 LIBNMB_OBJ = libcli/unexpected.o libcli/namecache.o libcli/nmblib.o \
             libcli/namequery.o 
 
-LIBNTLMSSP_OBJ = libcli/ntlmssp.o libcli/ntlmssp_parse.o libcli/util/ntlmssp_sign.o
+LIBNTLMSSP_OBJ = libcli/auth/ntlmssp.o libcli/auth/ntlmssp_parse.o libcli/auth/ntlmssp_sign.o
 
 LIBSAMBA_OBJ = libcli/util/nterr.o libcli/util/smbdes.o libcli/util/smbencrypt.o
 
@@ -199,7 +199,7 @@ LIBRAW_NDR_OBJ = librpc/ndr/ndr.o librpc/ndr/ndr_basic.o librpc/ndr/ndr_sec.o \
                librpc/gen_ndr/ndr_epmapper.o librpc/gen_ndr/ndr_winreg.o \
                librpc/gen_ndr/ndr_mgmt.o
 
-LIBRAW_RPC_OBJ = librpc/rpc/dcerpc.o \
+LIBRAW_RPC_OBJ = librpc/rpc/dcerpc.o librpc/rpc/dcerpc_auth.o \
                librpc/rpc/dcerpc_smb.o librpc/rpc/dcerpc_tcp.o \
                librpc/gen_rpc/rpc_echo.o librpc/gen_rpc/rpc_lsa.o \
                librpc/gen_rpc/rpc_dfs.o librpc/gen_rpc/rpc_spoolss.o \
@@ -261,8 +261,6 @@ AUTH_OBJ = auth/auth.o auth/auth_sam.o \
           auth/auth_builtin.o auth/auth_compat.o \
           $(PLAINTEXT_AUTH_OBJ) $(UNIGRP_OBJ)
 
-# auth/auth_server.o auth/auth_domain.o auth/auth_winbind.o auth/auth_ntlmssp.o 
-
 MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o
 
 SMBD_OBJ_MAIN = smbd/server.o
index 1d097c94ef482e70f772f1ac998dab798f683637..51462555f9ba8892808320cdfe244a60c754550c 100644 (file)
@@ -118,7 +118,7 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response,
                return False;
        }
 
-       SMBOWFencrypt_ntv2(kr, sec_blob, client_key_data, value_from_encryption);
+       SMBOWFencrypt_ntv2(kr, &sec_blob, &client_key_data, value_from_encryption);
        if (user_sess_key != NULL)
        {
                SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key);
index 908d2a4e76cc0566410c938d97598fb8a1db92a2..2b4eff6eb415414ba377cd50a94d5cfbbd665fb2 100644 (file)
@@ -756,7 +756,7 @@ extern int errno;
 #include "md5.h"
 #include "hmacmd5.h"
 
-#include "ntlmssp.h"
+#include "libcli/auth/ntlmssp.h"
 
 #include "auth.h"
 #include "passdb.h"
index 86b0bb6fd9d8843ba902d777285dede14ebe2acf..da3aeaa901d5236456a271d9ed57183427a35c23 100644 (file)
@@ -1,71 +1,67 @@
 /* 
-   Unix SMB/CIFS implementation.
-   crc32 implementation
-   Copyright (C) Andrew Tridgell 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.
-*/
+ * Copyright Francesco Ferrara, 1998 <francesco@aerra.it> 
+ *
+ * Used by kind permission, 14th October 1998. http://www.aerre.it/francesco
+ *
+ *
+ */
 
 #include "includes.h"
 
-/* table generated using algorithm from Mark Adler */
-static const uint32 crc_table[] = {
-       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 
-       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 
-       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 
-       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 
-       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 
-       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 
-       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 
-       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 
-       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 
-       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 
-       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 
-       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 
-       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 
-       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 
-       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 
-       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 
-       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 
-       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 
-       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 
-       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 
-       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 
-       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 
-       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 
-       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 
-       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 
-       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 
-       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 
-       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 
-       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 
-       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 
-       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 
-       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+static const unsigned long CRCTable[256] = 
+{
+        0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,
+        0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,
+        0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,
+        0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
+        0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,
+        0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,
+        0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,
+        0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
+        0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,
+        0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,
+        0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,0x76DC4190,0x01DB7106,
+        0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
+        0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,
+        0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,
+        0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,
+        0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
+        0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,
+        0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,
+        0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,0x5005713C,0x270241AA,
+        0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
+        0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,
+        0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,
+        0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,
+        0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
+        0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,
+        0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,
+        0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8,0xA1D1937E,
+        0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
+        0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,
+        0x316E8EEF,0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,
+        0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,
+        0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
+        0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,
+        0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,
+        0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242,
+        0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
+        0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,
+        0x616BFFD3,0x166CCF45,0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,
+        0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,
+        0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
+        0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,
+        0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,
+        0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D
 };
 
-
-/*
-  see PNG specification or ISO-3309 for details
-*/
-uint32 crc32_buffer(const uint8 *buf, int n)
+uint32 crc32_calc_buffer( const char *buffer, uint32 count)
 {
-       int i;
-       uint32 ret;
-       for (ret=~0, i=0;i<n; i++) {
-               ret = crc_table[0xff & (buf[i] ^ ret)] ^ (ret >> 8);
-       }
-       return ~ret;
+       uint32 crc=0xffffffff, i;
+        for(i=0;i<count;i++)
+                crc = (crc>>8) ^ CRCTable[(buffer[i] ^ crc) & 0xff];
+        crc^=0xffffffff;
+       DEBUG(10,("crc32_calc_buffer: %x\n", crc));
+       dump_data(100, buffer, count);
+        return crc;
 }
index 86b0bb6fd9d8843ba902d777285dede14ebe2acf..da3aeaa901d5236456a271d9ed57183427a35c23 100644 (file)
@@ -1,71 +1,67 @@
 /* 
-   Unix SMB/CIFS implementation.
-   crc32 implementation
-   Copyright (C) Andrew Tridgell 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.
-*/
+ * Copyright Francesco Ferrara, 1998 <francesco@aerra.it> 
+ *
+ * Used by kind permission, 14th October 1998. http://www.aerre.it/francesco
+ *
+ *
+ */
 
 #include "includes.h"
 
-/* table generated using algorithm from Mark Adler */
-static const uint32 crc_table[] = {
-       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 
-       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 
-       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 
-       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 
-       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 
-       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 
-       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 
-       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 
-       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 
-       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 
-       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 
-       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 
-       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 
-       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 
-       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 
-       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 
-       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 
-       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 
-       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 
-       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 
-       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 
-       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 
-       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 
-       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 
-       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 
-       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 
-       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 
-       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 
-       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 
-       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 
-       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 
-       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+static const unsigned long CRCTable[256] = 
+{
+        0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,
+        0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,
+        0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,0x1DB71064,0x6AB020F2,
+        0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,
+        0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,
+        0xFA0F3D63,0x8D080DF5,0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,
+        0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,
+        0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
+        0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,
+        0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,
+        0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,0x76DC4190,0x01DB7106,
+        0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,
+        0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,
+        0x91646C97,0xE6635C01,0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,
+        0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,
+        0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
+        0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,
+        0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,
+        0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,0x5005713C,0x270241AA,
+        0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,
+        0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,
+        0xB7BD5C3B,0xC0BA6CAD,0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,
+        0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,
+        0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
+        0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,
+        0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,
+        0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,0xD6D6A3E8,0xA1D1937E,
+        0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,
+        0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,
+        0x316E8EEF,0x4669BE79,0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,
+        0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,
+        0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
+        0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,
+        0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,
+        0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,0x86D3D2D4,0xF1D4E242,
+        0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,
+        0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,
+        0x616BFFD3,0x166CCF45,0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,
+        0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,
+        0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
+        0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,
+        0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,
+        0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D
 };
 
-
-/*
-  see PNG specification or ISO-3309 for details
-*/
-uint32 crc32_buffer(const uint8 *buf, int n)
+uint32 crc32_calc_buffer( const char *buffer, uint32 count)
 {
-       int i;
-       uint32 ret;
-       for (ret=~0, i=0;i<n; i++) {
-               ret = crc_table[0xff & (buf[i] ^ ret)] ^ (ret >> 8);
-       }
-       return ~ret;
+       uint32 crc=0xffffffff, i;
+        for(i=0;i<count;i++)
+                crc = (crc>>8) ^ CRCTable[(buffer[i] ^ crc) & 0xff];
+        crc^=0xffffffff;
+       DEBUG(10,("crc32_calc_buffer: %x\n", crc));
+       dump_data(100, buffer, count);
+        return crc;
 }
index 8e7df52bef15f07148a6c8e7bcb695d8355589db..d51cffbca46858f2140fb9c9f2b4f0fdad82d003 100644 (file)
@@ -91,6 +91,8 @@ free a data blob
 *******************************************************************/
 void data_blob_free(DATA_BLOB *d)
 {
+       return;
+
        if (d) {
                if (d->free) {
                        (d->free)(d);
index cda379c63f3b689ff0ba4230d06cbdf03e3c7766..63e6a71149794e258046e57e1b5716a9765b7906 100644 (file)
@@ -465,3 +465,8 @@ char *rep_inet_ntoa(struct in_addr ip)
        return ret;     
 }
 #endif
+
+const char *global_myname(void)
+{
+       return lp_netbios_name();
+}
index c9c38ddd33bd671280625cc3d40a1b964e53b9ad..9b6cef8bfe2b7351b0571bc056dd5b6e7a687696 100644 (file)
@@ -998,3 +998,14 @@ static BOOL unix_do_match(char *regexp, char *str)
 
        return False;
 }
+
+void dump_data_pw(const char *msg, const uchar * data, size_t len)
+{
+#ifdef DEBUG_PASSWORD
+       DEBUG(11, ("%s", msg));
+       if (data != NULL && len > 0)
+       {
+               dump_data(11, data, len);
+       }
+#endif
+}
diff --git a/source4/libcli/auth/ntlmssp.c b/source4/libcli/auth/ntlmssp.c
new file mode 100644 (file)
index 0000000..9ee71a2
--- /dev/null
@@ -0,0 +1,1055 @@
+/* 
+   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"
+
+static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, 
+                                      DATA_BLOB reply, DATA_BLOB *next_request);
+static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
+                                        const DATA_BLOB in, DATA_BLOB *out);
+static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, 
+                                        const DATA_BLOB reply, DATA_BLOB *next_request);
+static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
+                                   const DATA_BLOB request, DATA_BLOB *reply);
+
+/**
+ * Callbacks for NTLMSSP - for both client and server operating modes
+ * 
+ */
+
+static const struct ntlmssp_callbacks {
+       enum NTLMSSP_ROLE role;
+       enum NTLM_MESSAGE_TYPE ntlmssp_command;
+       NTSTATUS (*fn)(struct ntlmssp_state *ntlmssp_state, 
+                      DATA_BLOB in, DATA_BLOB *out);
+} ntlmssp_callbacks[] = {
+       {NTLMSSP_CLIENT, NTLMSSP_INITIAL, ntlmssp_client_initial},
+       {NTLMSSP_SERVER, NTLMSSP_NEGOTIATE, ntlmssp_server_negotiate},
+       {NTLMSSP_CLIENT, NTLMSSP_CHALLENGE, ntlmssp_client_challenge},
+       {NTLMSSP_SERVER, NTLMSSP_AUTH, ntlmssp_server_auth},
+       {NTLMSSP_CLIENT, NTLMSSP_UNKNOWN, NULL},
+       {NTLMSSP_SERVER, NTLMSSP_UNKNOWN, NULL}
+};
+
+
+/**
+ * Print out the NTLMSSP flags for debugging 
+ * @param neg_flags The flags from the packet
+ */
+
+void debug_ntlmssp_flags(uint32 neg_flags)
+{
+       DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags));
+       
+       if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_UNICODE\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_OEM) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_OEM\n"));
+       if (neg_flags & NTLMSSP_REQUEST_TARGET) 
+               DEBUGADD(4, ("  NTLMSSP_REQUEST_TARGET\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_SIGN) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_SIGN\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_SEAL) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_SEAL\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_LM_KEY\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NETWARE\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_NTLM) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NTLM\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NTLM2\n"));
+       if (neg_flags & NTLMSSP_CHAL_TARGET_INFO) 
+               DEBUGADD(4, ("  NTLMSSP_CHAL_TARGET_INFO\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_128) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_128\n"));
+       if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) 
+               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
+}
+
+/**
+ * Default challenge generation code.
+ *
+ */
+   
+static const uint8 *get_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+       static uchar chal[8];
+       generate_random_buffer(chal, sizeof(chal), False);
+
+       return chal;
+}
+
+/**
+ * Default 'we can set the challenge to anything we like' implementation
+ *
+ */
+   
+static BOOL may_set_challenge(const struct ntlmssp_state *ntlmssp_state)
+{
+       return True;
+}
+
+/**
+ * Default 'we can set the challenge to anything we like' implementation
+ *
+ * Does not actually do anything, as the value is always in the structure anyway.
+ *
+ */
+   
+static NTSTATUS set_challenge(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge)
+{
+       SMB_ASSERT(challenge->length == 8);
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set a username on an NTLMSSP context - ensures it is talloc()ed 
+ *
+ */
+
+NTSTATUS ntlmssp_set_username(NTLMSSP_STATE *ntlmssp_state, const char *user) 
+{
+       ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user);
+       if (!ntlmssp_state->user) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set a password on an NTLMSSP context - ensures it is talloc()ed 
+ *
+ */
+NTSTATUS ntlmssp_set_password(NTLMSSP_STATE *ntlmssp_state, const char *password) 
+{
+       if (!password) {
+               ntlmssp_state->password = NULL;
+       } else {
+               ntlmssp_state->password = talloc_strdup(ntlmssp_state->mem_ctx, password);
+               if (!ntlmssp_state->password) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set a domain on an NTLMSSP context - ensures it is talloc()ed 
+ *
+ */
+NTSTATUS ntlmssp_set_domain(NTLMSSP_STATE *ntlmssp_state, const char *domain) 
+{
+       ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain);
+       if (!ntlmssp_state->domain) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
+/** 
+ * Set a workstation on an NTLMSSP context - ensures it is talloc()ed 
+ *
+ */
+NTSTATUS ntlmssp_set_workstation(NTLMSSP_STATE *ntlmssp_state, const char *workstation) 
+{
+       ntlmssp_state->workstation = talloc_strdup(ntlmssp_state->mem_ctx, workstation);
+       if (!ntlmssp_state->domain) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       return NT_STATUS_OK;
+}
+
+/**
+ *  Store a DATA_BLOB containing an NTLMSSP response, for use later.
+ *  This copies the data blob
+ */
+
+NTSTATUS ntlmssp_store_response(NTLMSSP_STATE *ntlmssp_state,
+                               DATA_BLOB response) 
+{
+       ntlmssp_state->stored_response = data_blob_talloc(ntlmssp_state->mem_ctx, 
+                                                         response.data, response.length);
+       return NT_STATUS_OK;
+}
+
+/**
+ * Next state function for the NTLMSSP state machine
+ * 
+ * @param ntlmssp_state NTLMSSP State
+ * @param in The packet in from the NTLMSSP partner, as a DATA_BLOB
+ * @param out The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK. 
+ */
+
+NTSTATUS ntlmssp_update(NTLMSSP_STATE *ntlmssp_state, 
+                       const DATA_BLOB in, DATA_BLOB *out) 
+{
+       DATA_BLOB input;
+       uint32 ntlmssp_command;
+       int i;
+
+       *out = data_blob(NULL, 0);
+
+       if (!in.length && ntlmssp_state->stored_response.length) {
+               input = ntlmssp_state->stored_response;
+               
+               /* we only want to read the stored response once - overwrite it */
+               ntlmssp_state->stored_response = data_blob(NULL, 0);
+       } else {
+               input = in;
+       }
+
+       if (!input.length) {
+               switch (ntlmssp_state->role) {
+               case NTLMSSP_CLIENT:
+                       ntlmssp_command = NTLMSSP_INITIAL;
+                       break;
+               case NTLMSSP_SERVER:
+                       /* 'datagram' mode - no neg packet */
+                       ntlmssp_command = NTLMSSP_NEGOTIATE;
+                       break;
+               }
+       } else {
+               if (!msrpc_parse(&input, "Cd",
+                                "NTLMSSP",
+                                &ntlmssp_command)) {
+                       DEBUG(1, ("Failed to parse NTLMSSP packet, could not extract NTLMSSP command\n"));
+                       dump_data(2, (const char *)input.data, input.length);
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+       }
+
+       if (ntlmssp_command != ntlmssp_state->expected_state) {
+               DEBUG(1, ("got NTLMSSP command %u, expected %u\n", ntlmssp_command, ntlmssp_state->expected_state));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       for (i=0; ntlmssp_callbacks[i].fn; i++) {
+               if (ntlmssp_callbacks[i].role == ntlmssp_state->role 
+                   && ntlmssp_callbacks[i].ntlmssp_command == ntlmssp_command) {
+                       return ntlmssp_callbacks[i].fn(ntlmssp_state, input, out);
+               }
+       }
+
+       DEBUG(1, ("failed to find NTLMSSP callback for NTLMSSP mode %u, command %u\n", 
+                 ntlmssp_state->role, ntlmssp_command)); 
+
+       return NT_STATUS_INVALID_PARAMETER;
+}
+
+/**
+ * End an NTLMSSP state machine
+ * 
+ * @param ntlmssp_state NTLMSSP State, free()ed by this function
+ */
+
+void ntlmssp_end(NTLMSSP_STATE **ntlmssp_state)
+{
+       TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
+
+       (*ntlmssp_state)->ref_count--;
+
+       if ((*ntlmssp_state)->ref_count == 0) {
+               data_blob_free(&(*ntlmssp_state)->chal);
+               data_blob_free(&(*ntlmssp_state)->lm_resp);
+               data_blob_free(&(*ntlmssp_state)->nt_resp);
+
+               talloc_destroy(mem_ctx);
+       }
+
+       *ntlmssp_state = NULL;
+       return;
+}
+
+/**
+ * Determine correct target name flags for reply, given server role 
+ * and negotiated flags
+ * 
+ * @param ntlmssp_state NTLMSSP State
+ * @param neg_flags The flags from the packet
+ * @param chal_flags The flags to be set in the reply packet
+ * @return The 'target name' string.
+ */
+
+static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state,
+                                      uint32 neg_flags, uint32 *chal_flags) 
+{
+       if (neg_flags & NTLMSSP_REQUEST_TARGET) {
+               *chal_flags |= NTLMSSP_CHAL_TARGET_INFO;
+               *chal_flags |= NTLMSSP_REQUEST_TARGET;
+               if (ntlmssp_state->server_role == ROLE_STANDALONE) {
+                       *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
+                       return ntlmssp_state->get_global_myname();
+               } else {
+                       *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
+                       return ntlmssp_state->get_domain();
+               };
+       } else {
+               return "";
+       }
+}
+
+static void ntlmssp_handle_neg_flags(struct ntlmssp_state *ntlmssp_state,
+                                     uint32 neg_flags, BOOL allow_lm) {
+       if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) {
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
+               ntlmssp_state->unicode = True;
+       } else {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+               ntlmssp_state->unicode = False;
+       }
+
+       if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY && allow_lm) {
+               /* other end forcing us to use LM */
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY;
+               ntlmssp_state->use_ntlmv2 = False;
+       } else {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+       }
+
+       if (!(neg_flags & NTLMSSP_NEGOTIATE_NTLM2)) {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_LM_KEY;
+       }
+
+       if (!(neg_flags & NTLMSSP_NEGOTIATE_128)) {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_128;
+       }
+
+       if (!(neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH)) {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_KEY_EXCH;
+       }
+
+       if ((neg_flags & NTLMSSP_REQUEST_TARGET)) {
+               ntlmssp_state->neg_flags |= NTLMSSP_REQUEST_TARGET;
+       }
+       
+}
+
+
+/**
+ * Next state function for the Negotiate packet
+ * 
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent. 
+ */
+
+static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
+                                        const DATA_BLOB request, DATA_BLOB *reply) 
+{
+       DATA_BLOB struct_blob;
+       fstring dnsname, dnsdomname;
+       uint32 neg_flags = 0;
+       uint32 ntlmssp_command, 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 (request.length) {
+               if (!msrpc_parse(&request, "CddAA",
+                                "NTLMSSP",
+                                &ntlmssp_command,
+                                &neg_flags,
+                                &cliname,
+                                &domname)) {
+                       DEBUG(1, ("ntlmssp_server_negotiate: failed to parse NTLMSSP:\n"));
+                       dump_data(2, (const char *)request.data, request.length);
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+               
+               SAFE_FREE(cliname);
+               SAFE_FREE(domname);
+               
+               debug_ntlmssp_flags(neg_flags);
+       }
+       
+       ntlmssp_handle_neg_flags(ntlmssp_state, neg_flags, lp_lanman_auth());
+
+       chal_flags = ntlmssp_state->neg_flags;
+
+       target_name = ntlmssp_target_name(ntlmssp_state, 
+                                         neg_flags, &chal_flags); 
+       if (target_name == NULL) 
+               return NT_STATUS_INVALID_PARAMETER;
+
+       /* Ask our caller what challenge they would like in the packet */
+       cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
+
+       /* Check if we may set the challenge */
+       if (!ntlmssp_state->may_set_challenge(ntlmssp_state)) {
+               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2;
+       }
+
+       ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
+       ntlmssp_state->internal_chal = data_blob_talloc(ntlmssp_state->mem_ctx, cryptkey, 8);
+       
+
+       /* This should be a 'netbios domain -> DNS domain' mapping */
+       dnsdomname[0] = '\0';
+       get_mydomname(dnsdomname);
+       strlower_m(dnsdomname);
+       
+       dnsname[0] = '\0';
+       get_myfullname(dnsname);
+       strlower_m(dnsname);
+       
+       /* This creates the 'blob' of names that appears at the end of the packet */
+       if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) 
+       {
+               const char *target_name_dns = "";
+               if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) {
+                       target_name_dns = dnsdomname;
+               } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) {
+                       target_name_dns = dnsname;
+               }
+
+               msrpc_gen(&struct_blob, "aaaaa",
+                         NTLMSSP_NAME_TYPE_DOMAIN, target_name,
+                         NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
+                         NTLMSSP_NAME_TYPE_DOMAIN_DNS, dnsdomname,
+                         NTLMSSP_NAME_TYPE_SERVER_DNS, dnsname,
+                         0, "");
+       } else {
+               struct_blob = data_blob(NULL, 0);
+       }
+
+       {
+               /* Marshel the packet in the right format, be it unicode or ASCII */
+               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);
+
+       ntlmssp_state->expected_state = NTLMSSP_AUTH;
+
+       return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/**
+ * Next state function for the Authenticate packet
+ * 
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK. 
+ */
+
+static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
+                                   const DATA_BLOB request, DATA_BLOB *reply) 
+{
+       DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
+       DATA_BLOB nt_session_key = data_blob(NULL, 0);
+       DATA_BLOB lm_session_key = data_blob(NULL, 0);
+       DATA_BLOB session_key = data_blob(NULL, 0);
+       uint32 ntlmssp_command, auth_flags;
+       NTSTATUS nt_status;
+
+       /* used by NTLM2 */
+       BOOL doing_ntlm2 = False;
+
+       uchar session_nonce[16];
+       uchar session_nonce_hash[16];
+
+       const char *parse_string;
+       char *domain = NULL;
+       char *user = NULL;
+       char *workstation = NULL;
+
+       /* parse the NTLMSSP packet */
+       *reply = data_blob(NULL, 0);
+
+#if 0
+       file_save("ntlmssp_auth.dat", request.data, request.length);
+#endif
+
+       if (ntlmssp_state->unicode) {
+               parse_string = "CdBBUUUBd";
+       } else {
+               parse_string = "CdBBAAABd";
+       }
+
+       data_blob_free(&ntlmssp_state->lm_resp);
+       data_blob_free(&ntlmssp_state->nt_resp);
+
+       ntlmssp_state->user = NULL;
+       ntlmssp_state->domain = NULL;
+       ntlmssp_state->workstation = NULL;
+
+       /* now the NTLMSSP encoded auth hashes */
+       if (!msrpc_parse(&request, parse_string,
+                        "NTLMSSP", 
+                        &ntlmssp_command, 
+                        &ntlmssp_state->lm_resp,
+                        &ntlmssp_state->nt_resp,
+                        &domain, 
+                        &user, 
+                        &workstation,
+                        &encrypted_session_key,
+                        &auth_flags)) {
+               DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n"));
+               dump_data(2, (const char *)request.data, request.length);
+               SAFE_FREE(domain);
+               SAFE_FREE(user);
+               SAFE_FREE(workstation);
+               data_blob_free(&encrypted_session_key);
+               auth_flags = 0;
+               
+               /* Try again with a shorter string (Win9X truncates this packet) */
+               if (ntlmssp_state->unicode) {
+                       parse_string = "CdBBUUU";
+               } else {
+                       parse_string = "CdBBAAA";
+               }
+
+               /* now the NTLMSSP encoded auth hashes */
+               if (!msrpc_parse(&request, parse_string,
+                                "NTLMSSP", 
+                                &ntlmssp_command, 
+                                &ntlmssp_state->lm_resp,
+                                &ntlmssp_state->nt_resp,
+                                &domain, 
+                                &user, 
+                                &workstation)) {
+                       DEBUG(1, ("ntlmssp_server_auth: failed to parse NTLMSSP:\n"));
+                       dump_data(2, (const char *)request.data, request.length);
+                       SAFE_FREE(domain);
+                       SAFE_FREE(user);
+                       SAFE_FREE(workstation);
+
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+       }
+
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, domain))) {
+               SAFE_FREE(domain);
+               SAFE_FREE(user);
+               SAFE_FREE(workstation);
+               data_blob_free(&encrypted_session_key);
+               return nt_status;
+       }
+
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, user))) {
+               SAFE_FREE(domain);
+               SAFE_FREE(user);
+               SAFE_FREE(workstation);
+               data_blob_free(&encrypted_session_key);
+               return nt_status;
+       }
+
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_workstation(ntlmssp_state, workstation))) {
+               SAFE_FREE(domain);
+               SAFE_FREE(user);
+               SAFE_FREE(workstation);
+               data_blob_free(&encrypted_session_key);
+               return nt_status;
+       }
+
+       SAFE_FREE(domain);
+       SAFE_FREE(user);
+       SAFE_FREE(workstation);
+
+       DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%lu len2=%lu\n",
+                ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, (unsigned long)ntlmssp_state->lm_resp.length, (unsigned long)ntlmssp_state->nt_resp.length));
+
+#if 0
+       file_save("nthash1.dat",  &ntlmssp_state->nt_resp.data,  &ntlmssp_state->nt_resp.length);
+       file_save("lmhash1.dat",  &ntlmssp_state->lm_resp.data,  &ntlmssp_state->lm_resp.length);
+#endif
+
+       /* NTLM2 uses a 'challenge' that is made of up both the server challenge, and a 
+          client challenge 
+       
+          However, the NTLM2 flag may still be set for the real NTLMv2 logins, be careful.
+       */
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+               if (ntlmssp_state->nt_resp.length == 24 && ntlmssp_state->lm_resp.length == 24) {
+                       struct MD5Context md5_session_nonce_ctx;
+                       SMB_ASSERT(ntlmssp_state->internal_chal.data && ntlmssp_state->internal_chal.length == 8);
+                       
+                       doing_ntlm2 = True;
+
+                       memcpy(session_nonce, ntlmssp_state->internal_chal.data, 8);
+                       memcpy(&session_nonce[8], ntlmssp_state->lm_resp.data, 8);
+                       
+                       MD5Init(&md5_session_nonce_ctx);
+                       MD5Update(&md5_session_nonce_ctx, session_nonce, 16);
+                       MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
+                       
+                       ntlmssp_state->chal = data_blob_talloc(ntlmssp_state->mem_ctx, session_nonce_hash, 8);
+
+                       /* LM response is no longer useful */
+                       data_blob_free(&ntlmssp_state->lm_resp);
+
+                       /* We changed the effective challenge - set it */
+                       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->set_challenge(ntlmssp_state, &ntlmssp_state->chal))) {
+                               data_blob_free(&encrypted_session_key);
+                               return nt_status;
+                       }
+               }
+       }
+
+       /* Finally, actually ask if the password is OK */
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_state->check_password(ntlmssp_state, &nt_session_key, &lm_session_key))) {
+               data_blob_free(&encrypted_session_key);
+               return nt_status;
+       }
+
+       dump_data_pw("NT session key:\n", nt_session_key.data, nt_session_key.length);
+       dump_data_pw("LM first-8:\n", lm_session_key.data, lm_session_key.length);
+
+       /* Handle the different session key derivation for NTLM2 */
+       if (doing_ntlm2) {
+               if (nt_session_key.data && nt_session_key.length == 16) {
+                       session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+                       hmac_md5(nt_session_key.data, session_nonce, 
+                                sizeof(session_nonce), session_key.data);
+                       dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
+
+               }
+       } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+               if (lm_session_key.data && lm_session_key.length >= 8 && 
+                   ntlmssp_state->lm_resp.data && ntlmssp_state->lm_resp.length == 24) {
+                       session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+                       SMBsesskeygen_lmv1(lm_session_key.data, ntlmssp_state->lm_resp.data, 
+                                          session_key.data);
+                       dump_data_pw("LM session key:\n", session_key.data, session_key.length);
+               }
+       } else if (nt_session_key.data) {
+               session_key = nt_session_key;
+               dump_data_pw("unmodified session key:\n", session_key.data, session_key.length);
+       }
+
+       /* With KEY_EXCH, the client supplies the proposed session key, 
+          but encrypts it with the long-term key */
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+               if (!encrypted_session_key.data || encrypted_session_key.length != 16) {
+                       data_blob_free(&encrypted_session_key);
+                       DEBUG(1, ("Client-supplied KEY_EXCH session key was of invalid length (%u)!\n", 
+                                 encrypted_session_key.length));
+                       return NT_STATUS_INVALID_PARAMETER;
+               } else if (!session_key.data || session_key.length != 16) {
+                       DEBUG(5, ("server session key is invalid (len == %u), cannot do KEY_EXCH!\n", 
+                                 session_key.length));
+               } else {
+                       dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
+                       SamOEMhash(encrypted_session_key.data, 
+                                  session_key.data, 
+                                  encrypted_session_key.length);
+                       ntlmssp_state->session_key = data_blob_talloc(ntlmssp_state->mem_ctx, 
+                                                                     encrypted_session_key.data, 
+                                                                     encrypted_session_key.length);
+                       dump_data_pw("KEY_EXCH session key:\n", session_key.data, session_key.length);
+               }
+       } else {
+               ntlmssp_state->session_key = session_key;
+       }
+
+       data_blob_free(&encrypted_session_key);
+       
+       /* allow arbitarily many authentications */
+       ntlmssp_state->expected_state = NTLMSSP_AUTH;
+
+       return nt_status;
+}
+
+/**
+ * Create an NTLMSSP state machine
+ * 
+ * @param ntlmssp_state NTLMSSP State, allocated by this function
+ */
+
+NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
+{
+       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_server_start: talloc failed!\n"));
+               talloc_destroy(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       (*ntlmssp_state)->role = NTLMSSP_SERVER;
+
+       (*ntlmssp_state)->mem_ctx = mem_ctx;
+       (*ntlmssp_state)->get_challenge = get_challenge;
+       (*ntlmssp_state)->set_challenge = set_challenge;
+       (*ntlmssp_state)->may_set_challenge = may_set_challenge;
+
+       (*ntlmssp_state)->get_global_myname = global_myname;
+       (*ntlmssp_state)->get_domain = lp_workgroup;
+       (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */
+
+       (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE;
+
+       (*ntlmssp_state)->ref_count = 1;
+
+       (*ntlmssp_state)->neg_flags = 
+               NTLMSSP_NEGOTIATE_128 |
+               NTLMSSP_NEGOTIATE_NTLM |
+//             NTLMSSP_NEGOTIATE_NTLM2 |
+               NTLMSSP_NEGOTIATE_KEY_EXCH |
+               NTLMSSP_NEGOTIATE_SIGN;
+
+       return NT_STATUS_OK;
+}
+
+/*********************************************************************
+ Client side NTLMSSP
+*********************************************************************/
+
+/**
+ * Next state function for the Initial packet
+ * 
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB.  reply.data must be NULL
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK. 
+ */
+
+static NTSTATUS ntlmssp_client_initial(struct ntlmssp_state *ntlmssp_state, 
+                                 DATA_BLOB reply, DATA_BLOB *next_request) 
+{
+       if (ntlmssp_state->unicode) {
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+       } else {
+               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
+       }
+       
+       if (ntlmssp_state->use_ntlmv2) {
+//             ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+       }
+
+       /* generate the ntlmssp negotiate packet */
+       msrpc_gen(next_request, "CddAA",
+                 "NTLMSSP",
+                 NTLMSSP_NEGOTIATE,
+                 ntlmssp_state->neg_flags,
+                 ntlmssp_state->get_domain(), 
+                 ntlmssp_state->get_global_myname());
+
+       ntlmssp_state->expected_state = NTLMSSP_CHALLENGE;
+
+       return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+/**
+ * Next state function for the Challenge Packet.  Generate an auth packet.
+ * 
+ * @param ntlmssp_state NTLMSSP State
+ * @param request The request, as a DATA_BLOB.  reply.data must be NULL
+ * @param request The reply, as an allocated DATA_BLOB, caller to free.
+ * @return Errors or NT_STATUS_OK. 
+ */
+
+static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, 
+                                        const DATA_BLOB reply, DATA_BLOB *next_request) 
+{
+       uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
+       DATA_BLOB server_domain_blob;
+       DATA_BLOB challenge_blob;
+       DATA_BLOB struct_blob = data_blob(NULL, 0);
+       char *server_domain;
+       const char *chal_parse_string;
+       const char *auth_gen_string;
+       DATA_BLOB lm_response = data_blob(NULL, 0);
+       DATA_BLOB nt_response = data_blob(NULL, 0);
+       DATA_BLOB session_key = data_blob(NULL, 0);
+       DATA_BLOB encrypted_session_key = data_blob(NULL, 0);
+       NTSTATUS nt_status;
+
+       if (!msrpc_parse(&reply, "CdBd",
+                        "NTLMSSP",
+                        &ntlmssp_command, 
+                        &server_domain_blob,
+                        &chal_flags)) {
+               DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n"));
+               dump_data(2, (const char *)reply.data, reply.length);
+
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       
+       data_blob_free(&server_domain_blob);
+
+       DEBUG(3, ("Got challenge flags:\n"));
+       debug_ntlmssp_flags(chal_flags);
+
+       ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth());
+
+       if (ntlmssp_state->unicode) {
+               if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+                       chal_parse_string = "CdUdbddB";
+               } else {
+                       chal_parse_string = "CdUdbdd";
+               }
+               auth_gen_string = "CdBBUUUBd";
+       } else {
+               if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) {
+                       chal_parse_string = "CdAdbddB";
+               } else {
+                       chal_parse_string = "CdAdbdd";
+               }
+
+               auth_gen_string = "CdBBAAABd";
+       }
+
+       DEBUG(3, ("NTLMSSP: Set final flags:\n"));
+       debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
+       if (!msrpc_parse(&reply, chal_parse_string,
+                        "NTLMSSP",
+                        &ntlmssp_command, 
+                        &server_domain,
+                        &chal_flags,
+                        &challenge_blob, 8,
+                        &unkn1, &unkn2,
+                        &struct_blob)) {
+               DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n"));
+               dump_data(2, (const char *)reply.data, reply.length);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       ntlmssp_state->server_domain = talloc_strdup(ntlmssp_state->mem_ctx,
+                                                    server_domain);
+
+       SAFE_FREE(server_domain);
+       if (challenge_blob.length != 8) {
+               data_blob_free(&struct_blob);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (!ntlmssp_state->password) {
+               /* do nothing - blobs are zero length */
+       } else if (ntlmssp_state->use_ntlmv2) {
+
+               if (!struct_blob.length) {
+                       /* be lazy, match win2k - we can't do NTLMv2 without it */
+                       DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n"));
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               /* TODO: if the remote server is standalone, then we should replace 'domain'
+                  with the server name as supplied above */
+               
+               if (!SMBNTLMv2encrypt(ntlmssp_state->user, 
+                                     ntlmssp_state->domain, 
+                                     ntlmssp_state->password, &challenge_blob, 
+                                     &struct_blob, 
+                                     &lm_response, &nt_response, &session_key)) {
+                       data_blob_free(&challenge_blob);
+                       data_blob_free(&struct_blob);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+               struct MD5Context md5_session_nonce_ctx;
+               uchar nt_hash[16];
+               uchar session_nonce[16];
+               uchar session_nonce_hash[16];
+               uchar nt_session_key[16];
+               E_md4hash(ntlmssp_state->password, nt_hash);
+               
+               lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
+               generate_random_buffer(lm_response.data, 8, False);
+               memset(lm_response.data+8, 0, 16);
+
+               memcpy(session_nonce, challenge_blob.data, 8);
+               memcpy(&session_nonce[8], lm_response.data, 8);
+       
+               MD5Init(&md5_session_nonce_ctx);
+               MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8);
+               MD5Update(&md5_session_nonce_ctx, lm_response.data, 8);
+               MD5Final(session_nonce_hash, &md5_session_nonce_ctx);
+
+               DEBUG(5, ("NTLMSSP challenge set by NTLM2\n"));
+               DEBUG(5, ("challenge is: \n"));
+               dump_data(5, session_nonce_hash, 8);
+               
+               nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
+               SMBNTencrypt(ntlmssp_state->password,
+                            session_nonce_hash,
+                            nt_response.data);
+
+               session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+
+               SMBsesskeygen_ntv1(nt_hash, NULL, nt_session_key);
+               hmac_md5(nt_session_key, session_nonce, sizeof(session_nonce), session_key.data);
+               dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length);
+       } else {
+               
+               
+               uchar lm_hash[16];
+               uchar nt_hash[16];
+               E_deshash(ntlmssp_state->password, lm_hash);
+               E_md4hash(ntlmssp_state->password, nt_hash);
+               
+               /* lanman auth is insecure, it may be disabled */
+               if (lp_client_lanman_auth()) {
+                       lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
+                       SMBencrypt(ntlmssp_state->password,challenge_blob.data,
+                                  lm_response.data);
+               }
+               
+               nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24);
+               SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
+                            nt_response.data);
+               
+               session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16);
+               if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
+                   && lp_client_lanman_auth()) {
+                       SMBsesskeygen_lmv1(lm_hash, lm_response.data, 
+                                          session_key.data);
+                       dump_data_pw("LM session key\n", session_key.data, session_key.length);
+               } else {
+                       SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
+                       dump_data_pw("NT session key:\n", session_key.data, session_key.length);
+               }
+       }
+       data_blob_free(&struct_blob);
+
+       /* Key exchange encryptes a new client-generated session key with
+          the password-derived key */
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
+               uint8 client_session_key[16];
+               
+               generate_random_buffer(client_session_key, sizeof(client_session_key), False);  
+               encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key));
+               dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length);
+
+               SamOEMhash(encrypted_session_key.data, session_key.data, encrypted_session_key.length);
+               data_blob_free(&session_key);
+               session_key = data_blob_talloc(ntlmssp_state->mem_ctx, client_session_key, sizeof(client_session_key));
+               dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length);
+       }
+
+       /* this generates the actual auth packet */
+       if (!msrpc_gen(next_request, auth_gen_string, 
+                      "NTLMSSP", 
+                      NTLMSSP_AUTH, 
+                      lm_response.data, lm_response.length,
+                      nt_response.data, nt_response.length,
+                      ntlmssp_state->domain, 
+                      ntlmssp_state->user, 
+                      ntlmssp_state->get_global_myname(), 
+                      encrypted_session_key.data, encrypted_session_key.length,
+                      ntlmssp_state->neg_flags)) {
+               
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       data_blob_free(&encrypted_session_key);
+
+       data_blob_free(&ntlmssp_state->chal);
+
+       ntlmssp_state->chal = challenge_blob;
+       ntlmssp_state->lm_resp = lm_response;
+       ntlmssp_state->nt_resp = nt_response;
+       ntlmssp_state->session_key = session_key;
+
+       ntlmssp_state->expected_state = NTLMSSP_UNKNOWN;
+
+       if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) {
+               DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status)));
+               return nt_status;
+       }
+
+       return NT_STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+NTSTATUS ntlmssp_client_start(NTLMSSP_STATE **ntlmssp_state)
+{
+       TALLOC_CTX *mem_ctx;
+
+       mem_ctx = talloc_init("NTLMSSP Client context");
+       
+       *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
+       if (!*ntlmssp_state) {
+               DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
+               talloc_destroy(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       (*ntlmssp_state)->role = NTLMSSP_CLIENT;
+
+       (*ntlmssp_state)->mem_ctx = mem_ctx;
+
+       (*ntlmssp_state)->get_global_myname = global_myname;
+       (*ntlmssp_state)->get_domain = lp_workgroup;
+
+       (*ntlmssp_state)->unicode = True;
+
+       (*ntlmssp_state)->use_ntlmv2 = lp_client_ntlmv2_auth();
+
+       (*ntlmssp_state)->expected_state = NTLMSSP_INITIAL;
+
+       (*ntlmssp_state)->ref_count = 1;
+
+       (*ntlmssp_state)->neg_flags = 
+               NTLMSSP_NEGOTIATE_128 |
+               NTLMSSP_NEGOTIATE_NTLM |
+//             NTLMSSP_NEGOTIATE_NTLM2 |
+               NTLMSSP_NEGOTIATE_KEY_EXCH |
+               /*
+                * We need to set this to allow a later SetPassword
+                * via the SAMR pipe to succeed. Strange.... We could
+                * also add  NTLMSSP_NEGOTIATE_SEAL here. JRA.
+                * */
+               NTLMSSP_NEGOTIATE_SIGN |
+               NTLMSSP_REQUEST_TARGET;
+
+       return NT_STATUS_OK;
+}
+
similarity index 52%
rename from source4/include/ntlmssp.h
rename to source4/libcli/auth/ntlmssp.h
index f0278ffece899adc653a2ee3a635f1bee3a08656..681d4071dbb4ee3dc445213e1b20d8cf0b6c13cb 100644 (file)
@@ -30,6 +30,7 @@ enum NTLMSSP_ROLE
 /* NTLMSSP message types */
 enum NTLM_MESSAGE_TYPE
 {
+       NTLMSSP_INITIAL = 0 /* samba internal state */,
        NTLMSSP_NEGOTIATE = 1,
        NTLMSSP_CHALLENGE = 2,
        NTLMSSP_AUTH      = 3,
@@ -62,37 +63,18 @@ enum NTLM_MESSAGE_TYPE
 #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
+#define NTLMSSP_NAME_TYPE_SERVER      0x01
+#define NTLMSSP_NAME_TYPE_DOMAIN      0x02
+#define NTLMSSP_NAME_TYPE_SERVER_DNS  0x03
+#define NTLMSSP_NAME_TYPE_DOMAIN_DNS  0x04
 
 typedef struct ntlmssp_state 
 {
        TALLOC_CTX *mem_ctx;
+       unsigned int ref_count;
        enum NTLMSSP_ROLE role;
-       BOOL unicode;
-       char *user;
-       char *domain;
-       char *workstation;
-       DATA_BLOB lm_resp;
-       DATA_BLOB nt_resp;
-       DATA_BLOB chal;
-       void *auth_context;
-       const uint8 *(*get_challenge)(struct ntlmssp_state *ntlmssp_state);
-       NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state);
-
-       const char *(*get_global_myname)(void);
-       const char *(*get_domain)(void);
-
-       int server_role;
+       enum server_types server_role;
        uint32 expected_state;
-} NTLMSSP_STATE;
-
-typedef struct ntlmssp_client_state 
-{
-       TALLOC_CTX *mem_ctx;
-       unsigned int ref_count;
 
        BOOL unicode;
        BOOL use_ntlmv2;
@@ -100,34 +82,88 @@ typedef struct ntlmssp_client_state
        char *domain;
        char *workstation;
        char *password;
+       char *server_domain;
 
-       const char *(*get_global_myname)(void);
-       const char *(*get_domain)(void);
+       DATA_BLOB internal_chal; /* Random challenge as supplied to the client for NTLM authentication */
 
-       DATA_BLOB chal;
+       DATA_BLOB chal; /* Random challenge as input into the actual NTLM (or NTLM2) authentication */
        DATA_BLOB lm_resp;
        DATA_BLOB nt_resp;
        DATA_BLOB session_key;
        
-       uint32 neg_flags;
+       uint32 neg_flags; /* the current state of negotiation with the NTLMSSP partner */
        
+       void *auth_context;
+
+       /**
+        * Callback to get the 'challenge' used for NTLM authentication.  
+        *
+        * @param ntlmssp_state This structure
+        * @return 8 bytes of challnege data, determined by the server to be the challenge for NTLM authentication
+        *
+        */
+       const uint8 *(*get_challenge)(const struct ntlmssp_state *ntlmssp_state);
+
+       /**
+        * Callback to find if the challenge used by NTLM authentication may be modified 
+        *
+        * The NTLM2 authentication scheme modifies the effective challenge, but this is not compatiable with the
+        * current 'security=server' implementation..  
+        *
+        * @param ntlmssp_state This structure
+        * @return Can the challenge be set to arbitary values?
+        *
+        */
+       BOOL (*may_set_challenge)(const struct ntlmssp_state *ntlmssp_state);
+
+       /**
+        * Callback to set the 'challenge' used for NTLM authentication.  
+        *
+        * The callback may use the void *auth_context to store state information, but the same value is always available
+        * from the DATA_BLOB chal on this structure.
+        *
+        * @param ntlmssp_state This structure
+        * @param challange 8 bytes of data, agreed by the client and server to be the effective challenge for NTLM2 authentication
+        *
+        */
+       NTSTATUS (*set_challenge)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *challenge);
+
+       /**
+        * Callback to check the user's password.  
+        *
+        * The callback must reads the feilds of this structure for the information it needs on the user 
+        * @param ntlmssp_state This structure
+        * @param nt_session_key If an NT session key is returned by the authentication process, return it here
+        * @param lm_session_key If an LM session key is returned by the authentication process, return it here
+        *
+        */
+       NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *nt_session_key, DATA_BLOB *lm_session_key);
+
+       const char *(*get_global_myname)(void);
+       const char *(*get_domain)(void);
+
        /* SMB Signing */
        
        uint32 ntlmssp_seq_num;
 
        /* ntlmv2 */
-       char cli_sign_const[16];
-       char cli_seal_const[16];
-       char srv_sign_const[16];
-       char srv_seal_const[16];
+       char send_sign_const[16];
+       char send_seal_const[16];
+       char recv_sign_const[16];
+       char recv_seal_const[16];
 
-       unsigned char cli_sign_hash[258];
-       unsigned char cli_seal_hash[258];
-       unsigned char srv_sign_hash[258];
-       unsigned char srv_seal_hash[258];
+       unsigned char send_sign_hash[258];
+       unsigned char send_seal_hash[258];
+       unsigned char recv_sign_hash[258];
+       unsigned char recv_seal_hash[258];
 
        /* ntlmv1 */
        unsigned char ntlmssp_hash[258];
 
-} NTLMSSP_CLIENT_STATE;
+       /* it turns out that we don't always get the
+          response in at the time we want to process it.
+          Store it here, until we need it */
+       DATA_BLOB stored_response; 
+       
+} NTLMSSP_STATE;
 
similarity index 80%
rename from source4/libcli/ntlmssp_parse.c
rename to source4/libcli/auth/ntlmssp_parse.c
index ac779a3906840d14e7fbacd5c60bdb5af5058220..3444db030689ba6194eeeec49d61371ef920dee8 100644 (file)
@@ -2,7 +2,7 @@
    Unix SMB/CIFS implementation.
    simple kerberos5/SPNEGO routines
    Copyright (C) Andrew Tridgell 2001
-   Copyright (C) Jim McDonough   2002
+   Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
    Copyright (C) Andrew Bartlett 2002-2003
    
    This program is free software; you can redistribute it and/or modify
@@ -31,7 +31,7 @@
   format specifiers are:
 
   U = unicode string (input is unix string)
-  a = address (input is BOOL unicode, char *unix_string)
+  a = address (input is 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)
@@ -49,7 +49,6 @@ 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);
@@ -66,14 +65,9 @@ BOOL msrpc_gen(DATA_BLOB *blob,
                        data_size += str_ascii_charnum(s);
                        break;
                case 'a':
-                       unicode = va_arg(ap, BOOL);
                        n = va_arg(ap, int);
                        s = va_arg(ap, char *);
-                       if (unicode) {
-                               data_size += (str_charnum(s) * 2) + 4;
-                       } else {
-                               data_size += (str_ascii_charnum(s)) + 4;
-                       }
+                       data_size += (str_charnum(s) * 2) + 4;
                        break;
                case 'B':
                        b = va_arg(ap, uint8 *);
@@ -124,27 +118,16 @@ BOOL msrpc_gen(DATA_BLOB *blob,
                        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 *);
-                       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;
+                       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;
                        break;
 
                case 'B':
@@ -153,7 +136,8 @@ BOOL msrpc_gen(DATA_BLOB *blob,
                        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;
-                       memcpy(blob->data+data_ofs, b, n);
+                       if (n && b) /* don't follow null pointers... */
+                               memcpy(blob->data+data_ofs, b, n);
                        data_ofs += n;
                        break;
                case 'd':
@@ -220,23 +204,27 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
                        len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
                        ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 
-                       /* make sure its in the right format - be strict */
-                       if (len1 != len2 || ptr + len1 > blob->length) {
-                               return False;
-                       }
-                       if (len1 & 1) {
-                               /* if odd length and unicode */
-                               return False;
-                       }
-
                        ps = va_arg(ap, char **);
-                       if (0 < len1) {
-                               pull_string(NULL, p, blob->data + ptr, sizeof(p), 
-                                           len1, 
-                                           STR_UNICODE|STR_NOALIGN);
-                               (*ps) = smb_xstrdup(p);
+                       if (len1 == 0 && len2 == 0) {
+                               *ps = smb_xstrdup("");
                        } else {
-                               (*ps) = smb_xstrdup("");
+                               /* make sure its in the right format - be strict */
+                               if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+                                       return False;
+                               }
+                               if (len1 & 1) {
+                                       /* if odd length and unicode */
+                                       return False;
+                               }
+                               
+                               if (0 < len1) {
+                                       pull_string(NULL, p, blob->data + ptr, sizeof(p), 
+                                                   len1, 
+                                                   STR_UNICODE|STR_NOALIGN);
+                                       (*ps) = smb_xstrdup(p);
+                               } else {
+                                       (*ps) = smb_xstrdup("");
+                               }
                        }
                        break;
                case 'A':
@@ -245,19 +233,23 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
                        len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
                        ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
 
-                       /* make sure its in the right format - be strict */
-                       if (len1 != len2 || ptr + len1 > blob->length) {
-                               return False;
-                       }
-
                        ps = va_arg(ap, char **);
-                       if (0 < len1) {
-                               pull_string(NULL, p, blob->data + ptr, sizeof(p), 
-                                           len1, 
-                                           STR_ASCII|STR_NOALIGN);
-                               (*ps) = smb_xstrdup(p);
+                       /* make sure its in the right format - be strict */
+                       if (len1 == 0 && len2 == 0) {
+                               *ps = smb_xstrdup("");
                        } else {
-                               (*ps) = smb_xstrdup("");
+                               if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+                                       return False;
+                               }
+                               
+                               if (0 < len1) {
+                                       pull_string(NULL, p, blob->data + ptr, sizeof(p), 
+                                                   len1, 
+                                                   STR_ASCII|STR_NOALIGN);
+                                       (*ps) = smb_xstrdup(p);
+                               } else {
+                                       (*ps) = smb_xstrdup("");
+                               }
                        }
                        break;
                case 'B':
@@ -265,12 +257,17 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
                        len1 = SVAL(blob->data, head_ofs); head_ofs += 2;
                        len2 = SVAL(blob->data, head_ofs); head_ofs += 2;
                        ptr =  IVAL(blob->data, head_ofs); head_ofs += 4;
-                       /* make sure its in the right format - be strict */
-                       if (len1 != len2 || ptr + len1 > blob->length) {
-                               return False;
-                       }
+
                        b = (DATA_BLOB *)va_arg(ap, void *);
-                       *b = data_blob(blob->data + ptr, len1);
+                       if (len1 == 0 && len2 == 0) {
+                               *b = data_blob(NULL, 0);
+                       } else {
+                               /* make sure its in the right format - be strict */
+                               if ((len1 != len2) || (ptr + len1 < ptr) || (ptr + len1 < len1) || (ptr + len1 > blob->length)) {
+                                       return False;
+                               }
+                               *b = data_blob(blob->data + ptr, len1);
+                       }
                        break;
                case 'b':
                        b = (DATA_BLOB *)va_arg(ap, void *);
@@ -300,4 +297,3 @@ BOOL msrpc_parse(const DATA_BLOB *blob,
 
        return True;
 }
-
diff --git a/source4/libcli/auth/ntlmssp_sign.c b/source4/libcli/auth/ntlmssp_sign.c
new file mode 100644 (file)
index 0000000..11d63ec
--- /dev/null
@@ -0,0 +1,378 @@
+/* 
+ *  Unix SMB/CIFS implementation.
+ *  Version 3.0
+ *  NTLMSSP Signing routines
+ *  Copyright (C) Luke Kenneth Casson Leighton 1996-2001
+ *  Copyright (C) Andrew Bartlett 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "includes.h"
+
+#define CLI_SIGN "session key to client-to-server signing key magic constant"
+#define CLI_SEAL "session key to client-to-server sealing key magic constant"
+#define SRV_SIGN "session key to server-to-client signing key magic constant"
+#define SRV_SEAL "session key to server-to-client sealing key magic constant"
+
+static void NTLMSSPcalc_ap( unsigned char *hash, unsigned char *data, int len)
+{
+    unsigned char index_i = hash[256];
+    unsigned char index_j = hash[257];
+    int ind;
+
+    for (ind = 0; ind < len; ind++)
+    {
+        unsigned char tc;
+        unsigned char t;
+
+        index_i++;
+        index_j += hash[index_i];
+
+        tc = hash[index_i];
+        hash[index_i] = hash[index_j];
+        hash[index_j] = tc;
+
+        t = hash[index_i] + hash[index_j];
+        data[ind] = data[ind] ^ hash[t];
+    }
+
+    hash[256] = index_i;
+    hash[257] = index_j;
+}
+
+static void calc_hash(unsigned char *hash, const char *k2, int k2l)
+{
+       unsigned char j = 0;
+       int ind;
+
+       for (ind = 0; ind < 256; ind++)
+       {
+               hash[ind] = (unsigned char)ind;
+       }
+
+       for (ind = 0; ind < 256; ind++)
+       {
+               unsigned char tc;
+
+               j += (hash[ind] + k2[ind%k2l]);
+
+               tc = hash[ind];
+               hash[ind] = hash[j];
+               hash[j] = tc;
+       }
+
+       hash[256] = 0;
+       hash[257] = 0;
+}
+
+static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
+                            DATA_BLOB session_key, 
+                            const char *constant)
+{
+       struct MD5Context ctx3;
+
+       /* NOTE:  This code is currently complate fantasy - it's
+          got more in common with reality than the previous code
+          (the LM session key is not the right thing to use) but
+          it still needs work */
+
+       MD5Init(&ctx3);
+       MD5Update(&ctx3, session_key.data, session_key.length);
+       MD5Update(&ctx3, (const unsigned char *)constant, strlen(constant));
+       MD5Final((unsigned char *)digest, &ctx3);
+
+       calc_hash(hash, digest, 16);
+}
+
+enum ntlmssp_direction {
+       NTLMSSP_SEND,
+       NTLMSSP_RECEIVE
+};
+
+static NTSTATUS ntlmssp_make_packet_signature(NTLMSSP_STATE *ntlmssp_state,
+                                             const uchar *data, size_t length, 
+                                             enum ntlmssp_direction direction,
+                                             DATA_BLOB *sig) 
+{
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+               HMACMD5Context ctx;
+               char seq_num[4];
+               uchar digest[16];
+               SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+
+               hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
+               hmac_md5_update((const unsigned char *)seq_num, 4, &ctx);
+               hmac_md5_update(data, length, &ctx);
+               hmac_md5_final(digest, &ctx);
+
+               if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+                              , ntlmssp_state->ntlmssp_seq_num)) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               switch (direction) {
+               case NTLMSSP_SEND:
+                       NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash,  sig->data+4, sig->length-4);
+                       break;
+               case NTLMSSP_RECEIVE:
+                       NTLMSSPcalc_ap(ntlmssp_state->recv_sign_hash,  sig->data+4, sig->length-4);
+                       break;
+               }
+       } else {
+               uint32 crc;
+               crc = crc32_calc_buffer((const char *)data, length);
+               if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+                       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);
+       }
+       return NT_STATUS_OK;
+}
+
+NTSTATUS ntlmssp_sign_packet(NTLMSSP_STATE *ntlmssp_state,
+                            const uchar *data, size_t length, 
+                            DATA_BLOB *sig) 
+{
+       NTSTATUS nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
+
+       /* increment counter on send */
+       ntlmssp_state->ntlmssp_seq_num++;
+       return nt_status;
+}
+
+/**
+ * Check the signature of an incoming packet 
+ * @note caller *must* check that the signature is the size it expects 
+ *
+ */
+
+NTSTATUS ntlmssp_check_packet(NTLMSSP_STATE *ntlmssp_state,
+                             const uchar *data, size_t length, 
+                             const DATA_BLOB *sig) 
+{
+       DATA_BLOB local_sig;
+       NTSTATUS nt_status;
+
+       if (sig->length < 8) {
+               DEBUG(0, ("NTLMSSP packet check failed due to short signature (%lu bytes)!\n", 
+                         (unsigned long)sig->length));
+       }
+
+       nt_status = ntlmssp_make_packet_signature(ntlmssp_state, data, 
+                                                 length, NTLMSSP_RECEIVE, &local_sig);
+       
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
+               return nt_status;
+       }
+       
+       if (memcmp(sig->data+sig->length - 8, local_sig.data+local_sig.length - 8, 8) != 0) {
+               DEBUG(5, ("BAD SIG: wanted signature of\n"));
+               dump_data(5, (const char *)local_sig.data, local_sig.length);
+               
+               DEBUG(5, ("BAD SIG: got signature of\n"));
+               dump_data(5, (const char *)(sig->data), sig->length);
+
+               DEBUG(0, ("NTLMSSP packet check failed due to invalid signature!\n"));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       /* increment counter on recieive */
+       ntlmssp_state->ntlmssp_seq_num++;
+
+       return NT_STATUS_OK;
+}
+
+
+/**
+ * Seal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_seal_packet(NTLMSSP_STATE *ntlmssp_state,
+                            uchar *data, size_t length,
+                            DATA_BLOB *sig)
+{      
+       DEBUG(10,("ntlmssp_seal_data: seal\n"));
+       dump_data_pw("ntlmssp clear data\n", data, length);
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+               HMACMD5Context ctx;
+               char seq_num[4];
+               uchar digest[16];
+               SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
+
+               hmac_md5_init_limK_to_64((const unsigned char *)(ntlmssp_state->send_sign_const), 16, &ctx);
+               hmac_md5_update((const unsigned char *)seq_num, 4, &ctx);
+               hmac_md5_update(data, length, &ctx);
+               hmac_md5_final(digest, &ctx);
+
+               if (!msrpc_gen(sig, "dBd", NTLMSSP_SIGN_VERSION, digest, 8 /* only copy first 8 bytes */
+                              , ntlmssp_state->ntlmssp_seq_num)) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               dump_data_pw("ntlmssp client sealing hash:\n", 
+                            ntlmssp_state->send_seal_hash,
+                            sizeof(ntlmssp_state->send_seal_hash));
+               NTLMSSPcalc_ap(ntlmssp_state->send_seal_hash, data, length);
+               dump_data_pw("ntlmssp client signing hash:\n", 
+                            ntlmssp_state->send_sign_hash,
+                            sizeof(ntlmssp_state->send_sign_hash));
+               NTLMSSPcalc_ap(ntlmssp_state->send_sign_hash,  sig->data+4, sig->length-4);
+       } else {
+               uint32 crc;
+               crc = crc32_calc_buffer((const char *)data, length);
+               if (!msrpc_gen(sig, "dddd", NTLMSSP_SIGN_VERSION, 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               /* The order of these two operations matters - we must first seal the packet,
+                  then seal the sequence number - this is becouse the ntlmssp_hash is not
+                  constant, but is is rather updated with each iteration */
+               
+               dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+                            sizeof(ntlmssp_state->ntlmssp_hash));
+               NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+
+               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("ntlmssp sealed data\n", data, length);
+
+       /* increment counter on send */
+       ntlmssp_state->ntlmssp_seq_num++;
+
+       return NT_STATUS_OK;
+}
+
+/**
+ * Unseal data with the NTLMSSP algorithm
+ *
+ */
+
+NTSTATUS ntlmssp_unseal_packet(NTLMSSP_STATE *ntlmssp_state,
+                                     uchar *data, size_t length,
+                                     DATA_BLOB *sig)
+{
+       DEBUG(10,("ntlmssp__unseal_data: seal\n"));
+       dump_data_pw("ntlmssp sealed data\n", data, length);
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
+               NTLMSSPcalc_ap(ntlmssp_state->recv_seal_hash, data, length);
+       } else {
+               dump_data_pw("ntlmssp hash:\n", ntlmssp_state->ntlmssp_hash,
+                            sizeof(ntlmssp_state->ntlmssp_hash));
+               NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, data, length);
+       }
+       dump_data_pw("ntlmssp clear data\n", data, length);
+
+       return ntlmssp_check_packet(ntlmssp_state, data, length, sig);
+}
+
+/**
+   Initialise the state for NTLMSSP signing.
+*/
+NTSTATUS ntlmssp_sign_init(NTLMSSP_STATE *ntlmssp_state)
+{
+       unsigned char p24[24];
+       ZERO_STRUCT(p24);
+
+       DEBUG(3, ("NTLMSSP Sign/Seal - Initialising with flags:\n"));
+       debug_ntlmssp_flags(ntlmssp_state->neg_flags);
+
+       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
+       {
+               const char *send_sign_const;
+               const char *send_seal_const;
+               const char *recv_sign_const;
+               const char *recv_seal_const;
+
+               switch (ntlmssp_state->role) {
+               case NTLMSSP_CLIENT:
+                       send_sign_const = CLI_SIGN;
+                       send_seal_const = CLI_SEAL;
+                       recv_sign_const = SRV_SIGN;
+                       recv_seal_const = SRV_SEAL;
+                       break;
+               case NTLMSSP_SERVER:
+                       send_sign_const = SRV_SIGN;
+                       send_seal_const = SRV_SEAL;
+                       recv_sign_const = CLI_SIGN;
+                       recv_seal_const = CLI_SEAL;
+                       break;
+               }
+
+               calc_ntlmv2_hash(ntlmssp_state->send_sign_hash, 
+                                ntlmssp_state->send_sign_const, 
+                                ntlmssp_state->session_key, send_sign_const);
+               dump_data_pw("NTLMSSP send sign hash:\n", 
+                            ntlmssp_state->send_sign_hash, 
+                            sizeof(ntlmssp_state->send_sign_hash));
+
+               calc_ntlmv2_hash(ntlmssp_state->send_seal_hash, 
+                                ntlmssp_state->send_seal_const, 
+                                ntlmssp_state->session_key, send_seal_const);
+               dump_data_pw("NTLMSSP send sesl hash:\n", 
+                            ntlmssp_state->send_seal_hash, 
+                            sizeof(ntlmssp_state->send_seal_hash));
+
+               calc_ntlmv2_hash(ntlmssp_state->recv_sign_hash, 
+                                ntlmssp_state->recv_sign_const, 
+                                ntlmssp_state->session_key, send_sign_const);
+               dump_data_pw("NTLMSSP receive sign hash:\n", 
+                            ntlmssp_state->recv_sign_hash, 
+                            sizeof(ntlmssp_state->recv_sign_hash));
+
+               calc_ntlmv2_hash(ntlmssp_state->recv_seal_hash, 
+                                ntlmssp_state->recv_seal_const, 
+                                ntlmssp_state->session_key, send_seal_const);
+               dump_data_pw("NTLMSSP receive seal hash:\n", 
+                            ntlmssp_state->recv_sign_hash, 
+                            sizeof(ntlmssp_state->recv_sign_hash));
+
+       } 
+       else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) {
+               if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 8) {
+                       /* can't sign or check signatures yet */ 
+                       DEBUG(5, ("NTLMSSP Sign/Seal - cannot use LM KEY yet\n"));      
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+               
+               DEBUG(5, ("NTLMSSP Sign/Seal - using LM KEY\n"));
+
+               calc_hash(ntlmssp_state->ntlmssp_hash, (const char *)(ntlmssp_state->session_key.data), 8);
+               dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+                            sizeof(ntlmssp_state->ntlmssp_hash));
+       } else {
+               if (!ntlmssp_state->session_key.data || ntlmssp_state->session_key.length < 16) {
+                       /* can't sign or check signatures yet */ 
+                       DEBUG(5, ("NTLMSSP Sign/Seal - cannot use NT KEY yet\n"));
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+               
+               DEBUG(5, ("NTLMSSP Sign/Seal - using NT KEY\n"));
+
+               calc_hash(ntlmssp_state->ntlmssp_hash, (const char *)(ntlmssp_state->session_key.data), 16);
+               dump_data_pw("NTLMSSP hash:\n", ntlmssp_state->ntlmssp_hash,
+                            sizeof(ntlmssp_state->ntlmssp_hash));
+       }
+
+       ntlmssp_state->ntlmssp_seq_num = 0;
+
+       return NT_STATUS_OK;
+}
diff --git a/source4/libcli/ntlmssp.c b/source4/libcli/ntlmssp.c
deleted file mode 100644 (file)
index c4ad260..0000000
+++ /dev/null
@@ -1,625 +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"
-
-/**
- * Print out the NTLMSSP flags for debugging 
- * @param neg_flags The flags from the packet
- */
-
-void debug_ntlmssp_flags(uint32 neg_flags)
-{
-       DEBUG(3,("Got NTLMSSP neg_flags=0x%08x\n", neg_flags));
-       
-       if (neg_flags & NTLMSSP_NEGOTIATE_UNICODE) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_UNICODE\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_OEM) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_OEM\n"));
-       if (neg_flags & NTLMSSP_REQUEST_TARGET) 
-               DEBUGADD(4, ("  NTLMSSP_REQUEST_TARGET\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_SIGN) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_SIGN\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_SEAL) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_SEAL\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_LM_KEY\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_NETWARE) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NETWARE\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_NTLM) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NTLM\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_THIS_IS_LOCAL_CALL\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_ALWAYS_SIGN\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_NTLM2) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_NTLM2\n"));
-       if (neg_flags & NTLMSSP_CHAL_TARGET_INFO) 
-               DEBUGADD(4, ("  NTLMSSP_CHAL_TARGET_INFO\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_128) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_128\n"));
-       if (neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) 
-               DEBUGADD(4, ("  NTLMSSP_NEGOTIATE_KEY_EXCH\n"));
-}
-
-/**
- * Default challenge generation code.
- *
- */
-   
-static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state)
-{
-       static uchar chal[8];
-       generate_random_buffer(chal, sizeof(chal), False);
-
-       return chal;
-}
-
-/**
- * Determine correct target name flags for reply, given server role 
- * and negoitated falgs
- * 
- * @param ntlmssp_state NTLMSSP State
- * @param neg_flags The flags from the packet
- * @param chal_flags The flags to be set in the reply packet
- * @return The 'target name' string.
- */
-
-static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state,
-                                      uint32 neg_flags, uint32 *chal_flags) 
-{
-       if (neg_flags & NTLMSSP_REQUEST_TARGET) {
-               *chal_flags |= NTLMSSP_CHAL_TARGET_INFO;
-               *chal_flags |= NTLMSSP_REQUEST_TARGET;
-               if (ntlmssp_state->server_role == ROLE_STANDALONE) {
-                       *chal_flags |= NTLMSSP_TARGET_TYPE_SERVER;
-                       return ntlmssp_state->get_global_myname();
-               } else {
-                       *chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN;
-                       return ntlmssp_state->get_domain();
-               };
-       } else {
-               return "";
-       }
-}
-
-/**
- * Next state function for the Negotiate packet
- * 
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB
- * @param request The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or MORE_PROCESSING_REQUIRED if a reply is sent. 
- */
-
-static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state,
-                                        const 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_INVALID_PARAMETER;
-       }
-
-       SAFE_FREE(cliname);
-       SAFE_FREE(domname);
-  
-       debug_ntlmssp_flags(neg_flags);
-
-       cryptkey = ntlmssp_state->get_challenge(ntlmssp_state);
-
-       data_blob_free(&ntlmssp_state->chal);
-       ntlmssp_state->chal = data_blob(cryptkey, 8);
-
-       /* 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;
-       
-       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(ntlmssp_state, 
-                                         neg_flags, &chal_flags); 
-
-       /* This should be a 'netbios domain -> DNS domain' mapping */
-       dnsdomname[0] = '\0';
-       get_mydomname(dnsdomname);
-       strlower(dnsdomname);
-       
-       dnsname[0] = '\0';
-       get_myfullname(dnsname);
-       strlower(dnsname);
-       
-       if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) 
-       {
-               const char *target_name_dns = "";
-               if (chal_flags |= NTLMSSP_TARGET_TYPE_DOMAIN) {
-                       target_name_dns = dnsdomname;
-               } else if (chal_flags |= NTLMSSP_TARGET_TYPE_SERVER) {
-                       target_name_dns = dnsname;
-               }
-
-               /* the numbers here are the string type flags */
-               msrpc_gen(&struct_blob, "aaaaa",
-                         ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN, target_name,
-                         ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER, ntlmssp_state->get_global_myname(),
-                         ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_DOMAIN_DNS, target_name_dns,
-                         ntlmssp_state->unicode, NTLMSSP_NAME_TYPE_SERVER_DNS, dnsdomname,
-                         ntlmssp_state->unicode, 0, "");
-       } else {
-               struct_blob = data_blob(NULL, 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);
-
-       ntlmssp_state->expected_state = NTLMSSP_AUTH;
-
-       return NT_STATUS_MORE_PROCESSING_REQUIRED;
-}
-
-/**
- * Next state function for the Authenticate packet
- * 
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB
- * @param request The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or NT_STATUS_OK. 
- */
-
-static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state,
-                                   const DATA_BLOB request, DATA_BLOB *reply) 
-{
-       DATA_BLOB sess_key;
-       uint32 ntlmssp_command, neg_flags;
-       NTSTATUS nt_status;
-
-       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";
-       }
-
-       data_blob_free(&ntlmssp_state->lm_resp);
-       data_blob_free(&ntlmssp_state->nt_resp);
-
-       SAFE_FREE(ntlmssp_state->user);
-       SAFE_FREE(ntlmssp_state->domain);
-       SAFE_FREE(ntlmssp_state->workstation);
-
-       /* now the NTLMSSP encoded auth hashes */
-       if (!msrpc_parse(&request, parse_string,
-                        "NTLMSSP", 
-                        &ntlmssp_command, 
-                        &ntlmssp_state->lm_resp,
-                        &ntlmssp_state->nt_resp,
-                        &ntlmssp_state->domain, 
-                        &ntlmssp_state->user, 
-                        &ntlmssp_state->workstation,
-                        &sess_key,
-                        &neg_flags)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       data_blob_free(&sess_key);
-       
-       DEBUG(3,("Got user=[%s] domain=[%s] workstation=[%s] len1=%d len2=%d\n",
-                ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->workstation, ntlmssp_state->lm_resp.length, ntlmssp_state->nt_resp.length));
-
-#if 0
-       file_save("nthash1.dat",  &ntlmssp_state->nt_resp.data,  &ntlmssp_state->nt_resp.length);
-       file_save("lmhash1.dat",  &ntlmssp_state->lm_resp.data,  &ntlmssp_state->lm_resp.length);
-#endif
-
-       nt_status = ntlmssp_state->check_password(ntlmssp_state);
-       
-       *reply = data_blob(NULL, 0);
-
-       return nt_status;
-}
-
-/**
- * Create an NTLMSSP state machine
- * 
- * @param ntlmssp_state NTLMSSP State, allocated by this funciton
- */
-
-NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state)
-{
-       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_server_start: talloc failed!\n"));
-               talloc_destroy(mem_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       (*ntlmssp_state)->mem_ctx = mem_ctx;
-       (*ntlmssp_state)->get_challenge = get_challenge;
-
-       (*ntlmssp_state)->get_global_myname = lp_netbios_name;
-       (*ntlmssp_state)->get_domain = lp_workgroup;
-       (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */
-
-       (*ntlmssp_state)->expected_state = NTLMSSP_NEGOTIATE;
-
-       return NT_STATUS_OK;
-}
-
-/**
- * End an NTLMSSP state machine
- * 
- * @param ntlmssp_state NTLMSSP State, free()ed by this funciton
- */
-
-NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state)
-{
-       TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
-
-       data_blob_free(&(*ntlmssp_state)->chal);
-       data_blob_free(&(*ntlmssp_state)->lm_resp);
-       data_blob_free(&(*ntlmssp_state)->nt_resp);
-
-       SAFE_FREE((*ntlmssp_state)->user);
-       SAFE_FREE((*ntlmssp_state)->domain);
-       SAFE_FREE((*ntlmssp_state)->workstation);
-
-       talloc_destroy(mem_ctx);
-       *ntlmssp_state = NULL;
-       return NT_STATUS_OK;
-}
-
-/**
- * Next state function for the NTLMSSP state machine
- * 
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB
- * @param request The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors, NT_STATUS_MORE_PROCESSING_REQUIRED or NT_STATUS_OK. 
- */
-
-NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, 
-                              const DATA_BLOB request, DATA_BLOB *reply) 
-{
-       uint32 ntlmssp_command;
-       *reply = data_blob(NULL, 0);
-
-       if (!msrpc_parse(&request, "Cd",
-                        "NTLMSSP",
-                        &ntlmssp_command)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (ntlmssp_command != ntlmssp_state->expected_state) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (ntlmssp_command == NTLMSSP_NEGOTIATE) {
-               return ntlmssp_server_negotiate(ntlmssp_state, request, reply);
-       } else if (ntlmssp_command == NTLMSSP_AUTH) {
-               return ntlmssp_server_auth(ntlmssp_state, request, reply);
-       } else {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-}
-
-/*********************************************************************
- Client side NTLMSSP
-*********************************************************************/
-
-/**
- * Next state function for the Initial packet
- * 
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB.  reply.data must be NULL
- * @param request The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or NT_STATUS_OK. 
- */
-
-static NTSTATUS ntlmssp_client_initial(struct ntlmssp_client_state *ntlmssp_state, 
-                                 DATA_BLOB reply, DATA_BLOB *next_request) 
-{
-       if (ntlmssp_state->unicode) {
-               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
-       }
-       
-       /* generate the ntlmssp negotiate packet */
-       msrpc_gen(next_request, "CddAA",
-                 "NTLMSSP",
-                 NTLMSSP_NEGOTIATE,
-                 ntlmssp_state->neg_flags,
-                 ntlmssp_state->get_domain(), 
-                 ntlmssp_state->get_global_myname());
-
-       return NT_STATUS_MORE_PROCESSING_REQUIRED;
-}
-
-/**
- * Next state function for the Challenge Packet.  Generate an auth packet.
- * 
- * @param ntlmssp_state NTLMSSP State
- * @param request The request, as a DATA_BLOB.  reply.data must be NULL
- * @param request The reply, as an allocated DATA_BLOB, caller to free.
- * @return Errors or NT_STATUS_OK. 
- */
-
-static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_client_state *ntlmssp_state, 
-                                        const DATA_BLOB reply, DATA_BLOB *next_request) 
-{
-       uint32 chal_flags, ntlmssp_command, unkn1, unkn2;
-       DATA_BLOB server_domain_blob;
-       DATA_BLOB challenge_blob;
-       DATA_BLOB struct_blob;
-       char *server_domain;
-       const char *chal_parse_string;
-       const char *auth_gen_string;
-       DATA_BLOB lm_response = data_blob(NULL, 0);
-       DATA_BLOB nt_response = data_blob(NULL, 0);
-       DATA_BLOB session_key = data_blob(NULL, 0);
-       uint8 datagram_sess_key[16];
-
-       ZERO_STRUCT(datagram_sess_key);
-
-       if (!msrpc_parse(&reply, "CdBd",
-                        "NTLMSSP",
-                        &ntlmssp_command, 
-                        &server_domain_blob,
-                        &chal_flags)) {
-               DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-       
-       data_blob_free(&server_domain_blob);
-
-       if (chal_flags & NTLMSSP_NEGOTIATE_UNICODE) {
-               chal_parse_string = "CdUdbddB";
-               auth_gen_string = "CdBBUUUBd";
-               ntlmssp_state->unicode = True;
-               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_UNICODE;
-               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_OEM;
-       } else if (chal_flags & NTLMSSP_NEGOTIATE_OEM) {
-               chal_parse_string = "CdAdbddB";
-               auth_gen_string = "CdBBAAABd";
-               ntlmssp_state->unicode = False;
-               ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_UNICODE;
-               ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_OEM;
-       } else {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (!msrpc_parse(&reply, chal_parse_string,
-                        "NTLMSSP",
-                        &ntlmssp_command, 
-                        &server_domain,
-                        &chal_flags,
-                        &challenge_blob, 8,
-                        &unkn1, &unkn2,
-                        &struct_blob)) {
-               DEBUG(0, ("Failed to parse the NTLMSSP Challenge\n"));
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       SAFE_FREE(server_domain);
-       data_blob_free(&struct_blob);
-       
-       if (challenge_blob.length != 8) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (ntlmssp_state->use_ntlmv2) {
-
-               /* TODO: if the remote server is standalone, then we should replace 'domain'
-                  with the server name as supplied above */
-               
-               if (!SMBNTLMv2encrypt(ntlmssp_state->user, 
-                                     ntlmssp_state->domain, 
-                                     ntlmssp_state->password, challenge_blob, 
-                                     &lm_response, &nt_response, &session_key)) {
-                       data_blob_free(&challenge_blob);
-                       return NT_STATUS_NO_MEMORY;
-               }
-       } else {
-               uchar nt_hash[16];
-               E_md4hash(ntlmssp_state->password, nt_hash);
-               
-               /* non encrypted password supplied. Ignore ntpass. */
-               if (lp_client_lanman_auth()) {
-                       lm_response = data_blob(NULL, 24);
-                       SMBencrypt(ntlmssp_state->password,challenge_blob.data,
-                                  lm_response.data);
-               }
-               
-               nt_response = data_blob(NULL, 24);
-               SMBNTencrypt(ntlmssp_state->password,challenge_blob.data,
-                            nt_response.data);
-               session_key = data_blob(NULL, 16);
-               SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data);
-       }
-       
-       data_blob_free(&challenge_blob);
-
-       /* this generates the actual auth packet */
-       if (!msrpc_gen(next_request, auth_gen_string, 
-                      "NTLMSSP", 
-                      NTLMSSP_AUTH, 
-                      lm_response.data, lm_response.length,
-                      nt_response.data, nt_response.length,
-                      ntlmssp_state->domain, 
-                      ntlmssp_state->user, 
-                      ntlmssp_state->get_global_myname(), 
-                      datagram_sess_key, 0,
-                      ntlmssp_state->neg_flags)) {
-               
-               data_blob_free(&lm_response);
-               data_blob_free(&nt_response);
-               data_blob_free(&session_key);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       data_blob_free(&lm_response);
-       data_blob_free(&nt_response);
-
-       ntlmssp_state->session_key = session_key;
-
-       return NT_STATUS_MORE_PROCESSING_REQUIRED;
-}
-
-NTSTATUS ntlmssp_client_start(NTLMSSP_CLIENT_STATE **ntlmssp_state)
-{
-       TALLOC_CTX *mem_ctx;
-
-       mem_ctx = talloc_init("NTLMSSP Client context");
-       
-       *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state));
-       if (!*ntlmssp_state) {
-               DEBUG(0,("ntlmssp_server_start: talloc failed!\n"));
-               talloc_destroy(mem_ctx);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       (*ntlmssp_state)->mem_ctx = mem_ctx;
-
-       (*ntlmssp_state)->get_global_myname = lp_netbios_name;
-       (*ntlmssp_state)->get_domain = lp_workgroup;
-
-       (*ntlmssp_state)->unicode = True;
-
-       (*ntlmssp_state)->neg_flags = 
-               NTLMSSP_NEGOTIATE_128 | 
-               NTLMSSP_NEGOTIATE_NTLM |
-               NTLMSSP_REQUEST_TARGET;
-
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_client_end(NTLMSSP_CLIENT_STATE **ntlmssp_state)
-{
-       TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx;
-
-       data_blob_free(&(*ntlmssp_state)->session_key);
-       talloc_destroy(mem_ctx);
-       *ntlmssp_state = NULL;
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_client_update(NTLMSSP_CLIENT_STATE *ntlmssp_state, 
-                              DATA_BLOB reply, DATA_BLOB *next_request) 
-{
-       uint32 ntlmssp_command;
-       *next_request = data_blob(NULL, 0);
-
-       if (!reply.length) {
-               return ntlmssp_client_initial(ntlmssp_state, reply, next_request);
-       }               
-
-       if (!msrpc_parse(&reply, "Cd",
-                        "NTLMSSP",
-                        &ntlmssp_command)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       if (ntlmssp_command == NTLMSSP_CHALLENGE) {
-               return ntlmssp_client_challenge(ntlmssp_state, reply, next_request);
-       }
-       return NT_STATUS_INVALID_PARAMETER;
-}
-
-NTSTATUS ntlmssp_set_username(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *user) 
-{
-       ntlmssp_state->user = talloc_strdup(ntlmssp_state->mem_ctx, user);
-       if (!ntlmssp_state->user) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_set_password(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *password) 
-{
-       ntlmssp_state->password = talloc_strdup(ntlmssp_state->mem_ctx, password);
-       if (!ntlmssp_state->password) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_set_domain(NTLMSSP_CLIENT_STATE *ntlmssp_state, const char *domain) 
-{
-       ntlmssp_state->domain = talloc_strdup(ntlmssp_state->mem_ctx, domain);
-       if (!ntlmssp_state->domain) {
-               return NT_STATUS_NO_MEMORY;
-       }
-       return NT_STATUS_OK;
-}
diff --git a/source4/libcli/util/ntlmssp_sign.c b/source4/libcli/util/ntlmssp_sign.c
deleted file mode 100644 (file)
index bd6d64d..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/* 
- *  Unix SMB/CIFS implementation.
- *  Version 3.0
- *  NTLMSSP Signing routines
- *  Copyright (C) Luke Kenneth Casson Leighton 1996-2001
- *  Copyright (C) Andrew Bartlett 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include "includes.h"
-
-#define CLI_SIGN "session key to client-to-server signing key magic constant"
-#define CLI_SEAL "session key to client-to-server sealing key magic constant"
-#define SRV_SIGN "session key to server-to-client signing key magic constant"
-#define SRV_SEAL "session key to server-to-client sealing key magic constant"
-
-static void NTLMSSPcalc_ap( unsigned char *hash, unsigned char *data, int len)
-{
-    unsigned char index_i = hash[256];
-    unsigned char index_j = hash[257];
-    int ind;
-
-    for (ind = 0; ind < len; ind++)
-    {
-        unsigned char tc;
-        unsigned char t;
-
-        index_i++;
-        index_j += hash[index_i];
-
-        tc = hash[index_i];
-        hash[index_i] = hash[index_j];
-        hash[index_j] = tc;
-
-        t = hash[index_i] + hash[index_j];
-        data[ind] = data[ind] ^ hash[t];
-    }
-
-    hash[256] = index_i;
-    hash[257] = index_j;
-}
-
-static void calc_hash(unsigned char *hash, const char *k2, int k2l)
-{
-       unsigned char j = 0;
-       int ind;
-
-       for (ind = 0; ind < 256; ind++)
-       {
-               hash[ind] = (unsigned char)ind;
-       }
-
-       for (ind = 0; ind < 256; ind++)
-       {
-               unsigned char tc;
-
-               j += (hash[ind] + k2[ind%k2l]);
-
-               tc = hash[ind];
-               hash[ind] = hash[j];
-               hash[j] = tc;
-       }
-
-       hash[256] = 0;
-       hash[257] = 0;
-}
-
-static void calc_ntlmv2_hash(unsigned char hash[16], char digest[16],
-                            const char encrypted_response[16], 
-                            const char *constant)
-{
-       struct MD5Context ctx3;
-
-       MD5Init(&ctx3);
-       MD5Update(&ctx3, encrypted_response, 5);
-       MD5Update(&ctx3, constant, strlen(constant));
-       MD5Final(digest, &ctx3);
-
-       calc_hash(hash, digest, 16);
-}
-
-enum ntlmssp_direction {
-       NTLMSSP_SEND,
-       NTLMSSP_RECEIVE
-};
-
-static NTSTATUS ntlmssp_make_packet_signiture(NTLMSSP_CLIENT_STATE *ntlmssp_state,
-                                             const uchar *data, size_t length, 
-                                             enum ntlmssp_direction direction,
-                                             DATA_BLOB *sig) 
-{
-       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) {
-               HMACMD5Context ctx;
-               char seq_num[4];
-               uchar digest[16];
-               SIVAL(seq_num, 0, ntlmssp_state->ntlmssp_seq_num);
-
-               hmac_md5_init_limK_to_64(ntlmssp_state->cli_sign_const, 16, &ctx);
-               hmac_md5_update(seq_num, 4, &ctx);
-               hmac_md5_update(data, length, &ctx);
-               hmac_md5_final(digest, &ctx);
-
-               if (!msrpc_gen(sig, "Bd", digest, sizeof(digest), ntlmssp_state->ntlmssp_seq_num)) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-               switch (direction) {
-               case NTLMSSP_SEND:
-                       NTLMSSPcalc_ap(ntlmssp_state->cli_sign_hash,  sig->data, sig->length);
-                       break;
-               case NTLMSSP_RECEIVE:
-                       NTLMSSPcalc_ap(ntlmssp_state->srv_sign_hash,  sig->data, sig->length);
-                       break;
-               }
-       } else {
-               uint32 crc;
-               crc = crc32_buffer(data, length);
-               if (!msrpc_gen(sig, "ddd", 0, crc, ntlmssp_state->ntlmssp_seq_num)) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-               
-               NTLMSSPcalc_ap(ntlmssp_state->ntlmssp_hash, sig->data, sig->length);
-       }
-       return NT_STATUS_OK;
-}
-
-NTSTATUS ntlmssp_client_sign_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
-                                          const uchar *data, size_t length, 
-                                          DATA_BLOB *sig) 
-{
-       ntlmssp_state->ntlmssp_seq_num++;
-       return ntlmssp_make_packet_signiture(ntlmssp_state, data, length, NTLMSSP_SEND, sig);
-}
-
-/**
- * Check the signature of an incoming packet 
- * @note caller *must* check that the signature is the size it expects 
- *
- */
-
-NTSTATUS ntlmssp_client_check_packet(NTLMSSP_CLIENT_STATE *ntlmssp_state,
-                                          const uchar *data, size_t length, 
-                                          const DATA_BLOB *sig) 
-{
-       DATA_BLOB local_sig;
-       NTSTATUS nt_status;
-
-       if (sig->length < 8) {
-               DEBUG(0, ("NTLMSSP packet check failed due to short signiture (%u bytes)!\n", 
-                         sig->length));
-       }
-
-       nt_status = ntlmssp_make_packet_signiture(ntlmssp_state, data, 
-                                                 length, NTLMSSP_RECEIVE, &local_sig);
-       
-       if (!NT_STATUS_IS_OK(nt_status)) {
-               DEBUG(0, ("NTLMSSP packet check failed with %s\n", nt_errstr(nt_status)));
-               return nt_status;
-       }
-       
-       if (memcmp(sig->data, local_sig.data, MIN(sig->length, local_sig.length)) == 0) {
-               return NT_STATUS_OK;
-       } else {
-               DEBUG(5, ("BAD SIG: wanted signature of\n"));
-               dump_data(5, local_sig.data, local_sig.length);
-               
-               DEBUG(5, ("BAD SIG: got signature of\n"));
-               dump_data(5, sig->data, sig->length);
-
-               DEBUG(0, ("NTLMSSP packet check failed due to invalid signiture!\n"));
-               return NT_STATUS_ACCESS_DENIED;
-       }
-}
-
-/**
-   Initialise the state for NTLMSSP signing.
-*/
-NTSTATUS ntlmssp_client_sign_init(NTLMSSP_CLIENT_STATE *ntlmssp_state)
-{
-       unsigned char p24[24];
-       unsigned char lm_hash[16];
-
-       if (!ntlmssp_state->lm_resp.data) {
-               /* can't sign or check signitures yet */ 
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-                           
-       E_deshash(ntlmssp_state->password, lm_hash);
-               
-       NTLMSSPOWFencrypt(lm_hash, ntlmssp_state->lm_resp.data, p24);
-       
-       if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2)
-       {
-               calc_ntlmv2_hash(ntlmssp_state->cli_sign_hash, ntlmssp_state->cli_sign_const, p24, CLI_SIGN);
-               calc_ntlmv2_hash(ntlmssp_state->cli_seal_hash, ntlmssp_state->cli_seal_const, p24, CLI_SEAL);
-               calc_ntlmv2_hash(ntlmssp_state->srv_sign_hash, ntlmssp_state->srv_sign_const, p24, SRV_SIGN);
-               calc_ntlmv2_hash(ntlmssp_state->srv_seal_hash, ntlmssp_state->srv_seal_const, p24, SRV_SEAL);
-       }
-       else
-       {
-               char k2[8];
-               memcpy(k2, p24, 5);
-               k2[5] = 0xe5;
-               k2[6] = 0x38;
-               k2[7] = 0xb0;
-               
-               calc_hash(ntlmssp_state->ntlmssp_hash, k2, 8);
-       }
-
-       ntlmssp_state->ntlmssp_seq_num = 0;
-
-       ZERO_STRUCT(lm_hash);
-       return NT_STATUS_OK;
-}
index 00c2b5814606c3cf60cf7c6cf051c68926d24610..39f3803ade37700c9086b9702fe1e3538bf34eb5 100644 (file)
@@ -76,13 +76,12 @@ void E_deshash(const char *passwd, uchar p16[16])
 {
        fstring dospwd; 
        ZERO_STRUCT(dospwd);
-       ZERO_STRUCTP(p16);
        
        /* Password must be converted to DOS charset - null terminated, uppercase. */
-       push_ascii(dospwd, (const char *)passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE);
+       push_ascii(dospwd, passwd, sizeof(dospwd), STR_UPPER|STR_TERMINATE);
 
        /* Only the fisrt 14 chars are considered, password need not be null terminated. */
-       E_P16(dospwd, p16);
+       E_P16((const unsigned char *)dospwd, p16);
 
        ZERO_STRUCT(dospwd);    
 }
@@ -248,23 +247,23 @@ BOOL make_oem_passwd_hash(char data[516], const char *passwd, uchar old_pw_hash[
        return True;
 }
 
-/* Does the md5 encryption from the NT hash for NTLMv2. */
+/* Does the md5 encryption from the Key Response for NTLMv2. */
 void SMBOWFencrypt_ntv2(const uchar kr[16],
-                       const DATA_BLOB srv_chal,
-                       const DATA_BLOB cli_chal,
+                       const DATA_BLOB *srv_chal,
+                       const DATA_BLOB *cli_chal,
                        uchar resp_buf[16])
 {
        HMACMD5Context ctx;
 
        hmac_md5_init_limK_to_64(kr, 16, &ctx);
-       hmac_md5_update(srv_chal.data, srv_chal.length, &ctx);
-       hmac_md5_update(cli_chal.data, cli_chal.length, &ctx);
+       hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
+       hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
        hmac_md5_final(resp_buf, &ctx);
 
 #ifdef DEBUG_PASSWORD
        DEBUG(100, ("SMBOWFencrypt_ntv2: srv_chal, cli_chal, resp_buf\n"));
-       dump_data(100, srv_chal.data, srv_chal.length);
-       dump_data(100, cli_chal.data, cli_chal.length);
+       dump_data(100, srv_chal->data, srv_chal->length);
+       dump_data(100, cli_chal->data, cli_chal->length);
        dump_data(100, resp_buf, 16);
 #endif
 }
@@ -272,6 +271,8 @@ void SMBOWFencrypt_ntv2(const uchar kr[16],
 void SMBsesskeygen_ntv2(const uchar kr[16],
                        const uchar * nt_resp, uint8 sess_key[16])
 {
+       /* a very nice, 128 bit, variable session key */
+       
        HMACMD5Context ctx;
 
        hmac_md5_init_limK_to_64(kr, 16, &ctx);
@@ -287,6 +288,9 @@ void SMBsesskeygen_ntv2(const uchar kr[16],
 void SMBsesskeygen_ntv1(const uchar kr[16],
                        const uchar * nt_resp, uint8 sess_key[16])
 {
+       /* yes, this session key does not change - yes, this 
+          is a problem - but it is 128 bits */
+       
        mdfour((unsigned char *)sess_key, kr, 16);
 
 #ifdef DEBUG_PASSWORD
@@ -295,36 +299,125 @@ void SMBsesskeygen_ntv1(const uchar kr[16],
 #endif
 }
 
-DATA_BLOB NTLMv2_generate_response(uchar ntlm_v2_hash[16],
-                                  DATA_BLOB server_chal, size_t client_chal_length)
+void SMBsesskeygen_lmv1(const uchar lm_hash[16],
+                       const uchar lm_resp[24], /* only uses 8 */ 
+                       uint8 sess_key[16])
+{
+       /* Calculate the LM session key (effective length 40 bits,
+          but changes with each session) */
+
+       uchar p24[24];
+       uchar partial_lm_hash[16];
+       
+       memcpy(partial_lm_hash, lm_hash, 8);
+       memset(partial_lm_hash + 8, 0xbd, 8);    
+
+       SMBOWFencrypt(lm_hash, lm_resp, p24);
+       
+       memcpy(sess_key, p24, 16);
+       sess_key[5] = 0xe5;
+       sess_key[6] = 0x38;
+       sess_key[7] = 0xb0;
+
+#ifdef DEBUG_PASSWORD
+       DEBUG(100, ("SMBsesskeygen_lmv1:\n"));
+       dump_data(100, sess_key, 16);
+#endif
+}
+
+DATA_BLOB NTLMv2_generate_names_blob(const char *hostname, 
+                                    const char *domain)
+{
+       DATA_BLOB names_blob = data_blob(NULL, 0);
+       
+       msrpc_gen(&names_blob, "aaa", 
+                 True, NTLMSSP_NAME_TYPE_DOMAIN, domain,
+                 True, NTLMSSP_NAME_TYPE_SERVER, hostname,
+                 True, 0, "");
+       return names_blob;
+}
+
+static DATA_BLOB NTLMv2_generate_client_data(const DATA_BLOB *names_blob) 
+{
+       uchar client_chal[8];
+       DATA_BLOB response = data_blob(NULL, 0);
+       char long_date[8];
+
+       generate_random_buffer(client_chal, sizeof(client_chal), False);
+
+       put_long_date(long_date, time(NULL));
+
+       /* See http://www.ubiqx.org/cifs/SMB.html#SMB.8.5 */
+
+       msrpc_gen(&response, "ddbbdb", 
+                 0x00000101,     /* Header  */
+                 0,              /* 'Reserved'  */
+                 long_date, 8,   /* Timestamp */
+                 client_chal, 8, /* client challenge */
+                 0,              /* Unknown */
+                 names_blob->data, names_blob->length);        /* End of name list */
+
+       return response;
+}
+
+static DATA_BLOB NTLMv2_generate_response(const uchar ntlm_v2_hash[16],
+                                         const DATA_BLOB *server_chal,
+                                         const DATA_BLOB *names_blob)
 {
        uchar ntlmv2_response[16];
        DATA_BLOB ntlmv2_client_data;
        DATA_BLOB final_response;
        
        /* NTLMv2 */
+       /* generate some data to pass into the response function - including
+          the hostname and domain name of the server */
+       ntlmv2_client_data = NTLMv2_generate_client_data(names_blob);
 
-       /* We also get to specify some random data */
-       ntlmv2_client_data = data_blob(NULL, client_chal_length);
-       generate_random_buffer(ntlmv2_client_data.data, ntlmv2_client_data.length, False);
-       
        /* Given that data, and the challenge from the server, generate a response */
-       SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, ntlmv2_client_data, ntlmv2_response);
+       SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &ntlmv2_client_data, ntlmv2_response);
        
-       /* put it into nt_response, for the code below to put into the packet */
-       final_response = data_blob(NULL, ntlmv2_client_data.length + sizeof(ntlmv2_response));
+       final_response = data_blob(NULL, sizeof(ntlmv2_response) + ntlmv2_client_data.length);
+
        memcpy(final_response.data, ntlmv2_response, sizeof(ntlmv2_response));
-       /* after the first 16 bytes is the random data we generated above, so the server can verify us with it */
-       memcpy(final_response.data + sizeof(ntlmv2_response), ntlmv2_client_data.data, ntlmv2_client_data.length);
+
+       memcpy(final_response.data+sizeof(ntlmv2_response), 
+              ntlmv2_client_data.data, ntlmv2_client_data.length);
+
        data_blob_free(&ntlmv2_client_data);
 
        return final_response;
 }
 
+static DATA_BLOB LMv2_generate_response(const uchar ntlm_v2_hash[16],
+                                       const DATA_BLOB *server_chal)
+{
+       uchar lmv2_response[16];
+       DATA_BLOB lmv2_client_data = data_blob(NULL, 8);
+       DATA_BLOB final_response = data_blob(NULL, 24);
+       
+       /* LMv2 */
+       /* client-supplied random data */
+       generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length, False);  
+
+       /* Given that data, and the challenge from the server, generate a response */
+       SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, &lmv2_client_data, lmv2_response);
+       memcpy(final_response.data, lmv2_response, sizeof(lmv2_response));
+
+       /* after the first 16 bytes is the random data we generated above, 
+          so the server can verify us with it */
+       memcpy(final_response.data+sizeof(lmv2_response), 
+              lmv2_client_data.data, lmv2_client_data.length);
+
+       data_blob_free(&lmv2_client_data);
+
+       return final_response;
+}
+
 BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password, 
-                     const DATA_BLOB server_chal, 
+                     const DATA_BLOB *server_chal, 
+                     const DATA_BLOB *names_blob,
                      DATA_BLOB *lm_response, DATA_BLOB *nt_response, 
-                     DATA_BLOB *session_key) 
+                     DATA_BLOB *nt_session_key) 
 {
        uchar nt_hash[16];
        uchar ntlm_v2_hash[16];
@@ -338,18 +431,24 @@ BOOL SMBNTLMv2encrypt(const char *user, const char *domain, const char *password
                return False;
        }
        
-       *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, 64 /* pick a number, > 8 */);
+       if (nt_response) {
+               *nt_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal,
+                                                       names_blob); 
+               if (nt_session_key) {
+                       *nt_session_key = data_blob(NULL, 16);
+                       
+                       /* The NTLMv2 calculations also provide a session key, for signing etc later */
+                       /* use only the first 16 bytes of nt_response for session key */
+                       SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, nt_session_key->data);
+               }
+       }
        
        /* LMv2 */
        
-       *lm_response = NTLMv2_generate_response(ntlm_v2_hash, server_chal, 8);
-       
-       *session_key = data_blob(NULL, 16);
+       if (lm_response) {
+               *lm_response = LMv2_generate_response(ntlm_v2_hash, server_chal);
+       }
        
-       /* The NTLMv2 calculations also provide a session key, for signing etc later */
-       /* use only the first 16 bytes of nt_response for session key */
-       SMBsesskeygen_ntv2(ntlm_v2_hash, nt_response->data, session_key->data);
-
        return True;
 }
 
@@ -416,3 +515,4 @@ BOOL decode_pw_buffer(char in_buffer[516], char *new_pwrd,
        
        return True;
 }
+
index c45309ba689c4fbb0728f3894e0d0e4693ace6b2..978bc5640c6e87568e9415aef60df9760ba25eee 100644 (file)
@@ -28,7 +28,7 @@ interface dcerpc
                uint8 num_contexts;
                dcerpc_ctx_list ctx_list[num_contexts];
                [flag(NDR_ALIGN8)]    DATA_BLOB _pad;
-               [flag(NDR_REMAINING)] DATA_BLOB auth_verifier;
+               [flag(NDR_REMAINING)] DATA_BLOB auth_info;
        } dcerpc_bind;
 
        typedef struct {
@@ -53,8 +53,7 @@ interface dcerpc
                [flag(NDR_ALIGN4)]    DATA_BLOB _pad1;
                uint8 num_results;
                dcerpc_ack_ctx ctx_list[num_results];
-               [flag(NDR_ALIGN8)]    DATA_BLOB _pad2;
-               [flag(NDR_REMAINING)] DATA_BLOB auth_verifier;
+               [flag(NDR_REMAINING)] DATA_BLOB auth_info;
        } dcerpc_bind_ack;
 
        typedef struct {
@@ -75,21 +74,64 @@ interface dcerpc
                uint32 status;
        } dcerpc_fault;
 
+
+       const uint8 DCERPC_AUTH_TYPE_NONE    = 0;
+       const uint8 DCERPC_AUTH_TYPE_KRB5    = 1;
+       const uint8 DCERPC_AUTH_TYPE_NTLMSSP = 10;
+       
+       const uint8 DCERPC_AUTH_LEVEL_NONE      = 1;
+       const uint8 DCERPC_AUTH_LEVEL_CONNECT   = 2;
+       const uint8 DCERPC_AUTH_LEVEL_CALL      = 3;
+       const uint8 DCERPC_AUTH_LEVEL_PACKET    = 4;
+       const uint8 DCERPC_AUTH_LEVEL_INTEGRITY = 5;
+       const uint8 DCERPC_AUTH_LEVEL_PRIVACY   = 6;
+
+       typedef [public] struct {
+               uint8  auth_type; 
+               uint8  auth_level;
+               uint8  auth_pad_length;
+               uint8  auth_reserved;
+               uint32 auth_context_id;
+               [flag(NDR_REMAINING)] DATA_BLOB credentials;
+       } dcerpc_auth;
+
+       typedef [public] struct {
+               uint32 _pad;
+               [flag(NDR_REMAINING)] DATA_BLOB auth_info;
+       } dcerpc_auth3;
+
        typedef enum {
-               DCERPC_PKT_REQUEST=0,
-               DCERPC_PKT_RESPONSE=2,
-               DCERPC_PKT_FAULT=3,
-               DCERPC_PKT_BIND=11,
-               DCERPC_PKT_BIND_ACK=12,
-               DCERPC_PKT_BIND_NAK=13
+               DCERPC_PKT_REQUEST     =  0,
+               DCERPC_PKT_PING        =  1,
+               DCERPC_PKT_RESPONSE    =  2,
+               DCERPC_PKT_FAULT       =  3,
+               DCERPC_PKT_WORKING     =  4,
+               DCERPC_PKT_NOCALL      =  5,
+               DCERPC_PKT_REJECT      =  6,
+               DCERPC_PKT_ACK         =  7,
+               DCERPC_PKT_CL_CANCEL   =  8,
+               DCERPC_PKT_FACK        =  9,
+               DCERPC_PKT_CANCEL_ACK  = 10,
+               DCERPC_PKT_BIND        = 11,
+               DCERPC_PKT_BIND_ACK    = 12,
+               DCERPC_PKT_BIND_NAK    = 13,
+               DCERPC_PKT_ALTER       = 14,
+               DCERPC_PKT_ALTER_ACK   = 15,
+               DCERPC_PKT_AUTH3       = 16,
+               DCERPC_PKT_SHUTDOWN    = 17,
+               DCERPC_PKT_CO_CANCEL   = 18,
+               DCERPC_PKT_ORPHANED    = 19
        } dcerpc_pkt_type;
 
        typedef [nodiscriminant] union {
-               [case(DCERPC_PKT_REQUEST)]  dcerpc_request  request;
-               [case(DCERPC_PKT_RESPONSE)] dcerpc_response response;
-               [case(DCERPC_PKT_BIND)]     dcerpc_bind     bind;
-               [case(DCERPC_PKT_BIND_ACK)] dcerpc_bind_ack bind_ack;
-               [case(DCERPC_PKT_FAULT)]    dcerpc_fault    fault;
+               [case(DCERPC_PKT_REQUEST)]   dcerpc_request  request;
+               [case(DCERPC_PKT_RESPONSE)]  dcerpc_response response;
+               [case(DCERPC_PKT_BIND)]      dcerpc_bind     bind;
+               [case(DCERPC_PKT_BIND_ACK)]  dcerpc_bind_ack bind_ack;
+               [case(DCERPC_PKT_ALTER)]     dcerpc_bind     alter;
+               [case(DCERPC_PKT_ALTER_ACK)] dcerpc_bind_ack alter_ack;
+               [case(DCERPC_PKT_FAULT)]     dcerpc_fault    fault;
+               [case(DCERPC_PKT_AUTH3)]     dcerpc_auth3    auth;
        } dcerpc_payload;
 
 
index 6116150cea01f62fe8cd9a348fa2112897f2498e..9915ba4212c2d9fa8d4149a9090f23e3e5937cc5 100644 (file)
 
 #define NDR_BASE_MARSHALL_SIZE 1024
 
+/*
+  only include interfaces that contain callable dcerpc functions here
+*/
 const struct dcerpc_interface_table *dcerpc_pipes[] = {
        &dcerpc_table_samr,
        &dcerpc_table_lsarpc,
        &dcerpc_table_netdfs,
        &dcerpc_table_atsvc,
-       &dcerpc_table_dcerpc,
        &dcerpc_table_rpcecho,
        &dcerpc_table_epmapper,
        &dcerpc_table_eventlog,
@@ -93,31 +95,6 @@ NTSTATUS ndr_pull_subcontext(struct ndr_pull *ndr, struct ndr_pull *ndr2, uint32
 }
 
 
-/* limit the remaining size of the current ndr parse structure to the
-   given size, starting at the given offset 
-
-   this is used when a ndr packet has an explicit size on the wire, and we
-   need to make sure that we don't use more data than is indicated
-
-   the 'ofs' parameter indicates how many bytes back from the current
-   offset in the buffer the 'size' number of bytes starts
-*/
-NTSTATUS ndr_pull_limit_size(struct ndr_pull *ndr, uint32 size, uint32 ofs)
-{
-       uint32 new_size;
-       new_size = ndr->offset + size - ofs;
-
-       if (new_size > ndr->data_size) {
-               return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, 
-                                     "ndr_pull_limit_size %s %u failed",
-                                     size, ofs);
-       }
-       ndr->data_size = new_size;
-
-       return NT_STATUS_OK;
-}
-
-
 /*
   advance by 'size' bytes
 */
@@ -780,7 +757,7 @@ NTSTATUS ndr_pull_union_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, uint32 level,
   pull a struct from a blob using NDR
 */
 NTSTATUS ndr_pull_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
-                             NTSTATUS (*fn)(struct ndr_pull *, int ndr_flags, void *))
+                             NTSTATUS (*fn)(struct ndr_pull *, int , void *))
 {
        struct ndr_pull *ndr;
        ndr = ndr_pull_init_blob(blob, mem_ctx);
@@ -790,4 +767,24 @@ NTSTATUS ndr_pull_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
        return fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
 }
 
+/*
+  push a struct to a blob using NDR
+*/
+NTSTATUS ndr_push_struct_blob(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, void *p,
+                             NTSTATUS (*fn)(struct ndr_push *, int , void *))
+{
+       NTSTATUS status;
+       struct ndr_push *ndr;
+       ndr = ndr_push_init_ctx(mem_ctx);
+       if (!ndr) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       status = fn(ndr, NDR_SCALARS|NDR_BUFFERS, p);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
+       *blob = ndr_push_blob(ndr);
+
+       return NT_STATUS_OK;
+}
index 1f78bc17b615e784d1cdb04d9c0452145dac2463..52f4d294284bb2dbe28a045e153b5911bcdbadea 100644 (file)
@@ -256,6 +256,17 @@ NTSTATUS ndr_push_bytes(struct ndr_push *ndr, const char *data, uint32 n)
        return NT_STATUS_OK;
 }
 
+/*
+  push some zero bytes
+*/
+NTSTATUS ndr_push_zero(struct ndr_push *ndr, uint32 n)
+{
+       NDR_PUSH_NEED_BYTES(ndr, n);
+       memset(ndr->data + ndr->offset, 0, n);
+       ndr->offset += n;
+       return NT_STATUS_OK;
+}
+
 /*
   push an array of uint8
 */
@@ -298,27 +309,6 @@ void ndr_push_restore(struct ndr_push *ndr, struct ndr_push_save *save)
        ndr->offset = save->offset;
 }
 
-/*
-  this is used when a packet has a 4 byte length field. We remember the start position
-  and come back to it later to fill in the size
-*/
-NTSTATUS ndr_push_length4_start(struct ndr_push *ndr, struct ndr_push_save *save)
-{
-       NDR_PUSH_ALIGN(ndr, 4);
-       ndr_push_save(ndr, save);
-       return ndr_push_uint32(ndr, 0);
-}
-
-NTSTATUS ndr_push_length4_end(struct ndr_push *ndr, struct ndr_push_save *save)
-{
-       struct ndr_push_save save2;
-       ndr_push_save(ndr, &save2);
-       ndr_push_restore(ndr, save);
-       NDR_CHECK(ndr_push_uint32(ndr, save2.offset - ndr->offset));
-       ndr_push_restore(ndr, &save2);
-       return NT_STATUS_OK;
-}
-
 /*
   push a 1 if a pointer is non-NULL, otherwise 0
 */
@@ -576,34 +566,6 @@ NTSTATUS ndr_push_string(struct ndr_push *ndr, int ndr_flags, const char *s)
        return NT_STATUS_OK;
 }
 
-/*
-  push a 4 byte offset pointer, remembering where we are so we can later fill
-  in the correct value
-*/
-NTSTATUS ndr_push_offset(struct ndr_push *ndr, struct ndr_push_save *ofs)
-{
-       NDR_PUSH_ALIGN(ndr, 4);
-       ndr_push_save(ndr, ofs);
-       return ndr_push_uint32(ndr, 0);
-}
-
-/*
-  fill in the correct offset in a saved offset pointer
-  the offset is taken relative to 'save'
-*/
-NTSTATUS ndr_push_offset_ptr(struct ndr_push *ndr, 
-                            struct ndr_push_save *ofs, 
-                            struct ndr_push_save *save)
-{
-       struct ndr_push_save save2;
-       ndr_push_save(ndr, &save2);
-       ndr_push_restore(ndr, ofs);
-       NDR_CHECK(ndr_push_uint32(ndr, save2.offset - save->offset));
-       ndr_push_restore(ndr, &save2);
-       return NT_STATUS_OK;
-}
-
-
 /*
   push a GUID
 */
@@ -761,7 +723,9 @@ NTSTATUS GUID_from_string(const char *s, struct GUID *guid)
         return NT_STATUS_OK;
 }
 
-
+/*
+  its useful to be able to display these in debugging messages
+*/
 const char *GUID_string(TALLOC_CTX *mem_ctx, const struct GUID *guid)
 {
        return talloc_asprintf(mem_ctx, 
index 012677a122a3dbd45f030bd7c38fb264e4bdbd23..bf5da4edb497145c6281079b214801ad627e5bc8 100644 (file)
@@ -41,6 +41,8 @@ struct dcerpc_pipe *dcerpc_pipe_init(void)
        p->reference_count = 0;
        p->mem_ctx = mem_ctx;
        p->call_id = 1;
+       p->auth_info = NULL;
+       p->ntlmssp_state = NULL;
 
        return p;
 }
@@ -61,7 +63,8 @@ void dcerpc_pipe_close(struct dcerpc_pipe *p)
    parse a data blob into a dcerpc_packet structure. This handles both
    input and output packets
 */
-NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
+static NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
+                           struct dcerpc_packet *pkt)
 {
        struct ndr_pull *ndr;
 
@@ -73,32 +76,169 @@ NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet
        return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
 }
 
+/* 
+   parse a possibly signed blob into a dcerpc request packet structure
+*/
+static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, 
+                                        DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
+                                        struct dcerpc_packet *pkt)
+{
+       struct ndr_pull *ndr;
+       NTSTATUS status;
+       struct dcerpc_auth auth;
+       DATA_BLOB auth_blob;
+
+       /* non-signed packets are simpler */
+       if (!p->auth_info || !p->ntlmssp_state) {
+               return dcerpc_pull(blob, mem_ctx, pkt);
+       }
+
+       ndr = ndr_pull_init_blob(blob, mem_ctx);
+       if (!ndr) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* pull the basic packet */
+       status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (pkt->ptype != DCERPC_PKT_RESPONSE) {
+               return status;
+       }
+
+       auth_blob.length = 8 + pkt->auth_length;
+
+       /* check for a valid length */
+       if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
+               return NT_STATUS_INFO_LENGTH_MISMATCH;
+       }
+
+       auth_blob.data = 
+               pkt->u.response.stub_and_verifier.data + 
+               pkt->u.response.stub_and_verifier.length - auth_blob.length;
+       pkt->u.response.stub_and_verifier.length -= auth_blob.length;
+
+       /* pull the auth structure */
+       ndr = ndr_pull_init_blob(&auth_blob, mem_ctx);
+       if (!ndr) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* check the signature */
+       status = ntlmssp_check_packet(p->ntlmssp_state, 
+                                     pkt->u.response.stub_and_verifier.data, 
+                                     pkt->u.response.stub_and_verifier.length, 
+                                     &auth.credentials);
+
+       /* remove the indicated amount of paddiing */
+       if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
+               return NT_STATUS_INFO_LENGTH_MISMATCH;
+       }
+       pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
+
+       return status;
+}
+
 
 /* 
    push a dcerpc_packet into a blob. This handles both input and
    output packets
 */
-NTSTATUS dcerpc_push(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
+static NTSTATUS dcerpc_push(struct dcerpc_pipe *p, 
+                           DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
+                           struct dcerpc_packet *pkt)
 {
-       struct ndr_push *ndr;
        NTSTATUS status;
+       struct ndr_push *ndr;
 
        ndr = ndr_push_init_ctx(mem_ctx);
        if (!ndr) {
                return NT_STATUS_NO_MEMORY;
        }
 
+       if (p->auth_info) {
+               pkt->auth_length = p->auth_info->credentials.length;
+       } else {
+               pkt->auth_length = 0;
+       }
+
        status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
+       if (p->auth_info) {
+               status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, 
+                                             p->auth_info);
+       }
+
        *blob = ndr_push_blob(ndr);
 
        /* fill in the frag length */
        SSVAL(blob->data, 8, blob->length);
 
-       return status;
+       return NT_STATUS_OK;
+}
+
+
+/* 
+   push a dcerpc request packet into a blob, possibly signing it.
+*/
+static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, 
+                                        DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
+                                        struct dcerpc_packet *pkt)
+{
+       NTSTATUS status;
+       struct ndr_push *ndr;
+
+       /* non-signed packets are simpler */
+       if (!p->auth_info || !p->ntlmssp_state) {
+               return dcerpc_push(p, blob, mem_ctx, pkt);
+       }
+
+       ndr = ndr_push_init_ctx(mem_ctx);
+       if (!ndr) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* pad to 8 byte multiple */
+       p->auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
+       ndr_push_zero(ndr, p->auth_info->auth_pad_length);
+
+       /* sign the packet */
+       status = ntlmssp_sign_packet(p->ntlmssp_state, 
+                                    ndr->data+24, ndr->offset-24,
+                                    &p->auth_info->credentials);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }       
+
+       /* add the auth verifier */
+       status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->auth_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* extract the whole packet as a blob */
+       *blob = ndr_push_blob(ndr);
+
+       /* fill in the fragment length and auth_length */
+       SSVAL(blob->data,  8, blob->length);
+       SSVAL(blob->data, 10, p->auth_info->credentials.length);
+
+       return NT_STATUS_OK;
 }
 
 
@@ -118,28 +258,25 @@ static void init_dcerpc_hdr(struct dcerpc_packet *pkt)
 
 /* 
    perform a bind using the given syntax 
+
+   the auth_info structure is updated with the reply authentication info
+   on success
 */
 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
+                    TALLOC_CTX *mem_ctx,
                     const struct dcerpc_syntax_id *syntax,
                     const struct dcerpc_syntax_id *transfer_syntax)
 {
-       TALLOC_CTX *mem_ctx;
        struct dcerpc_packet pkt;
        NTSTATUS status;
        DATA_BLOB blob;
-       DATA_BLOB blob_out;
        struct dcerpc_syntax_id tsyntax;
 
-       mem_ctx = talloc_init("dcerpc_bind");
-       if (!mem_ctx) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
        init_dcerpc_hdr(&pkt);
 
        pkt.ptype = DCERPC_PKT_BIND;
        pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
-       pkt.call_id = p->call_id++;
+       pkt.call_id = p->call_id;
        pkt.auth_length = 0;
 
        pkt.u.bind.max_xmit_frag = 0x2000;
@@ -148,7 +285,6 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
        pkt.u.bind.num_contexts = 1;
        pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
        if (!pkt.u.bind.ctx_list) {
-               talloc_destroy(mem_ctx);
                return NT_STATUS_NO_MEMORY;
        }
        pkt.u.bind.ctx_list[0].context_id = 0;
@@ -156,23 +292,23 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
        pkt.u.bind.ctx_list[0].abstract_syntax = *syntax;
        tsyntax = *transfer_syntax;
        pkt.u.bind.ctx_list[0].transfer_syntaxes = &tsyntax;
-       pkt.u.bind.auth_verifier = data_blob(NULL, 0);
+       pkt.u.bind.auth_info = data_blob(NULL, 0);
 
-       status = dcerpc_push(&blob, mem_ctx, &pkt);
+       /* construct the NDR form of the packet */
+       status = dcerpc_push(p, &blob, mem_ctx, &pkt);
        if (!NT_STATUS_IS_OK(status)) {
-               talloc_destroy(mem_ctx);
                return status;
        }
 
-       status = p->transport.full_request(p, mem_ctx, &blob, &blob_out);
+       /* send it on its way */
+       status = p->transport.full_request(p, mem_ctx, &blob, &blob);
        if (!NT_STATUS_IS_OK(status)) {
-               talloc_destroy(mem_ctx);
                return status;
        }
 
-       status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
+       /* unmarshall the NDR */
+       status = dcerpc_pull(&blob, mem_ctx, &pkt);
        if (!NT_STATUS_IS_OK(status)) {
-               talloc_destroy(mem_ctx);
                return status;
        }
 
@@ -185,13 +321,55 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
        p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
        p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
 
-       talloc_destroy(mem_ctx);
+       /* the bind_ack might contain a reply set of credentials */
+       if (p->auth_info && pkt.u.bind_ack.auth_info.length) {
+               status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
+                                             mem_ctx,
+                                             p->auth_info,
+                                             (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
+       }
 
        return status;  
 }
 
-/* Perform a bind using the given UUID and version */
+/* 
+   perform a continued bind (and auth3)
+*/
+NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p, 
+                     TALLOC_CTX *mem_ctx)
+{
+       struct dcerpc_packet pkt;
+       NTSTATUS status;
+       DATA_BLOB blob;
+
+       init_dcerpc_hdr(&pkt);
+
+       pkt.ptype = DCERPC_PKT_AUTH3;
+       pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
+       pkt.call_id = p->call_id++;
+       pkt.auth_length = 0;
+       pkt.u.auth._pad = 0;
+       pkt.u.auth.auth_info = data_blob(NULL, 0);
+
+       /* construct the NDR form of the packet */
+       status = dcerpc_push(p, &blob, mem_ctx, &pkt);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       /* send it on its way */
+       status = p->transport.initial_request(p, mem_ctx, &blob);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       return status;  
+}
+
+
+/* perform a dcerpc bind, using the uuid as the key */
 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
+                           TALLOC_CTX *mem_ctx,
                            const char *uuid, unsigned version)
 {
        struct dcerpc_syntax_id syntax;
@@ -215,7 +393,7 @@ NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
        transfer_syntax.major_version = 2;
        transfer_syntax.minor_version = 0;
 
-       return dcerpc_bind(p, &syntax, &transfer_syntax);
+       return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
 }
 
 /*
@@ -230,7 +408,7 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
        
        struct dcerpc_packet pkt;
        NTSTATUS status;
-       DATA_BLOB blob_in, blob_out, payload;
+       DATA_BLOB blob, payload;
        uint32 remaining, chunk_size;
 
        init_dcerpc_hdr(&pkt);
@@ -261,12 +439,12 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
                        (stub_data_in->length - remaining);
                pkt.u.request.stub_and_verifier.length = chunk_size;
 
-               status = dcerpc_push(&blob_in, mem_ctx, &pkt);
+               status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
                
-               status = p->transport.initial_request(p, mem_ctx, &blob_in);
+               status = p->transport.initial_request(p, mem_ctx, &blob);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }               
@@ -285,15 +463,18 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
                (stub_data_in->length - remaining);
        pkt.u.request.stub_and_verifier.length = remaining;
 
-       status = dcerpc_push(&blob_in, mem_ctx, &pkt);
+       status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
        /* send the pdu and get the initial response pdu */
-       status = p->transport.full_request(p, mem_ctx, &blob_in, &blob_out);
+       status = p->transport.full_request(p, mem_ctx, &blob, &blob);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
 
-       status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
+       status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -317,12 +498,12 @@ NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
        while (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
                uint32 length;
 
-               status = p->transport.secondary_request(p, mem_ctx, &blob_out);
+               status = p->transport.secondary_request(p, mem_ctx, &blob);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
 
-               status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
+               status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
@@ -568,6 +749,9 @@ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
                goto failed;
        }
 
+       /* possibly check the packet signature */
+       
+
        if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
                status = dcerpc_ndr_validate_out(mem_ctx, struct_ptr, struct_size, 
                                                 ndr_push, ndr_pull);
index e0e7c8bd5a68feb568428bfc791ec11b512e910a..e41b998d903e7d873594131946010851f2d1d1b4 100644 (file)
@@ -36,6 +36,8 @@ struct dcerpc_pipe {
        uint32 srv_max_xmit_frag;
        uint32 srv_max_recv_frag;
        unsigned flags;
+       struct ntlmssp_state *ntlmssp_state;
+       struct dcerpc_auth *auth_info;
 
        struct dcerpc_transport {
                void *private;
diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
new file mode 100644 (file)
index 0000000..32fdcb0
--- /dev/null
@@ -0,0 +1,130 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   dcerpc authentication operations
+
+   Copyright (C) Andrew Tridgell 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"
+
+/*
+  do a simple ntlm style authentication on a dcerpc pipe
+*/
+NTSTATUS dcerpc_bind_auth_ntlm(struct dcerpc_pipe *p,
+                              const char *uuid, unsigned version,
+                              const char *domain,
+                              const char *username,
+                              const char *password)
+{
+       NTSTATUS status;
+       struct ntlmssp_state *state;
+       TALLOC_CTX *mem_ctx;
+
+       mem_ctx = talloc_init("dcerpc_bind_auth_ntlm");
+       if (!mem_ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = ntlmssp_client_start(&state);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = ntlmssp_set_domain(state, domain);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto done;
+       }
+       
+       status = ntlmssp_set_username(state, username);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto done;
+       }
+
+       status = ntlmssp_set_password(state, password);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto done;
+       }
+
+       p->auth_info = talloc(p->mem_ctx, sizeof(*p->auth_info));
+       if (!p->auth_info) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       p->auth_info->auth_type = DCERPC_AUTH_TYPE_NTLMSSP;
+       p->auth_info->auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
+       p->auth_info->auth_pad_length = 0;
+       p->auth_info->auth_reserved = 0;
+       p->auth_info->auth_context_id = random();
+       p->auth_info->credentials = data_blob(NULL, 0);
+       p->ntlmssp_state = NULL;
+
+       status = ntlmssp_update(state, 
+                               p->auth_info->credentials,
+                               &p->auth_info->credentials);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               goto done;
+       }
+       status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto done;
+       }
+
+       status = ntlmssp_update(state, 
+                               p->auth_info->credentials, 
+                               &p->auth_info->credentials);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               goto done;
+       }
+
+       status = dcerpc_auth3(p, mem_ctx);
+       p->ntlmssp_state = state;
+       p->auth_info->credentials = data_blob(NULL, 0);
+
+       ntlmssp_sign_init(state);
+
+done:
+       talloc_destroy(mem_ctx);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               p->ntlmssp_state = NULL;
+       }
+
+       return status;
+}
+
+
+/*
+  do a non-athenticated dcerpc bind
+*/
+NTSTATUS dcerpc_bind_auth_none(struct dcerpc_pipe *p,
+                              const char *uuid, unsigned version)
+{
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS status;
+
+       mem_ctx = talloc_init("dcerpc_bind_auth_ntlm");
+       if (!mem_ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = dcerpc_bind_byuuid(p, mem_ctx, uuid, version);
+       talloc_destroy(mem_ctx);
+
+       return status;
+}
index 6af997275c24d562e2f01cd275bf1011d3821589..9acae002491270fc5125b3a535a597eb48964437 100644 (file)
@@ -301,9 +301,7 @@ static const char *smb_peer_name(struct dcerpc_pipe *p)
 */
 NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p, 
                              struct cli_tree *tree,
-                             const char *pipe_name,
-                             const char *pipe_uuid, 
-                             uint32 pipe_version)
+                             const char *pipe_name)
 {
        struct smb_private *smb;
         NTSTATUS status;
@@ -375,12 +373,5 @@ NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe **p,
        (*p)->transport.private = smb;
        tree->reference_count++;
 
-       /* bind to the pipe, using the uuid as the key */
-       status = dcerpc_bind_byuuid(*p, pipe_uuid, pipe_version);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               dcerpc_pipe_close(*p);
-       }
-
         return NT_STATUS_OK;
 }
index ec94baf5832d064ef417b6d61e9727b6047f5f68..b3523e6855d5bcad24e4c2ca389c459c1e17321f 100644 (file)
@@ -146,12 +146,9 @@ static const char *tcp_peer_name(struct dcerpc_pipe *p)
 */
 NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p, 
                              const char *server,
-                             uint32 port,
-                             const char *pipe_uuid, 
-                             uint32 pipe_version)
+                             uint32 port)
 {
        struct tcp_private *tcp;
-        NTSTATUS status;
        int fd;
        struct in_addr addr;
 
@@ -194,13 +191,5 @@ NTSTATUS dcerpc_pipe_open_tcp(struct dcerpc_pipe **p,
 
        (*p)->transport.private = tcp;
 
-       /* bind to the pipe, using the uuid as the key */
-       status = dcerpc_bind_byuuid(*p, pipe_uuid, pipe_version);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               dcerpc_pipe_close(*p);
-               return status;
-       }
-
         return NT_STATUS_OK;
 }
index cef3355b8a5f00f24d8706e18fe7453a0d6848a6..c5020cad4b4276a83d5a2707cec0f0fcbdebb3d9 100644 (file)
@@ -72,6 +72,14 @@ static void display_tower(TALLOC_CTX *mem_ctx, struct epm_towers *twr)
                        break;
 
                case 0x1f:
+                       printf(" TCP2:");
+                       if (rhs->rhs_data.length == 2) {
+                               printf("%d", RSVAL(rhs->rhs_data.data, 0));
+                       }
+                       break;
+
+               case 0x07:
+                       /* what is the difference between this and 0x1f? */
                        printf(" TCP:");
                        if (rhs->rhs_data.length == 2) {
                                printf("%d", RSVAL(rhs->rhs_data.data, 0));
index 22798ed236febbec9c51dc24655cc6e12e294376..11b27f12ebfb227d7de37e4d0daea27c8be3ccb5 100644 (file)
@@ -142,8 +142,7 @@ static NTSTATUS torture_rpc_tcp(struct dcerpc_pipe **p,
 
        DEBUG(2,("Connecting to dcerpc server %s:%s\n", host, port));
 
-       status = dcerpc_pipe_open_tcp(p, host, atoi(port),
-                                     pipe_uuid, pipe_version);
+       status = dcerpc_pipe_open_tcp(p, host, atoi(port));
        if (!NT_STATUS_IS_OK(status)) {
                 printf("Open of pipe '%s' failed with error (%s)\n",
                       pipe_name, nt_errstr(status));
@@ -152,6 +151,16 @@ static NTSTATUS torture_rpc_tcp(struct dcerpc_pipe **p,
 
        /* always do NDR validation in smbtorture */
        (*p)->flags |= DCERPC_DEBUG_VALIDATE_BOTH;
+
+       /* bind to the pipe, using the uuid as the key */
+       status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version,
+                                      lp_workgroup(),
+                                      lp_parm_string(-1, "torture", "username"),
+                                      lp_parm_string(-1, "torture", "password"));
+       if (!NT_STATUS_IS_OK(status)) {
+               dcerpc_pipe_close(*p);
+               return status;
+       }
  
         return status;
 }
@@ -176,11 +185,15 @@ NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       if (! *lp_parm_string(-1, "torture", "share")) {
+               lp_set_cmdline("torture:share", "ipc$");
+       }
+
        if (!torture_open_connection(&cli)) {
                 return NT_STATUS_UNSUCCESSFUL;
        }
 
-       status = dcerpc_pipe_open_smb(p, cli->tree, pipe_name, pipe_uuid, pipe_version);
+       status = dcerpc_pipe_open_smb(p, cli->tree, pipe_name);
        if (!NT_STATUS_IS_OK(status)) {
                 printf("Open of pipe '%s' failed with error (%s)\n",
                       pipe_name, nt_errstr(status));
@@ -188,6 +201,20 @@ NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p,
                 return status;
         }
 
+       /* bind to the pipe, using the uuid as the key */
+#if 1
+       status = dcerpc_bind_auth_ntlm(*p, pipe_uuid, pipe_version,
+                                      lp_workgroup(),
+                                      lp_parm_string(-1, "torture", "username"),
+                                      lp_parm_string(-1, "torture", "password"));
+#else
+       status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
+#endif
+       if (!NT_STATUS_IS_OK(status)) {
+               dcerpc_pipe_close(*p);
+               return status;
+       }
+
        /* always do NDR validation in smbtorture */
        (*p)->flags |= DCERPC_DEBUG_VALIDATE_BOTH;