[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