[PATCH] Add NTLMv2 support for Samba HEAD

Andrew Bartlett abartlet at pcug.org.au
Sat Jun 16 13:00:46 GMT 2001


OK, now with patch attached.  It even compiles...  (still only as tested
as it was before, ie not in this partiular form).

In particular, the srv_pipe stuff is untested - sorry.

Andrew Bartlett wrote:
> 
> Tim, I noticed you have started merging some of the smbencrypt.c stuff
> over from TNG, so I decided to look at how much was left to do NTLMv2.
> This is the stuff I was working on when I was last in the office.
> 
> In any case, the patch is now quite small.  This code was tested with
> TNG's smbclient, but I didn't get a chance to test with anything else
> before I had to leave.
> 
> The major issue with the previous incarnation of this patch (a few
> months ago) was the licensing of the md5 code, which is now resolved.
> The only remaining issue is big/little edeinness, but I'm not an expert
> in that area (lib/md5.c is where to look).
> 
> This patch adds NTLMv2 for reply.c server functionality only, I will add
> domain login support when I rewrite the whole thing (I'm not going to do
> it twice...).  We also need to do client support, which I have not even
> looked at.
> 
> Hope its useful.
> 
> Andrew Bartlett
> 
> --
> Andrew Bartlett
> abartlet at pcug.org.au

-- 
Andrew Bartlett
abartlet at pcug.org.au
-------------- next part --------------
--- /dev/null	Thu Aug 24 19:00:32 2000
+++ source/lib/md5.c	Tue Jun  5 15:25:53 2001
@@ -0,0 +1,252 @@
+#if 0
+#include <libdefs.h>
+#endif
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "includes.h"
+
+#include "md5.h"
+
+#ifndef WORDS_BIGENDIAN
+#define byteReverse(buf, len)	/* Nothing */
+#else
+static void byteReverse(unsigned char *buf, unsigned longs);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32 t;
+    do {
+	t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+	    ((unsigned) buf[1] << 8 | buf[0]);
+	*(uint32 *) buf = t;
+	buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    register uint32 t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+	ctx->bits[1]++;		/* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+	unsigned char *p = (unsigned char *) ctx->in + t;
+
+	t = 64 - t;
+	if (len < t) {
+	    memmove(p, buf, len);
+	    return;
+	}
+	memmove(p, buf, t);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+	buf += t;
+	len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+	memmove(ctx->in, buf, 64);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+	buf += 64;
+	len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memmove(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned int count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+	/* Two lots of padding:  Pad the first block to 64 bytes */
+	memset(p, 0, count);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+	/* Now fill the next block with 56 bytes */
+	memset(ctx->in, 0, 56);
+    } else {
+	/* Pad block to 56 bytes */
+	memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32 *) ctx->in)[14] = ctx->bits[0];
+    ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32 *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memmove(digest, ctx->buf, 16);
+    memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32 buf[4], uint32 const in[16])
+{
+    register uint32 a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
--- /dev/null	Thu Aug 24 19:00:32 2000
+++ source/include/md5.h	Tue Jun  5 15:06:39 2001
@@ -0,0 +1,21 @@
+#ifndef MD5_H
+#define MD5_H
+
+struct MD5Context {
+	uint32 buf[4];
+	uint32 bits[2];
+	unsigned char in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+	       unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
--- /dev/null	Thu Aug 24 19:00:32 2000
+++ source/include/hmacmd5.h	Tue Jun  5 14:24:23 2001
@@ -0,0 +1,33 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   Interface header: Scheduler service
+   Copyright (C) Luke Kenneth Casson Leighton 1996-1999
+   Copyright (C) Andrew Tridgell 1992-1999
+   
+   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.
+*/
+
+#ifndef _HMAC_MD5_H
+
+typedef struct 
+{
+        struct MD5Context ctx;
+        uchar k_ipad[65];    
+        uchar k_opad[65];
+
+} HMACMD5Context;
+
+#endif /* _HMAC_MD5_H */
--- /dev/null	Thu Aug 24 19:00:32 2000
+++ source/lib/hmacmd5.c	Tue Jun  5 15:15:05 2001
@@ -0,0 +1,136 @@
+/* 
+   Unix SMB/Netbios implementation.
+   Version 1.9.
+   Interface header: Scheduler service
+   Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+   Copyright (C) Andrew Tridgell 1992-2000
+   
+   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.
+*/
+
+/* taken direct from rfc2104 implementation and modified for suitable use
+ * for ntlmv2.
+ */
+
+#include "includes.h"
+
+/***********************************************************************
+ the rfc 2104 version of hmac_md5 initialisation.
+***********************************************************************/
+void hmac_md5_init_rfc2104(uchar*  key, int key_len, HMACMD5Context *ctx)
+{
+        int i;
+
+        /* if key is longer than 64 bytes reset it to key=MD5(key) */
+        if (key_len > 64)
+	{
+		uchar tk[16];
+                struct MD5Context tctx;
+
+                MD5Init(&tctx);
+                MD5Update(&tctx, key, key_len);
+                MD5Final(tk, &tctx);
+
+                key = tk;
+                key_len = 16;
+        }
+
+        /* start out by storing key in pads */
+        ZERO_STRUCT(ctx->k_ipad);
+        ZERO_STRUCT(ctx->k_opad);
+        bcopy( key, ctx->k_ipad, key_len);
+        bcopy( key, ctx->k_opad, key_len);
+
+        /* XOR key with ipad and opad values */
+        for (i=0; i<64; i++)
+	{
+                ctx->k_ipad[i] ^= 0x36;
+                ctx->k_opad[i] ^= 0x5c;
+        }
+
+        MD5Init(&ctx->ctx);
+        MD5Update(&ctx->ctx, ctx->k_ipad, 64);  
+}
+
+/***********************************************************************
+ the microsoft version of hmac_md5 initialisation.
+***********************************************************************/
+void hmac_md5_init_limK_to_64(const uchar* key, int key_len,
+			HMACMD5Context *ctx)
+{
+        int i;
+
+        /* if key is longer than 64 bytes truncate it */
+        if (key_len > 64)
+	{
+                key_len = 64;
+        }
+
+        /* start out by storing key in pads */
+        ZERO_STRUCT(ctx->k_ipad);
+        ZERO_STRUCT(ctx->k_opad);
+        bcopy( key, ctx->k_ipad, key_len);
+        bcopy( key, ctx->k_opad, key_len);
+
+        /* XOR key with ipad and opad values */
+        for (i=0; i<64; i++)
+	{
+                ctx->k_ipad[i] ^= 0x36;
+                ctx->k_opad[i] ^= 0x5c;
+        }
+
+        MD5Init(&ctx->ctx);
+        MD5Update(&ctx->ctx, ctx->k_ipad, 64);  
+}
+
+/***********************************************************************
+ update hmac_md5 "inner" buffer
+***********************************************************************/
+void hmac_md5_update(const uchar* text, int text_len, HMACMD5Context *ctx)
+{
+        MD5Update(&ctx->ctx, text, text_len); /* then text of datagram */
+}
+
+/***********************************************************************
+ finish off hmac_md5 "inner" buffer and generate outer one.
+***********************************************************************/
+void hmac_md5_final(uchar *digest, HMACMD5Context *ctx)
+
+{
+        struct MD5Context ctx_o;
+
+        MD5Final(digest, &ctx->ctx);          
+
+        MD5Init(&ctx_o);
+        MD5Update(&ctx_o, ctx->k_opad, 64);   
+        MD5Update(&ctx_o, digest, 16); 
+        MD5Final(digest, &ctx_o);
+}
+
+/***********************************************************
+ single function to calculate an HMAC MD5 digest from data.
+ use the microsoft hmacmd5 init method because the key is 16 bytes.
+************************************************************/
+void hmac_md5( uchar key[16], uchar* data, int data_len, uchar* digest)
+{
+	HMACMD5Context ctx;
+	hmac_md5_init_limK_to_64(key, 16, &ctx);
+	if (data_len != 0)
+	{
+		hmac_md5_update(data, data_len, &ctx);
+	}
+	hmac_md5_final(digest, &ctx);
+}
+
-------------- next part --------------
Index: source/Makefile.in
===================================================================
RCS file: /cvsroot/samba/source/Makefile.in,v
retrieving revision 1.296
diff -u -r1.296 Makefile.in
--- source/Makefile.in	6 Jun 2001 07:35:08 -0000	1.296
+++ source/Makefile.in	16 Jun 2001 12:39:05 -0000
@@ -105,6 +105,7 @@
 	  lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o \
 	  lib/talloc.o lib/hash.o lib/substitute.o lib/fsusage.o \
 	  lib/ms_fnmatch.o lib/select.o lib/error.o lib/messages.o \
+	  lib/md5.o lib/hmacmd5.o \
 	  nsswitch/wb_client.o nsswitch/wb_common.o $(TDB_OBJ)
 
 READLINE_OBJ = lib/readline.o
Index: source/include/smb.h
===================================================================
RCS file: /cvsroot/samba/source/include/smb.h,v
retrieving revision 1.358
diff -u -r1.358 smb.h
--- source/include/smb.h	8 Jun 2001 03:02:33 -0000	1.358
+++ source/include/smb.h	16 Jun 2001 12:39:27 -0000
@@ -25,6 +25,9 @@
 #ifndef _SMB_H
 #define _SMB_H
 
+#include "md5.h"
+#include "hmacmd5.h"
+
 #define BUFFER_SIZE (0xFFFF)
 #define SAFETY_MARGIN 1024
 #define LARGE_WRITEX_HDR_SIZE 65
Index: source/lib/md4.c
===================================================================
RCS file: /cvsroot/samba/source/lib/md4.c,v
retrieving revision 1.9
diff -u -r1.9 md4.c
--- source/lib/md4.c	13 Dec 1999 13:27:16 -0000	1.9
+++ source/lib/md4.c	16 Jun 2001 12:39:27 -0000
@@ -101,7 +101,7 @@
 		X[j] = 0;
 }
 
-static void copy64(uint32 *M, unsigned char *in)
+static void copy64(uint32 *M, const unsigned char *in)
 {
 	int i;
 
@@ -110,7 +110,7 @@
 			(in[i*4+1]<<8) | (in[i*4+0]<<0);
 }
 
-static void copy4(unsigned char *out,uint32 x)
+static void copy4(unsigned char *out, const uint32 x)
 {
 	out[0] = x&0xFF;
 	out[1] = (x>>8)&0xFF;
@@ -119,7 +119,7 @@
 }
 
 /* produce a md4 message digest from data of length n bytes */
-void mdfour(unsigned char *out, unsigned char *in, int n)
+void mdfour(unsigned char *out, const unsigned char *in, int n)
 {
 	unsigned char buf[128];
 	uint32 M[16];
Index: source/libsmb/smbdes.c
===================================================================
RCS file: /cvsroot/samba/source/libsmb/smbdes.c,v
retrieving revision 1.30
diff -u -r1.30 smbdes.c
--- source/libsmb/smbdes.c	13 Dec 1999 13:27:21 -0000	1.30
+++ source/libsmb/smbdes.c	16 Jun 2001 12:39:27 -0000
@@ -259,7 +259,7 @@
 	permute(out, rl, perm6, 64);
 }
 
-static void str_to_key(unsigned char *str,unsigned char *key)
+static void str_to_key(const unsigned char *str,unsigned char *key)
 {
 	int i;
 
@@ -277,7 +277,7 @@
 }
 
 
-static void smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
+static void smbhash(unsigned char *out, const unsigned char *in, const unsigned char *key, int forw)
 {
 	int i;
 	char outb[64];
@@ -305,14 +305,14 @@
 	}
 }
 
-void E_P16(unsigned char *p14,unsigned char *p16)
+void E_P16(const unsigned char *p14,unsigned char *p16)
 {
 	unsigned char sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
 	smbhash(p16, sp8, p14, 1);
 	smbhash(p16+8, sp8, p14+7, 1);
 }
 
-void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
+void E_P24(const unsigned char *p21, const unsigned char *c8, unsigned char *p24)
 {
 	smbhash(p24, c8, p21, 1);
 	smbhash(p24+8, c8, p21+7, 1);
Index: source/libsmb/smbencrypt.c
===================================================================
RCS file: /cvsroot/samba/source/libsmb/smbencrypt.c,v
retrieving revision 1.51
diff -u -r1.51 smbencrypt.c
--- source/libsmb/smbencrypt.c	22 Apr 2001 02:54:04 -0000	1.51
+++ source/libsmb/smbencrypt.c	16 Jun 2001 12:39:34 -0000
@@ -4,6 +4,8 @@
    SMB parameters and setup
    Copyright (C) Andrew Tridgell 1992-1998
    Modified by Jeremy Allison 1995.
+   Copyright (C) Jeremy Allison 1995-2000.
+   Copyright (C) Luke Kennethc Casson Leighton 1996-2000.
    
    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
@@ -83,6 +85,24 @@
 	return i;
 }
 
+static int _my_mbstowcsupper(int16 * dst, const uchar * src, int len)
+{
+	int i;
+	int16 val;
+
+	for (i = 0; i < len; i++)
+	{
+		val = toupper(*src);
+		SSVAL(dst, 0, val);
+		dst++;
+		src++;
+		if (val == 0)
+			break;
+	}
+	return i;
+}
+
+
 /* 
  * Creates the MD4 Hash of the users password in NT UNICODE.
  */
@@ -141,8 +161,36 @@
 	memset(passwd, '\0', sizeof(passwd));
 }
 
+/* Does both the NTLMv2 owfs of a user's password */
+void ntv2_owf_gen(const uchar owf[16],
+		  const char *user_n, const char *domain_n, uchar kr_buf[16])
+{
+	pstring user_u;
+	pstring dom_u;
+	HMACMD5Context ctx;
+
+	int user_l = strlen(user_n);
+	int domain_l = strlen(domain_n);
+
+	_my_mbstowcsupper((int16 *) user_u, user_n, user_l * 2);
+	_my_mbstowcsupper((int16 *) dom_u, domain_n, domain_l * 2);
+
+	hmac_md5_init_limK_to_64(owf, 16, &ctx);
+	hmac_md5_update(user_u, user_l * 2, &ctx);
+	hmac_md5_update(dom_u, domain_l * 2, &ctx);
+	hmac_md5_final(kr_buf, &ctx);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("ntv2_owf_gen: user, domain, owfkey, kr\n"));
+	dump_data(100, user_u, user_l * 2);
+	dump_data(100, dom_u, domain_l * 2);
+	dump_data(100, owf, 16);
+	dump_data(100, kr_buf, 16);
+#endif
+}
+
 /* Does the des encryption from the NT or LM MD4 hash. */
-void SMBOWFencrypt(uchar passwd[16], uchar *c8, uchar p24[24])
+void SMBOWFencrypt(const uchar passwd[16], const uchar *c8, uchar p24[24])
 {
 	uchar p21[21];
  
@@ -226,6 +274,53 @@
 	SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True);
 
 	return True;
+}
+
+/* Does the md5 encryption from the NT hash for NTLMv2. */
+void SMBOWFencrypt_ntv2(const uchar kr[16],
+			const uchar * srv_chal, int srv_chal_len,
+			const uchar * cli_chal, int cli_chal_len,
+			char resp_buf[16])
+{
+	HMACMD5Context ctx;
+
+	hmac_md5_init_limK_to_64(kr, 16, &ctx);
+	hmac_md5_update(srv_chal, srv_chal_len, &ctx);
+	hmac_md5_update(cli_chal, cli_chal_len, &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, srv_chal_len);
+	dump_data(100, cli_chal, cli_chal_len);
+	dump_data(100, resp_buf, 16);
+#endif
+}
+
+void SMBsesskeygen_ntv2(const uchar kr[16],
+			const uchar * nt_resp, char sess_key[16])
+{
+	HMACMD5Context ctx;
+
+	hmac_md5_init_limK_to_64(kr, 16, &ctx);
+	hmac_md5_update(nt_resp, 16, &ctx);
+	hmac_md5_final(sess_key, &ctx);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("SMBsesskeygen_ntv2:\n"));
+	dump_data(100, sess_key, 16);
+#endif
+}
+
+void SMBsesskeygen_ntv1(const uchar kr[16],
+			const uchar * nt_resp, char sess_key[16])
+{
+	mdfour(sess_key, kr, 16);
+
+#ifdef DEBUG_PASSWORD
+	DEBUG(100, ("SMBsesskeygen_ntv1:\n"));
+	dump_data(100, sess_key, 16);
+#endif
 }
 
 /***********************************************************
Index: source/param/loadparm.c
===================================================================
RCS file: /cvsroot/samba/source/param/loadparm.c,v
retrieving revision 1.302
diff -u -r1.302 loadparm.c
--- source/param/loadparm.c	8 Jun 2001 03:02:34 -0000	1.302
+++ source/param/loadparm.c	16 Jun 2001 12:39:36 -0000
@@ -272,6 +272,7 @@
 	BOOL bAllowTrustedDomains;
 	BOOL bRestrictAnonymous;
 	BOOL bLanmanAuth;
+	BOOL bNTLMAuth;
 	BOOL bDebugHiresTimestamp;
 	BOOL bDebugPid;
 	BOOL bDebugUid;
@@ -698,6 +699,7 @@
 	{"unix password sync", P_BOOL, P_GLOBAL, &Globals.bUnixPasswdSync, NULL, NULL, 0},
 	{"restrict anonymous", P_BOOL, P_GLOBAL, &Globals.bRestrictAnonymous, NULL, NULL, 0},
 	{"lanman auth", P_BOOL, P_GLOBAL, &Globals.bLanmanAuth, NULL, NULL, 0},
+	{"ntlm auth", P_BOOL, P_GLOBAL, &Globals.bNTLMAuth, NULL, NULL, 0},
 	{"use rhosts", P_BOOL, P_GLOBAL, &Globals.bUseRhosts, NULL, NULL, 0},
 	
 	{"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE},
@@ -1288,6 +1290,7 @@
 	Globals.bStatCache = True;	/* use stat cache by default */
 	Globals.bRestrictAnonymous = False;
 	Globals.bLanmanAuth = True;	/* Do use the LanMan hash if it is available */
+        Globals.bNTLMAuth = True;       /* Do not use NTLMv1 authentication */
 	Globals.map_to_guest = 0;	/* By Default, "Never" */
 	Globals.min_passwd_length = MINPASSWDLENGTH;	/* By Default, 5. */
 	Globals.oplock_break_wait_time = 0;	/* By Default, 0 msecs. */
@@ -1560,6 +1563,7 @@
 FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains)
 FN_GLOBAL_BOOL(lp_restrict_anonymous, &Globals.bRestrictAnonymous)
 FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth)
+FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth)
 FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs)
 FN_GLOBAL_BOOL(lp_kernel_oplocks, &Globals.bKernelOplocks)
 FN_GLOBAL_BOOL(lp_enhanced_browsing, &Globals.enhanced_browsing)
Index: source/rpc_server/srv_pipe.c
===================================================================
RCS file: /cvsroot/samba/source/rpc_server/srv_pipe.c,v
retrieving revision 1.65
diff -u -r1.65 srv_pipe.c
--- source/rpc_server/srv_pipe.c	18 May 2001 01:30:21 -0000	1.65
+++ source/rpc_server/srv_pipe.c	16 Jun 2001 12:39:43 -0000
@@ -263,7 +263,7 @@
 static BOOL api_pipe_ntlmssp_verify(pipes_struct *p, RPC_AUTH_NTLMSSP_RESP *ntlmssp_resp)
 {
 	uchar lm_owf[24];
-	uchar nt_owf[24];
+	uchar nt_owf[128];
 	fstring user_name;
 	fstring pipe_user_name;
 	fstring domain;
@@ -363,7 +363,7 @@
 		become_root();
 
 		if(!(p->ntlmssp_auth_validated = pass_check_smb(pipe_user_name, domain,
-		                      (uchar*)p->challenge, lm_owf, nt_owf, NULL))) {
+		                      (uchar*)p->challenge, lm_owf, nt_owf, ntlmssp_resp->hdr_nt_resp.str_str_len, NULL))) {
 			DEBUG(1,("api_pipe_ntlmssp_verify: User %s\\%s from machine %s \
 failed authentication on named pipe %s.\n", domain, pipe_user_name, wks, p->name ));
 			unbecome_root();
Index: source/smbd/password.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/password.c,v
retrieving revision 1.216
diff -u -r1.216 password.c
--- source/smbd/password.c	14 Jun 2001 00:08:41 -0000	1.216
+++ source/smbd/password.c	16 Jun 2001 12:39:47 -0000
@@ -2,8 +2,9 @@
    Unix SMB/Netbios implementation.
    Version 1.9.
    Password and authentication handling
-   Copyright (C) Andrew Tridgell 1992-1998
-   
+   Copyright (C) Andrew Tridgell              1992-2000
+   Copyright (C) Luke Kenneth Casson Leighton 1996-2000
+    
    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
@@ -441,22 +442,66 @@
   return (memcmp(p24, password, 24) == 0);
 }
 
+
+/****************************************************************************
+core of smb password checking routine.
+****************************************************************************/
+static BOOL smb_pwd_check_ntlmv2(const char *password, int pwd_len,
+				uchar *part_passwd,
+				uchar const *c8,
+				const char *user, const char *domain)
+{
+	/* Finish the encryption of part_passwd. */
+	uchar kr[16];
+	uchar resp[16];
+
+	if (part_passwd == NULL)
+	{
+		DEBUG(10,("No password set - allowing access\n"));
+	}
+	/* No password set - always true ! */
+	if (part_passwd == NULL)
+	{
+		return True;
+	}
+
+	ntv2_owf_gen(part_passwd, user, domain, kr);
+	SMBOWFencrypt_ntv2(kr, c8, 8, password+16, pwd_len-16, resp);
+
+#if DEBUG_PASSWORD
+	DEBUG(100,("Part password (P16) was |"));
+	dump_data(100, part_passwd, 16);
+	DEBUG(100,("Password from client was |"));
+	dump_data(100, password, pwd_len);
+	DEBUG(100,("Given challenge was |"));
+	dump_data(100, c8, 8);
+	DEBUG(100,("Value from encryption was |"));
+	dump_data(100, resp, 16);
+#endif
+
+	return (memcmp(resp, password, 16) == 0);
+}
+
+
 /****************************************************************************
  Do a specific test for an smb password being correct, given a smb_password and
  the lanman and NT responses.
 ****************************************************************************/
 BOOL smb_password_ok(SAM_ACCOUNT *sampass, uchar chal[8],
-                     uchar lm_pass[24], uchar nt_pass[24])
+                     uchar lm_pass[24], uchar nt_pass[128], int nt_pass_len)
 {
 	uchar challenge[8];
 	char* user_name;
+	char* domain;
 	uint8 *nt_pw, *lm_pw;
 
 	if (!lm_pass || !sampass) 
 		return(False);
 
 	user_name = pdb_get_username(sampass);
+	domain = pdb_get_domain(sampass);
 	
+
 	DEBUG(4,("smb_password_ok: Checking SMB password for user %s\n",user_name));
 
 	if(pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
@@ -481,8 +526,18 @@
 		/* We have the NT MD4 hash challenge available - see if we can
 		   use it (ie. does it exist in the smbpasswd file).
 		*/
+		
+		DEBUG(4,("smb_password_ok: Check NTLMv2 password\n"));
+		if (smb_pwd_check_ntlmv2((uchar *)nt_pass, nt_pass_len,
+					 (uchar *)nt_pw, 
+					 challenge, user_name, domain
+					 ))
+			{
+				return True;
+			}
+		
 		DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
-		if (smb_password_check((char *)nt_pass, (uchar *)nt_pw, challenge)) {
+		if (lp_ntlm_auth() && smb_password_check((char *)nt_pass, (uchar *)nt_pw, challenge)) {
 			DEBUG(4,("smb_password_ok: NT MD4 password check succeeded\n"));
 			return(True);
 		}
@@ -520,7 +575,7 @@
 ****************************************************************************/
 
 BOOL pass_check_smb(char *user, char *domain, uchar *chal, 
-                    uchar *lm_pwd, uchar *nt_pwd, struct passwd *pwd)
+                    uchar *lm_pwd, uchar *nt_pwd, int pwlen, struct passwd *pwd)
 {
 	struct passwd *pass;
 	SAM_ACCOUNT *sampass=NULL;
@@ -596,7 +651,7 @@
 		}		
 	}
 
-	if (smb_password_ok(sampass, chal, lm_pwd, nt_pwd))
+	if (smb_password_ok(sampass, chal, lm_pwd, nt_pwd, pwlen))
 	{
 		pdb_free_sam(sampass);
 		return(True);
@@ -631,7 +686,7 @@
 		}
 
 		ret = pass_check_smb(user, global_myworkgroup,
-		                      challenge, (uchar *)password, (uchar *)password, pwd);
+		                      challenge, (uchar *)password, (uchar *)password, pwlen, pwd);
 
 		/*
 		 * Try with PAM (may not be compiled in - returns True if not. JRA).
 /****************************************************************************
Index: source/smbd/reply.c
===================================================================
RCS file: /cvsroot/samba/source/smbd/reply.c,v
retrieving revision 1.289
diff -u -r1.289 reply.c
--- source/smbd/reply.c	12 Jun 2001 09:51:03 -0000	1.289
+++ source/smbd/reply.c	16 Jun 2001 12:39:57 -0000
@@ -454,7 +454,7 @@
      return(ERROR(0, NT_STATUS_LOGON_FAILURE));
     }
 
-    if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd)) {
+    if (!smb_password_ok(sam_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd, smb_nt_passlen)) {
       DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
       SSVAL(outbuf, smb_flg2, SVAL(outbuf, smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
     pdb_free_sam(sam_trust_acct);








More information about the samba-technical mailing list