I suppose it would help if I attached the patch.... :)
Says something sad about our present audit process for nobody to have
noticed that in 4 days :(
Amos Jeffries wrote:
This is the fakeauth merger and upgrade.
- renames fakeauth to ntlm_fake_auth
- links ntlm_fake_auth to libntlmauth
- removes duplicate code provided by libcompat and libntlmauth
- moves the remaining bits of fakeauth/ntlm.h to ntlm_fake_auth.cc.
- moves some of the basic NTLM operations into libntlmauth
* fetch_string UNICODE support
* make challenge packet
* validate packet type
* make challenge nonce
* unpack user and domain from authenticate packet
- tweaks libntlmauth to split the make challenge operation so that it
only generates the challenge object (does not encode blob for sending,
or hard-code field values any more).
- tweaks the smb_lm helper which already linked libntlmauth so that it
uses the updated API correctly after the above changes.
- documents libntlmauth and some of ntlm_fake_auth helper
Amos
--
Please be using
Current Stable Squid 2.7.STABLE9 or 3.1.4
=== modified file 'configure.in'
--- configure.in 2010-06-02 13:36:08 +0000
+++ configure.in 2010-06-03 06:52:51 +0000
@@ -3815,7 +3815,7 @@
helpers/digest_auth/file/Makefile \
helpers/digest_auth/ldap/Makefile \
helpers/ntlm_auth/Makefile \
- helpers/ntlm_auth/fakeauth/Makefile \
+ helpers/ntlm_auth/fake/Makefile \
helpers/ntlm_auth/no_check/Makefile \
helpers/ntlm_auth/smb_lm/Makefile \
helpers/ntlm_auth/smb_lm/smbval/Makefile \
=== modified file 'doc/release-notes/release-3.2.sgml'
--- doc/release-notes/release-3.2.sgml 2010-06-03 10:10:36 +0000
+++ doc/release-notes/release-3.2.sgml 2010-06-03 10:35:43 +0000
@@ -123,6 +123,7 @@
<sect2>NTLM Authentication protocol helpers
<p><itemize>
+ <item>fakeauth_auth - ntlm_fake_auth - Perform NTLMSSP to recover the username but don't verify the password.
<item>ntlm_auth - ntlm_smb_lm_auth - Perform SMB LanManager domain-less authentication over NTLM protocol.
</itemize>
=== modified file 'helpers/ntlm_auth/Makefile.am'
--- helpers/ntlm_auth/Makefile.am 2009-11-12 01:12:50 +0000
+++ helpers/ntlm_auth/Makefile.am 2010-06-03 06:52:51 +0000
@@ -3,5 +3,5 @@
# $Id$
#
-DIST_SUBDIRS = fakeauth no_check smb_lm mswin_sspi
+DIST_SUBDIRS = fake no_check smb_lm mswin_sspi
SUBDIRS = $(NTLM_AUTH_HELPERS)
=== renamed directory 'helpers/ntlm_auth/fakeauth' => 'helpers/ntlm_auth/fake'
=== modified file 'helpers/ntlm_auth/fake/Makefile.am'
--- helpers/ntlm_auth/fakeauth/Makefile.am 2010-04-14 11:13:32 +0000
+++ helpers/ntlm_auth/fake/Makefile.am 2010-06-03 06:52:51 +0000
@@ -1,15 +1,14 @@
include $(top_srcdir)/src/Common.am
-libexec_PROGRAMS = fakeauth_auth
-fakeauth_auth_SOURCES = fakeauth_auth.c ntlm.h
-
-## we need our local files too (but avoid -I. at all costs)
-INCLUDES += -I$(srcdir)
-
-LDADD = \
- $(top_builddir)/compat/libcompat.la \
- -L$(top_builddir)/lib -lmiscutil \
+libexec_PROGRAMS = ntlm_fake_auth
+ntlm_fake_auth_SOURCES = ntlm_fake_auth.cc
+
+ntlm_fake_auth_LDADD = \
+ -L$(top_builddir)/lib -lntlmauth \
+ $(COMPAT_LIB) \
$(CRYPTLIB) \
$(XTRA_LIBS)
+ntlm_fake_auth_DEPENDENCIES = $(top_builddir)/lib/libntlmauth.a
+
EXTRA_DIST = config.test
=== removed file 'helpers/ntlm_auth/fakeauth/ntlm.h'
--- helpers/ntlm_auth/fakeauth/ntlm.h 2009-08-23 09:30:49 +0000
+++ helpers/ntlm_auth/fakeauth/ntlm.h 1970-01-01 00:00:00 +0000
@@ -1,161 +0,0 @@
-/*
- * $Id$
- *
- * AUTHOR: Andrew Doran <a...@interlude.eu.org>
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * 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, USA.
- *
- */
-
-#ifndef _NTLM_H_
-#define _NTLM_H_
-
-/* undefine this to have strict protocol adherence. You don't really need
- * that though */
-#define IGNORANCE_IS_BLISS
-
-#include <sys/types.h>
-
-/* All of this cruft is little endian */
-#include "squid_endian.h"
-
-/* NTLM request types that we know about */
-#define NTLM_ANY 0
-
-/* Negotiation request sent by client */
-struct ntlm_negotiate {
- ntlmhdr hdr; /* NTLM header */
- int32_t flags; /* Request flags */
- strhdr domain; /* Domain we wish to authenticate in */
- strhdr workstation; /* Client workstation name */
- char pad[256]; /* String data */
-};
-
-/* Challenge request sent by server. */
-struct ntlm_challenge {
- ntlmhdr hdr; /* NTLM header */
- strhdr target; /* Authentication target (domain/server ...) */
- int32_t flags; /* Request flags */
- u_char challenge[8]; /* Challenge string */
- int16_t unknown[8]; /* Some sort of context data */
- char pad[256]; /* String data */
-};
-
-/* Authentication request sent by client in response to challenge */
-struct ntlm_authenticate {
- ntlmhdr hdr; /* NTLM header */
- strhdr lmresponse; /* LANMAN challenge response */
- strhdr ntresponse; /* NT challenge response */
- strhdr domain; /* Domain to authenticate against */
- strhdr user; /* Username */
- strhdr workstation; /* Workstation name */
- strhdr sessionkey; /* Session key for server's use */
- int32_t flags; /* Request flags */
- char pad[256 * 6]; /* String data */
-};
-
-char *ntlmGetString(ntlmhdr * hdr, strhdr * str, int flags);
-void ntlmMakeChallenge(struct ntlm_challenge *chal, int32_t flags);
-int ntlmCheckHeader(ntlmhdr * hdr, int type);
-int ntlmCheckNegotiation(struct ntlm_negotiate *neg);
-int ntlmAuthenticate(struct ntlm_authenticate *neg);
-
-#define safe_free(x) if (x) { free(x); x = NULL; }
-
-#undef debug
-
-/************* CONFIGURATION ***************/
-/*
- * define this if you want debugging
- */
-#ifndef DEBUG
-#define DEBUG
-#endif
-
-#define FAIL_DEBUG 0
-
-/************* END CONFIGURATION ***************/
-
-#include <sys/types.h>
-
-extern int debug_enabled;
-#if FAIL_DEBUG
-extern int fail_debug_enabled;
-#endif
-
-/* Debugging stuff */
-
-#ifdef __GNUC__ /* this is really a gcc-ism */
-#ifdef DEBUG
-#include <stdio.h>
-#include <unistd.h>
-static const char *__foo;
-#define debug(X...) if (debug_enabled) { \
- fprintf(stderr,"ntlm-auth[%ld](%s:%d): ", (long)getpid(), \
- ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\
- __LINE__);\
- fprintf(stderr,X); }
-#else /* DEBUG */
-#define debug(X...) /* */
-#endif /* DEBUG */
-#else /* __GNUC__ */
-static void
-debug(char *format,...)
-{
-#ifdef DEBUG
-#ifdef _SQUID_MSWIN_
-#if FAIL_DEBUG
- if (debug_enabled || fail_debug_enabled) {
-#else
-if (debug_enabled) {
-#endif
- va_list args;
-
- va_start(args, format);
- fprintf(stderr, "ntlm-auth[%ld]: ", (long)getpid());
- vfprintf(stderr, format, args);
- va_end(args);
-#if FAIL_DEBUG
- fail_debug_enabled = 0;
-#endif
- }
-#endif /* _SQUID_MSWIN_ */
-#endif /* DEBUG */
-}
-#endif /* __GNUC__ */
-
-
-/* A couple of harmless helper macros */
-#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
-#ifdef __GNUC__
-#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
-#else
-/* no gcc, no debugging. varargs macros are a gcc extension */
-#define SEND2(X,Y) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
-#endif
-
-#endif /* _NTLM_H_ */
=== renamed file 'helpers/ntlm_auth/fakeauth/fakeauth_auth.c' => 'helpers/ntlm_auth/fake/ntlm_fake_auth.cc'
--- helpers/ntlm_auth/fakeauth/fakeauth_auth.c 2010-02-20 04:31:04 +0000
+++ helpers/ntlm_auth/fake/ntlm_fake_auth.cc 2010-06-03 13:13:34 +0000
@@ -1,7 +1,38 @@
/*
+ * $Id$
*
+ * AUTHOR: Andrew Doran <a...@interlude.eu.org>
* AUTHOR: Robert Collins <rbtcoll...@hotmail.com>
- *
+ * AUTHOR: Guido Serassio: <guido.seras...@acmeconsulting.it>
+ *
+ * SQUID Web Proxy Cache http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ * Squid is the result of efforts by numerous individuals from
+ * the Internet community; see the CONTRIBUTORS file for full
+ * details. Many organizations have provided support for Squid's
+ * development; see the SPONSORS file for full details. Squid is
+ * Copyrighted (C) 2001 by the Regents of the University of
+ * California; see the COPYRIGHT file for full details. Squid
+ * incorporates software developed and/or copyrighted by other
+ * sources; see the CREDITS file for full details.
+ *
+ * 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, USA.
+ *
+ */
+/*
* Example ntlm authentication program for Squid, based on the
* original proxy_auth code from client_side.c, written by
* Jon Thackray <j...@uk.gdscorp.com>. Initial ntlm code by
@@ -18,21 +49,16 @@
*
*/
+/* undefine this to have strict protocol adherence. You don't really need
+ * that though */
+#define IGNORANCE_IS_BLISS
+
#include "config.h"
#include "ntlmauth.h"
-#include "squid_endian.h"
-
#include "util.h"
+
+#if HAVE_CTYPE_H
#include <ctype.h>
-
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
#endif
#if HAVE_STRING_H
#include <string.h>
@@ -46,7 +72,20 @@
#if HAVE_GETOPT_H
#include <getopt.h>
#endif
-#include "ntlm.h"
+
+
+#define safe_free(x) if (x) { free(x); x = NULL; }
+
+/* A couple of harmless helper macros */
+#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
+#ifdef __GNUC__
+#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
+#define SEND3(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
+#else
+/* no gcc, no debugging. varargs macros are a gcc extension */
+#define SEND2(X,Y) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
+#define SEND3(X,Y,Z) debug("sending '" X "' to squid\n",Y,Z); printf(X "\n",Y,Z);
+#endif
#define ERR "ERR\n"
#define OK "OK\n"
@@ -54,15 +93,11 @@
#define BUFFER_SIZE 10240
const char *authenticate_ntlm_domain = "WORKGROUP";
-int debug_enabled = 0;
int strip_domain_enabled = 0;
int NTLM_packet_debug_enabled = 0;
-/* NTLM authentication by a...@interlude.eu.org - 07/1999 */
-/* XXX this is not done cleanly... */
-
static void
-hex_dump(void *data, int size)
+hex_dump(unsigned char *data, int size)
{
/* dumps size bytes of *data to stdout. Looks like:
* [0000] 75 6E 6B 6E 6F 77 6E 20
@@ -85,7 +120,7 @@
if (n % 16 == 1) {
/* store address for this line */
snprintf(addrstr, sizeof(addrstr), "%.4x",
- (int) (p - (unsigned char *) data));
+ (int) (p - data));
}
c = *p;
if (xisalnum(c) == 0) {
@@ -131,189 +166,6 @@
}
}
-
-/*
- * Generates a challenge request. The randomness of the 8 byte
- * challenge strings can be guarenteed to be poor at best.
- */
-void
-ntlmMakeChallenge(struct ntlm_challenge *chal, int32_t flags)
-{
- static unsigned hash;
- int r;
- char *d;
- int i;
-
- debug("ntlmMakeChallenge: flg %08x\n", flags);
-
- memset(chal, 0, sizeof(*chal));
- memcpy(chal->hdr.signature, "NTLMSSP", 8);
- chal->flags = htole32(CHALLENGE_TARGET_IS_DOMAIN |
- NEGOTIATE_ALWAYS_SIGN |
- NEGOTIATE_USE_NTLM |
- NEGOTIATE_REQUEST_TARGET |
- (NEGOTIATE_UNICODE & flags ? NEGOTIATE_UNICODE : NEGOTIATE_ASCII)
- );
- chal->hdr.type = htole32(NTLM_CHALLENGE);
- chal->flags = flags;
- chal->unknown[6] = htole16(0x003a);
-
- d = (char *) chal + 48;
- i = 0;
-
- if (authenticate_ntlm_domain != NULL)
- while (authenticate_ntlm_domain[i++]);
-
- chal->flags = flags;
- chal->target.offset = htole32(48);
- chal->target.maxlen = htole16(i);
- chal->target.len = chal->target.maxlen;
-
- r = (int) rand();
- r = (hash ^ r) + r;
-
- for (i = 0; i < 8; i++) {
- chal->challenge[i] = r;
- r = (r >> 2) ^ r;
- }
-
- hash = r;
-}
-
-/*
- * Check the vailidity of a request header. Return -1 on error.
- */
-int
-ntlmCheckHeader(ntlmhdr * hdr, int type)
-{
- /*
- * Must be the correct security package and request type. The
- * 8 bytes compared includes the ASCII 'NUL'.
- */
- if (memcmp(hdr->signature, "NTLMSSP", 8) != 0) {
- fprintf(stderr, "ntlmCheckHeader: bad header signature\n");
- return (-1);
- }
- if (type == NTLM_ANY)
- return 0;
-
- if (le32toh(hdr->type) != type) {
- /* don't report this error - it's ok as we do a if() around this function */
-// fprintf(stderr, "ntlmCheckHeader: type is %d, wanted %d\n",
- // le32toh(hdr->type), type);
- return (-1);
- }
- return (0);
-}
-
-/*
- * Extract a string from an NTLM request and return as ASCII.
- */
-char *
-ntlmGetString(ntlmhdr * hdr, strhdr * str, int flags)
-{
- static char buf[512];
- u_short *s, c;
- char *d, *sc;
- int l, o;
-
- l = le16toh(str->len);
- o = le32toh(str->offset);
-
- /* Sanity checks. XXX values arbitrarialy chosen */
- if (l <= 0 || l >= 32 || o >= 256) {
- fprintf(stderr, "ntlmGetString: insane: l:%d o:%d\n", l, o);
- return (NULL);
- }
- if ((flags & NEGOTIATE_ASCII) == 0) {
- /* UNICODE string */
- s = (u_short *) ((char *) hdr + o);
- d = buf;
-
- for (l >>= 1; l; s++, l--) {
- c = le16toh(*s);
- if (c > 254 || c == '\0') {
- fprintf(stderr, "ntlmGetString: bad uni: %04x\n", c);
- return (NULL);
- }
- *d++ = c;
- }
-
- *d = 0;
- } else {
- /* ASCII/OEM string */
- sc = (char *) hdr + o;
- d = buf;
-
- for (; l; l--) {
- if (*sc == '\0' || !xisprint(*sc)) {
- fprintf(stderr, "ntlmGetString: bad ascii: %04x\n", *sc);
- return (NULL);
- }
- *d++ = *sc++;
- }
-
- *d = 0;
- }
-
- return (buf);
-}
-
-/*
- * Decode the strings in an NTLM authentication request
- */
-static int
-ntlmDecodeAuth(struct ntlm_authenticate *auth, char *buf, size_t size)
-{
- const char *p;
- char *origbuf;
- int s;
-
- if (!buf) {
- return 1;
- }
- origbuf = buf;
- if (ntlmCheckHeader(&auth->hdr, NTLM_AUTHENTICATE)) {
- fprintf(stderr, "ntlmDecodeAuth: header check fails\n");
- return -1;
- }
- debug("ntlmDecodeAuth: size of %d\n", (int) size);
- debug("ntlmDecodeAuth: flg %08x\n", auth->flags);
- debug("ntlmDecodeAuth: usr o(%d) l(%d)\n", auth->user.offset, auth->user.len);
-
- if ((p = ntlmGetString(&auth->hdr, &auth->domain, auth->flags)) == NULL)
- p = authenticate_ntlm_domain;
-
- debug("ntlmDecodeAuth: Domain '%s'.\n", p);
-
- if ((s = strlen(p) + 1) >= size)
- return 1;
- strcpy(buf, p);
-
- debug("ntlmDecodeAuth: Domain '%s'.\n", buf);
-
- size -= s;
- buf += (s - 1);
- *buf++ = '\\'; /* Using \ is more consistent with MS-proxy */
-
- if ( (p = ntlmGetString(&auth->hdr, &auth->user, auth->flags)) == NULL)
- return 1;
-
- if ((s = strlen(p) + 1) >= size)
- return 1;
-
- while (*p)
- *buf++ = (*p++); //tolower
-
- *buf++ = '\0';
- size -= s;
-
- debug("ntlmDecodeAuth: user: %s%s\n", origbuf, p);
-
- return 0;
-}
-
-
/*
* options:
* -d enable debugging.
@@ -334,7 +186,6 @@
my_program_name);
}
-
static void
process_options(int argc, char *argv[])
{
@@ -369,15 +220,14 @@
exit(1);
}
-
int
main(int argc, char *argv[])
{
char buf[BUFFER_SIZE];
int buflen = 0;
- char user[256], *p, *decoded = NULL;
- struct ntlm_challenge chal;
- struct ntlm_negotiate *nego;
+ char user[NTLM_MAX_FIELD_LENGTH], domain[NTLM_MAX_FIELD_LENGTH];
+ char *p, *decoded = NULL;
+ ntlmhdr *packet = NULL;
char helper_command[3];
int len;
char *data = NULL;
@@ -392,60 +242,62 @@
debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name);
while (fgets(buf, BUFFER_SIZE, stdin) != NULL) {
- user[0] = '\0'; /*no usercode */
+ user[0] = '\0'; /*no user code */
+ domain[0] = '\0'; /*no domain code */
if ((p = strchr(buf, '\n')) != NULL)
*p = '\0'; /* strip \n */
buflen = strlen(buf); /* keep this so we only scan the buffer for \0 once per loop */
if (buflen > 3)
- decoded = base64_decode(buf + 3);
+ packet = (ntlmhdr*)base64_decode(buf + 3);
if (buflen > 3 && NTLM_packet_debug_enabled) {
strncpy(helper_command, buf, 2);
helper_command[2] = '\0';
debug("Got '%s' from Squid with data:\n", helper_command);
- hex_dump(decoded, ((strlen(buf) - 3) * 3) / 4);
+ hex_dump((unsigned char*)packet, ((buflen - 3) * 3) / 4);
} else
debug("Got '%s' from Squid\n", buf);
if (strncasecmp(buf, "YR", 2) == 0) {
+ char nonce[NTLM_NONCE_LEN];
+ ntlm_challenge chal;
+ ntlm_make_nonce(nonce);
if (buflen > 3) {
- nego = (struct ntlm_negotiate *) decoded;
- ntlmMakeChallenge(&chal, nego->flags);
- } else
- ntlmMakeChallenge(&chal, NEGOTIATE_ASCII);
- len =
- sizeof(chal) - sizeof(chal.pad) +
- le16toh(chal.target.maxlen);
+ ntlm_negotiate *nego = (ntlm_negotiate *)packet;
+ ntlm_make_challenge(&chal, authenticate_ntlm_domain, NULL, nonce, NTLM_NONCE_LEN, nego->flags);
+ } else {
+ ntlm_make_challenge(&chal, authenticate_ntlm_domain, NULL, nonce, NTLM_NONCE_LEN, NEGOTIATE_ASCII);
+ }
+ // TODO: find out what this context means, and why only the fake auth helper contains it.
+ chal.context_high = htole32(0x003a<<16);
+
+ len = sizeof(chal) - sizeof(chal.payload) + le16toh(chal.target.maxlen);
data = (char *) base64_encode_bin((char *) &chal, len);
if (NTLM_packet_debug_enabled) {
printf("TT %s\n", data);
- decoded = base64_decode(data);
debug("sending 'TT' to squid with data:\n");
- hex_dump(decoded, (strlen(data) * 3) / 4);
+ hex_dump((unsigned char *)&chal, len);
} else
SEND2("TT %s", data);
} else if (strncasecmp(buf, "KK ", 3) == 0) {
- if (!decoded) {
- SEND2("BH received KK with no data! user=%s", user);
- } else if (!ntlmCheckHeader((ntlmhdr *) decoded, NTLM_AUTHENTICATE)) {
- if (!ntlmDecodeAuth((struct ntlm_authenticate *) decoded, user, 256)) {
+ if (!packet) {
+ SEND("BH received KK with no data! user=");
+ } else if (!ntlm_validate_packet(packet, NTLM_AUTHENTICATE)) {
+ if (ntlm_unpack_auth((ntlm_authenticate *)packet, user, domain, (buflen-3)) == 0) {
lc(user);
+ lc(domain);
if (strip_domain_enabled) {
- strtok(user, "\\");
- p = strtok(NULL, "\\");
- if (!p)
- p = user;
- SEND2("AF %s", p);
+ SEND2("AF %s", user);
} else {
- SEND2("AF %s", user);
+ SEND3("AF %s%s%s", domain, (*domain?"\\":""), user);
}
} else {
lc(user);
- SEND2("NA invalid credentials, user=%s", user);
+ lc(domain);
+ SEND3("NA invalid credentials, user=%s%s%s", domain, (*domain?"\\":""), user);
}
} else {
- lc(user);
- SEND2("BH wrong packet type! user=%s", user);
+ SEND("BH wrong packet type! user=");
}
}
}
=== modified file 'helpers/ntlm_auth/smb_lm/Makefile.am'
--- helpers/ntlm_auth/smb_lm/Makefile.am 2010-04-14 11:13:32 +0000
+++ helpers/ntlm_auth/smb_lm/Makefile.am 2010-06-03 06:52:51 +0000
@@ -10,11 +10,13 @@
-I$(srcdir) \
-I$(srcdir)/smbval
-LDADD = \
- $(top_builddir)/compat/libcompat.la \
- -L$(top_builddir)/lib -lntlmauth -lmiscutil \
+ntlm_smb_lm_auth_LDADD = \
+ -L$(top_builddir)/lib -lntlmauth \
smbval/libsmbvalid.a \
+ $(COMPAT_LIB) \
$(CRYPTLIB) \
$(XTRA_LIBS)
+ntlm_smb_lm_auth_DEPENDENCIES = $(top_builddir)/lib/libntlmauth.a
+
EXTRA_DIST = config.test
=== modified file 'helpers/ntlm_auth/smb_lm/libntlmssp.c'
--- helpers/ntlm_auth/smb_lm/libntlmssp.c 2010-05-01 00:13:01 +0000
+++ helpers/ntlm_auth/smb_lm/libntlmssp.c 2010-06-03 06:52:51 +0000
@@ -68,20 +68,8 @@
#define debug_dump_ntlmssp_flags(X) /* empty */
#endif /* DEBUG */
-void
-print_debug (char *format,...)
-{
-#if DEBUG
- va_list args;
- va_start(args,format);
- vfprintf(stderr, format, args);
- va_end(args);
-#endif /* DEBUG */
- return;
-}
-
#define ENCODED_PASS_LEN 24
-static unsigned char challenge[NONCE_LEN];
+static unsigned char challenge[NTLM_NONCE_LEN];
static unsigned char lmencoded_empty_pass[ENCODED_PASS_LEN],
ntencoded_empty_pass[ENCODED_PASS_LEN];
SMB_Handle_Type handle = NULL;
@@ -125,29 +113,29 @@
if (handle != NULL) {
return 0;
}
- print_debug("Connecting to server %s domain %s\n", domain_controller, domain);
+ debug("Connecting to server %s domain %s\n", domain_controller, domain);
handle = SMB_Connect_Server(NULL, domain_controller, domain);
smberr = SMB_Get_Last_Error();
SMB_Get_Error_Msg(smberr, errstr, 1000);
if (handle == NULL) { /* couldn't connect */
- print_debug("Couldn't connect to SMB Server. Error:%s\n", errstr);
+ debug("Couldn't connect to SMB Server. Error:%s\n", errstr);
return 1;
}
if (SMB_Negotiate(handle, SMB_Prots) < 0) { /* An error */
- print_debug("Error negotiating protocol with SMB Server\n");
+ debug("Error negotiating protocol with SMB Server\n");
SMB_Discon(handle, 0);
handle = NULL;
return 2;
}
if (handle->Security == 0) { /* share-level security, unuseable */
- print_debug("SMB Server uses share-level security .. we need user security.\n");
+ debug("SMB Server uses share-level security .. we need user security.\n");
SMB_Discon(handle, 0);
handle = NULL;
return 3;
}
- memcpy(challenge, handle->Encrypt_Key, NONCE_LEN);
+ memcpy(challenge, handle->Encrypt_Key, NTLM_NONCE_LEN);
SMBencrypt((unsigned char *)"",challenge,lmencoded_empty_pass);
SMBNTencrypt((unsigned char *)"",challenge,ntencoded_empty_pass);
return 0;
@@ -164,7 +152,16 @@
if (init_challenge(my_domain, my_domain_controller) > 0) {
return NULL;
}
- return ntlm_make_challenge(my_domain, my_domain_controller, (char *)challenge, NONCE_LEN);
+ ntlm_challenge chal;
+ u_int32_t flags = REQUEST_NON_NT_SESSION_KEY |
+ CHALLENGE_TARGET_IS_DOMAIN |
+ NEGOTIATE_ALWAYS_SIGN |
+ NEGOTIATE_USE_NTLM |
+ NEGOTIATE_USE_LM |
+ NEGOTIATE_ASCII;
+ ntlm_make_challenge(&chal, my_domain, my_domain_controller, (char *)challenge, NTLM_NONCE_LEN, flags);
+ int len = sizeof(chal) - sizeof(chal.payload) + le16toh(chal.target.maxlen);
+ return base64_encode_bin((char *)&chal, len);
}
int ntlm_errno;
@@ -184,7 +181,7 @@
{
char *p = credentials;
lstring tmp;
- tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
+ tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->domain, auth->flags);
*p = '\0';
if (tmp.str == NULL)
return NULL;
@@ -192,7 +189,7 @@
p += tmp.l;
*p++ = '\\';
*p = '\0';
- tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
+ tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->user, auth->flags);
if (tmp.str == NULL)
return NULL;
memcpy(p, tmp.str, tmp.l);
@@ -216,20 +213,20 @@
lstring tmp;
if (handle == NULL) { /*if null we aren't connected, but it shouldn't happen */
- print_debug("Weird, we've been disconnected\n");
+ debug("Weird, we've been disconnected\n");
ntlm_errno = NTLM_NOT_CONNECTED;
return NULL;
}
- /* print_debug("fetching domain\n"); */
- tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain);
+ /* debug("fetching domain\n"); */
+ tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->domain, auth->flags);
if (tmp.str == NULL || tmp.l == 0) {
- print_debug("No domain supplied. Returning no-auth\n");
+ debug("No domain supplied. Returning no-auth\n");
ntlm_errno = NTLM_LOGON_ERROR;
return NULL;
}
if (tmp.l > MAX_DOMAIN_LEN) {
- print_debug("Domain string exceeds %d bytes, rejecting\n", MAX_DOMAIN_LEN);
+ debug("Domain string exceeds %d bytes, rejecting\n", MAX_DOMAIN_LEN);
ntlm_errno = NTLM_LOGON_ERROR;
return NULL;
}
@@ -237,15 +234,15 @@
user = domain + tmp.l;
*user++ = '\0';
- /* print_debug("fetching user name\n"); */
- tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user);
+ /* debug("fetching user name\n"); */
+ tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->user, auth->flags);
if (tmp.str == NULL || tmp.l == 0) {
- print_debug("No username supplied. Returning no-auth\n");
+ debug("No username supplied. Returning no-auth\n");
ntlm_errno = NTLM_LOGON_ERROR;
return NULL;
}
if (tmp.l > MAX_USERNAME_LEN) {
- print_debug("Username string exceeds %d bytes, rejecting\n", MAX_USERNAME_LEN);
+ debug("Username string exceeds %d bytes, rejecting\n", MAX_USERNAME_LEN);
ntlm_errno = NTLM_LOGON_ERROR;
return NULL;
}
@@ -254,14 +251,14 @@
/* Authenticating against the NT response doesn't seem to work... */
- tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse);
+ tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->lmresponse, auth->flags);
if (tmp.str == NULL || tmp.l == 0) {
fprintf(stderr, "No auth at all. Returning no-auth\n");
ntlm_errno = NTLM_LOGON_ERROR;
return NULL;
}
if (tmp.l > MAX_PASSWD_LEN) {
- print_debug("Password string exceeds %d bytes, rejecting\n", MAX_PASSWD_LEN);
+ debug("Password string exceeds %d bytes, rejecting\n", MAX_PASSWD_LEN);
ntlm_errno = NTLM_LOGON_ERROR;
return NULL;
}
@@ -270,7 +267,7 @@
pass[min(MAX_PASSWD_LEN,tmp.l)] = '\0';
#if 1
- print_debug("Empty LM pass detection: user: '%s', ours:'%s', his: '%s'"
+ debug("Empty LM pass detection: user: '%s', ours:'%s', his: '%s'"
"(length: %d)\n",
user,lmencoded_empty_pass,tmp.str,tmp.l);
if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) {
@@ -280,9 +277,9 @@
return NULL;
}
- tmp = ntlm_fetch_string ((char *) auth, auth_length, &auth->ntresponse);
+ tmp = ntlm_fetch_string(&(auth->hdr), auth_length, &auth->ntresponse, auth->flags);
if (tmp.str != NULL && tmp.l != 0) {
- print_debug("Empty NT pass detection: user: '%s', ours:'%s', his: '%s'"
+ debug("Empty NT pass detection: user: '%s', ours:'%s', his: '%s'"
"(length: %d)\n",
user,ntencoded_empty_pass,tmp.str,tmp.l);
if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) {
@@ -297,11 +294,10 @@
/* TODO: check against empty password!!!!! */
-
- print_debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass);
+ debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass);
rv = SMB_Logon_Server(handle, user, pass, domain, 1);
- print_debug("Login attempt had result %d\n", rv);
+ debug("Login attempt had result %d\n", rv);
if (rv != NTV_NO_ERROR) { /* failed */
ntlm_errno = rv;
@@ -309,6 +305,6 @@
}
*(user - 1) = '\\'; /* hack. Performing, but ugly. */
- print_debug("credentials: %s\n", credentials);
+ debug("credentials: %s\n", credentials);
return credentials;
}
=== modified file 'helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.c'
--- helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.c 2010-05-02 00:13:07 +0000
+++ helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.c 2010-06-03 06:52:51 +0000
@@ -195,7 +195,7 @@
* it's going to live as long as the process anyways */
d = malloc(strlen(argv[j]) + 1);
strcpy(d, argv[j]);
- print_debug("Adding domain-controller %s\n", d);
+ debug("Adding domain-controller %s\n", d);
if (NULL == (c = strchr(d, '\\')) && NULL == (c = strchr(d, '/'))) {
fprintf(stderr, "Couldn't grok domain-controller %s\n", d);
free(d);
@@ -247,31 +247,31 @@
int j = 0;
const char *ch = NULL;
for (j = 0; j < numcontrollers; j++) {
- print_debug("obtain_challenge: selecting %s\\%s (attempt #%d)\n",
+ debug("obtain_challenge: selecting %s\\%s (attempt #%d)\n",
current_dc->domain, current_dc->controller, j + 1);
if (current_dc->dead != 0) {
if (time(NULL) - current_dc->dead >= DEAD_DC_RETRY_INTERVAL) {
/* mark helper as retry-worthy if it's so. */
- print_debug("Reviving DC\n");
+ debug("Reviving DC\n");
current_dc->dead = 0;
} else { /* skip it */
- print_debug("Skipping it\n");
+ debug("Skipping it\n");
continue;
}
}
/* else branch. Here we KNOW that the DC is fine */
- print_debug("attempting challenge retrieval\n");
+ debug("attempting challenge retrieval\n");
ch = make_challenge(current_dc->domain, current_dc->controller);
- print_debug("make_challenge retuned %p\n", ch);
+ debug("make_challenge retuned %p\n", ch);
if (ch) {
- print_debug("Got it\n");
+ debug("Got it\n");
return ch; /* All went OK, returning */
}
/* Huston, we've got a problem. Take this DC out of the loop */
- print_debug("Marking DC as DEAD\n");
+ debug("Marking DC as DEAD\n");
current_dc->dead = time(NULL);
/* Try with the next */
- print_debug("moving on to next controller\n");
+ debug("moving on to next controller\n");
current_dc = current_dc->next;
}
/* all DCs failed. */
@@ -293,13 +293,13 @@
strerror(errno));
exit(1); /* BIIG buffer */
}
- print_debug("managing request\n");
+ debug("managing request\n");
ch2 = memchr(buf, '\n', BUFFER_SIZE); /* safer against overrun than strchr */
if (ch2) {
*ch2 = '\0'; /* terminate the string at newline. */
ch = ch2;
}
- print_debug("ntlm authenticator. Got '%s' from Squid\n", buf);
+ debug("ntlm authenticator. Got '%s' from Squid\n", buf);
if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */
/* figure out what we got */
@@ -357,8 +357,8 @@
smb_errorclass = SMBlib_Error_Class(SMB_Get_Last_SMB_Err());
smb_errorcode = SMBlib_Error_Code(SMB_Get_Last_SMB_Err());
nb_error = RFCNB_Get_Last_Error();
- print_debug("No creds. SMBlib error %d, SMB error class %d, SMB error code %d, NB error %d\n",
- smblib_err, smb_errorclass, smb_errorcode, nb_error);
+ debug("No creds. SMBlib error %d, SMB error class %d, SMB error code %d, NB error %d\n",
+ smblib_err, smb_errorclass, smb_errorcode, nb_error);
/* Should I use smblib_err? Actually it seems I can do as well
* without it.. */
if (nb_error != 0) { /* netbios-level error */
@@ -370,7 +370,7 @@
}
switch (smb_errorclass) {
case SMBC_SUCCESS:
- print_debug("Huh? Got a SMB success code but could check auth..");
+ debug("Huh? Got a SMB success code but could check auth..");
SEND("NA Authentication failed");
/*
* send_bh_or_ld("SMB success, but no creds. Internal error?",
@@ -379,7 +379,7 @@
return;
case SMBC_ERRDOS:
/*this is the most important one for errors */
- print_debug("DOS error\n");
+ debug("DOS error\n");
switch (smb_errorcode) {
/* two categories matter to us: those which could be
* server errors, and those which are auth errors */
@@ -401,7 +401,7 @@
return;
}
case SMBC_ERRSRV: /* server errors */
- print_debug("Server error");
+ debug("Server error");
switch (smb_errorcode) {
/* mostly same as above */
case SMBV_badpw:
@@ -460,11 +460,11 @@
int
main(int argc, char *argv[])
{
- print_debug("ntlm_auth build " __DATE__ ", " __TIME__ " starting up...\n");
+ debug("ntlm_auth build " __DATE__ ", " __TIME__ " starting up...\n");
#if DEBUG
- print_debug("changing dir to /tmp\n");
+ debug("changing dir to /tmp\n");
if (chdir("/tmp") != 0) {
- print_debug("ERROR: (%d) failed.\n",errno);
+ debug("ERROR: (%d) failed.\n",errno);
return 2;
}
#endif
@@ -472,7 +472,7 @@
my_program_name = argv[0];
process_options(argc, argv);
- print_debug("options processed OK\n");
+ debug("options processed OK\n");
/* initialize FDescs */
setbuf(stdout, NULL);
@@ -484,7 +484,7 @@
int n;
pid_t pid = getpid();
n = pid % numcontrollers;
- print_debug("load balancing. Selected controller #%d\n", n);
+ debug("load balancing. Selected controller #%d\n", n);
while (n > 0) {
current_dc = current_dc->next;
n--;
=== modified file 'helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.h'
--- helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.h 2010-05-01 19:18:36 +0000
+++ helpers/ntlm_auth/smb_lm/ntlm_smb_lm_auth.h 2010-06-03 06:52:51 +0000
@@ -40,9 +40,9 @@
/* A couple of harmless helper macros */
-#define SEND(X) print_debug("sending '%s' to squid\n",X); printf(X "\n");
+#define SEND(X) debug("sending '%s' to squid\n",X); printf(X "\n");
#ifdef __GNUC__
-#define SEND2(X,Y...) print_debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
+#define SEND2(X,Y...) debug("sending '" X "' to squid\n",Y); printf(X "\n",Y);
#else
/* no gcc, no debugging. varargs macros are a gcc extension */
#define SEND2 printf
=== modified file 'include/config.h'
--- include/config.h 2010-04-09 02:53:27 +0000
+++ include/config.h 2010-06-03 06:52:51 +0000
@@ -95,6 +95,9 @@
#define xmemmove(d,s,n) bcopy((s),(d),(n))
#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
#define xisspace(x) isspace((unsigned char)x)
#define xtoupper(x) toupper((unsigned char)x)
#define xtolower(x) tolower((unsigned char)x)
=== modified file 'include/ntlmauth.h'
--- include/ntlmauth.h 2010-05-31 12:20:10 +0000
+++ include/ntlmauth.h 2010-06-03 13:01:43 +0000
@@ -17,6 +17,8 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
+ *
+ *
* SQUID Web Proxy Cache http://www.squid-cache.org/
* ----------------------------------------------------------
*
@@ -57,39 +59,16 @@
/* NP: All of this cruft is little endian */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
/* Used internally. Microsoft seems to think this is right, I believe them.
* Right. */
-#define MAX_FIELD_LENGTH 300 /* max length of an NTLMSSP field */
+#define NTLM_MAX_FIELD_LENGTH 300 /* max length of an NTLMSSP field */
/* Here start the NTLMSSP definitions */
-/* NTLM request types that we know about */
-#define NTLM_NEGOTIATE 1
-#define NTLM_CHALLENGE 2
-#define NTLM_CHALLENGE_HEADER_OFFSET 40
-#define NTLM_AUTHENTICATE 3
-
-#define NONCE_LEN 8
-
-/* negotiate request flags */
-#define NEGOTIATE_UNICODE 0x0001
-#define NEGOTIATE_ASCII 0x0002
-#define NEGOTIATE_REQUEST_TARGET 0x0004
-#define NEGOTIATE_REQUEST_SIGN 0x0010
-#define NEGOTIATE_REQUEST_SEAL 0x0020
-#define NEGOTIATE_DATAGRAM_STYLE 0x0040
-#define NEGOTIATE_USE_LM 0x0080
-#define NEGOTIATE_USE_NETWARE 0x0100
-#define NEGOTIATE_USE_NTLM 0x0200
-#define NEGOTIATE_DOMAIN_SUPPLIED 0x1000
-#define NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
-#define NEGOTIATE_THIS_IS_LOCAL_CALL 0x4000
-#define NEGOTIATE_ALWAYS_SIGN 0x8000
-
-/* challenge request flags */
-#define CHALLENGE_TARGET_IS_DOMAIN 0x10000
-#define CHALLENGE_TARGET_IS_SERVER 0x20000
-#define CHALLENGE_TARGET_IS_SHARE 0x40000
/* these are marked as "extra" fields */
#define REQUEST_INIT_RESPONSE 0x100000
@@ -104,20 +83,71 @@
int32_t offset; /**< Offset from start of request */
} strhdr;
-/** We use this to keep data/lenght couples. Only used internally. */
+/** We use this to keep data/length couples. */
typedef struct _lstring {
int32_t l; /**< length, -1 if empty */
char *str; /**< the string. NULL if not initialized */
} lstring;
-/** This is an header common to all signatures, it's used to discriminate
- * among the different signature types.
+/** Debug dump the given flags field to stderr */
+void ntlm_dump_ntlmssp_flags(const u_int32_t flags);
+
+
+/* ************************************************************************* */
+/* Packet and Payload structures and handling functions */
+/* ************************************************************************* */
+
+/* NTLM request types that we know about */
+#define NTLM_ANY 0
+#define NTLM_NEGOTIATE 1
+#define NTLM_CHALLENGE 2
+#define NTLM_AUTHENTICATE 3
+
+/** This is an header common to all packets, it's used to discriminate
+ * among the different packet signature types.
*/
typedef struct _ntlmhdr {
char signature[8]; /**< "NTLMSSP" */
int32_t type; /**< One of the NTLM_* types above. */
} ntlmhdr;
+/** Validate the packet type matches one we want. */
+int ntlm_validate_packet(const ntlmhdr *packet, const int type);
+
+/** Retrieve a string from the NTLM packet payload. */
+lstring ntlm_fetch_string(const ntlmhdr *packet,
+ const int32_t packet_length,
+ const strhdr *str,
+ const u_int32_t flags);
+
+/** Append a string to the NTLM packet payload. */
+void ntlm_add_to_payload(const ntlmhdr *packet_hdr,
+ char *payload,
+ int *payload_length,
+ strhdr * hdr,
+ const char *toadd,
+ const int toadd_length);
+
+
+/* ************************************************************************* */
+/* Negotiate Packet structures and functions */
+/* ************************************************************************* */
+
+/* negotiate request flags */
+#define NEGOTIATE_UNICODE 0x0001
+#define NEGOTIATE_ASCII 0x0002
+#define NEGOTIATE_REQUEST_TARGET 0x0004
+#define NEGOTIATE_REQUEST_SIGN 0x0010
+#define NEGOTIATE_REQUEST_SEAL 0x0020
+#define NEGOTIATE_DATAGRAM_STYLE 0x0040
+#define NEGOTIATE_USE_LM 0x0080
+#define NEGOTIATE_USE_NETWARE 0x0100
+#define NEGOTIATE_USE_NTLM 0x0200
+#define NEGOTIATE_DOMAIN_SUPPLIED 0x1000
+#define NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
+#define NEGOTIATE_THIS_IS_LOCAL_CALL 0x4000
+#define NEGOTIATE_ALWAYS_SIGN 0x8000
+
/** Negotiation request sent by client */
typedef struct _ntlm_negotiate {
ntlmhdr hdr; /**< "NTLMSSP" , LSWAP(0x1) */
@@ -127,17 +157,48 @@
char payload[256]; /**< String data */
} ntlm_negotiate;
+
+/* ************************************************************************* */
+/* Challenge Packet structures and functions */
+/* ************************************************************************* */
+
+#define NTLM_NONCE_LEN 8
+
+/* challenge request flags */
+#define CHALLENGE_TARGET_IS_DOMAIN 0x10000
+#define CHALLENGE_TARGET_IS_SERVER 0x20000
+#define CHALLENGE_TARGET_IS_SHARE 0x40000
+
/** Challenge request sent by server. */
typedef struct _ntlm_challenge {
ntlmhdr hdr; /**< "NTLMSSP" , LSWAP(0x2) */
strhdr target; /**< Authentication target (domain/server ...) */
u_int32_t flags; /**< Request flags */
- u_char challenge[NONCE_LEN]; /**< Challenge string */
+ u_char challenge[NTLM_NONCE_LEN]; /**< Challenge string */
u_int32_t context_low; /**< LS part of the server context handle */
u_int32_t context_high; /**< MS part of the server context handle */
char payload[256]; /**< String data */
} ntlm_challenge;
+/* Size of the ntlm_challenge structures formatted fields (excluding payload) */
+#define NTLM_CHALLENGE_HEADER_OFFSET (sizeof(ntlm_challenge)-256)
+
+/** Generate a challenge request nonce. */
+void ntlm_make_nonce(char *nonce);
+
+/** Generate a challenge request Blob to be sent to the client. */
+void ntlm_make_challenge(ntlm_challenge *ch,
+ const char *domain,
+ const char *domain_controller,
+ const char *challenge_nonce,
+ const int challenge_nonce_len,
+ const u_int32_t flags);
+
+
+/* ************************************************************************* */
+/* Authenticate Packet structures and functions */
+/* ************************************************************************* */
+
/** Authentication request sent by client in response to challenge */
typedef struct _ntlm_authenticate {
ntlmhdr hdr; /**< "NTLMSSP" , LSWAP(0x3) */
@@ -151,11 +212,15 @@
char payload[256 * 6]; /**< String data */
} ntlm_authenticate;
-const char *ntlm_make_challenge(char *domain, char *domain_controller,
- char *challenge_nonce, int challenge_nonce_len);
-lstring ntlm_fetch_string(char *packet, int32_t length, strhdr * str);
-void ntlm_add_to_payload(char *payload, int *payload_length,
- strhdr * hdr, char *toadd,
- int toadd_length, int base_offset);
+/** Unpack username and domain out of a packet payload. */
+int ntlm_unpack_auth(const ntlm_authenticate *auth,
+ char *user,
+ char *domain,
+ const int32_t size);
+
+
+#if __cplusplus
+}
+#endif
#endif /* SQUID_NTLMAUTH_H */
=== modified file 'lib/Makefile.am'
--- lib/Makefile.am 2010-05-28 21:53:06 +0000
+++ lib/Makefile.am 2010-06-03 06:52:51 +0000
@@ -78,7 +78,8 @@
# $(top_srcdir)/include/version.h should be a dependency
libntlmauth_a_SOURCES = \
- ntlmauth.c
+ ntlmauth.c \
+ $(top_srcdir)/include/ntlmauth.h
libntlmauth_a_LIBADD = \
$(LIBOBJS)
libsspwin32_a_SOURCES = \
=== modified file 'lib/ntlmauth.c'
--- lib/ntlmauth.c 2010-05-31 12:20:10 +0000
+++ lib/ntlmauth.c 2010-06-03 12:27:48 +0000
@@ -1,6 +1,10 @@
/*
* $Id$
*
+ * AUTHOR: Francesco Chemolli <kin...@kame.usr.dsi.unimi.it>
+ * AUTHOR: Guido Serassio: <guido.seras...@acmeconsulting.it>
+ * AUTHOR: Amos Jeffries <squ...@treenet.co.nz>
+ *
* * * * * * * * Legal stuff * * * * * * *
*
* (C) 2000 Francesco Chemolli <kin...@kame.usr.dsi.unimi.it>,
@@ -33,7 +37,10 @@
#include "ntlmauth.h"
#include "util.h" /* for base64-related stuff */
-#if UNUSED_CODE
+/* ************************************************************************* */
+/* DEBUG functions */
+/* ************************************************************************* */
+
/** Dumps NTLM flags to standard error for debugging purposes */
void
ntlm_dump_ntlmssp_flags(u_int32_t flags)
@@ -60,36 +67,94 @@
(flags & REQUEST_NON_NT_SESSION_KEY ? "Req_nonnt_sesskey " : "")
);
}
-#endif
+
+/* ************************************************************************* */
+/* Packet and Payload handling functions */
+/* ************************************************************************* */
+
+/**
+ * Check the validity of a decoded NTLM packet. Return -1 on error.
+ */
+int
+ntlm_validate_packet(const ntlmhdr * hdr, const int type)
+{
+ /*
+ * Must be the correct security package and request type.
+ * The 8 bytes compared includes the ASCII 'NUL'.
+ */
+ if (memcmp(hdr->signature, "NTLMSSP", 8) != 0) {
+ fprintf(stderr, "ntlmCheckHeader: bad header signature\n");
+ return (-1);
+ }
+ if (type == NTLM_ANY)
+ return 0;
+
+ if (le32toh(hdr->type) != type) {
+ /* don't report this error - it's ok as we do a if() around this function */
+// fprintf(stderr, "ntlmCheckHeader: type is %d, wanted %d\n", le32toh(hdr->type), type);
+ return (-1);
+ }
+ return (0);
+}
#define lstring_zero(s) s.str=NULL; s.l=-1;
/**
* Fetches a string from the authentication packet.
- * The lstring data-part points to inside the packet itself.
+ * The lstring data-part may point to inside the packet itself or a temporary static buffer.
* It's up to the user to memcpy() that if the value needs to
* be used in any way that requires a tailing \0. (can check whether the
* value is there though, in that case lstring.length == -1).
+ *
+ * String may be either ASCII or UNICODE depending on whether flags contains NEGOTIATE_ASCII
*/
lstring
-ntlm_fetch_string(char *packet, int32_t length, strhdr * str)
+ntlm_fetch_string(const ntlmhdr *packet, const int32_t packet_size, const strhdr * str, const u_int32_t flags)
{
int16_t l; /* length */
int32_t o; /* offset */
+ static char buf[NTLM_MAX_FIELD_LENGTH];
lstring rv;
+ u_short *s, c;
+ char *d, *sc;
lstring_zero(rv);
l = le16toh(str->len);
o = le32toh(str->offset);
- /* debug("fetch_string(plength=%d,l=%d,o=%d)\n",length,l,o); */
+ /* debug("fetch_string(plength=%d,l=%d,o=%d)\n",packet_size,l,o); */
- if (l < 0 || l > MAX_FIELD_LENGTH || o + l > length || o == 0) {
+ if (l < 0 || l > NTLM_MAX_FIELD_LENGTH || o + l > packet_size || o == 0) {
/* debug("ntlmssp: insane data (l: %d, o: %d)\n", l,o); */
return rv;
}
- rv.str = packet + o;
- rv.l = l;
+ rv.str = (char *)packet + o;
+ if ((flags & NEGOTIATE_ASCII) == 0) {
+ /* UNICODE string */
+ s = (u_short *) ((char *) packet + o);
+ rv.str = d = buf;
+
+ for (l >>= 1; l; s++, l--) {
+ c = le16toh(*s);
+ if (c > 254 || c == '\0') {
+ fprintf(stderr, "ntlmssp: bad unicode: %04x\n", c);
+ return rv;
+ }
+ *d++ = c;
+ rv.l++;
+ }
+ } else {
+ /* ASCII/OEM string */
+ sc = (char *) packet + o;
+
+ for (; l; l--) {
+ if (*sc == '\0' || !xisprint(*sc)) {
+ fprintf(stderr, "ntlmssp: bad ascii: %04x\n", *sc);
+ return rv;
+ }
+ rv.l++;
+ }
+ }
return rv;
}
@@ -99,54 +164,156 @@
* there is enough space in the payload string to accommodate the
* added value.
* payload_length and hdr will be modified as a side-effect.
- * base_offset is the payload offset from the packet's beginning, and is
*/
void
-ntlm_add_to_payload(char *payload, int *payload_length,
- strhdr * hdr, char *toadd,
- int toadd_length, int base_offset)
+ntlm_add_to_payload(const ntlmhdr *packet_hdr,
+ char *payload,
+ int *payload_length,
+ strhdr * hdr,
+ const char *toadd,
+ const int toadd_length)
{
-
int l = (*payload_length);
memcpy(payload + l, toadd, toadd_length);
hdr->len = htole16(toadd_length);
hdr->maxlen = htole16(toadd_length);
- hdr->offset = htole32(l + base_offset); /* 48 is the base offset of the payload */
+ hdr->offset = htole32(l + payload - (char*)packet_hdr);
(*payload_length) += toadd_length;
}
+/* ************************************************************************* */
+/* Negotiate Packet functions */
+/* ************************************************************************* */
+
+// ??
+
+
+/* ************************************************************************* */
+/* Challenge Packet functions */
+/* ************************************************************************* */
+
+/*
+ * Generates a challenge request nonce. The randomness of the 8 byte
+ * challenge strings can be guarenteed to be poor at best.
+ */
+void
+ntlm_make_nonce(char *nonce)
+{
+ static unsigned hash;
+ int i;
+ int r = (int) rand();
+ r = (hash ^ r) + r;
+
+ for (i = 0; i < NTLM_NONCE_LEN; i++) {
+ nonce[i] = r;
+ r = (r >> 2) ^ r;
+ }
+ hash = r;
+}
+
+#if DEAD_API
/**
* Prepares a base64-encode challenge packet to be sent to the client
* \note domain should be upper_case
* \note the storage type for the returned value depends on
* base64_encode_bin. Currently this means static storage.
*/
-const char *
-ntlm_make_challenge(char *domain, char *domain_controller,
- char *challenge_nonce, int challenge_nonce_len)
-{
- ntlm_challenge ch;
+void
+ntlm_make_challenge(const char *domain, const char *dc_UNUSED,
+ const char *cn, const int cnl)
+{
+ /* This function API has changes somewhat, and not all user helpers */
+ ntlm_challenge chal;
+
+ /* ORIGINAL flags was HARD-CODED set to these:
+ TODO: find all old callers (without flags field) and have them send these in manually now...
+ */
+ u_int32_t flags = REQUEST_NON_NT_SESSION_KEY |
+ CHALLENGE_TARGET_IS_DOMAIN |
+ NEGOTIATE_ALWAYS_SIGN |
+ NEGOTIATE_USE_NTLM |
+ NEGOTIATE_USE_LM |
+ NEGOTIATE_ASCII;
+
+ ntlm_make_challenge(&chal, domain, dc_UNUSED, cn, cnl, flags);
+
+/* ORIGINAL handling of ntlm_challenge object was to encode it like this:
+ TODO: find all old callers and have them do teh decode themselves now.
+*/
+ return base64_encode_bin((char *)&chal, NTLM_CHALLENGE_HEADER_OFFSET + pl);
+}
+#endif
+
+/**
+ * Prepares a challenge packet to be sent to the client
+ * \note domain should be upper_case
+ */
+void
+ntlm_make_challenge(ntlm_challenge *ch,
+ const char *domain, const char *domain_controller_UNUSED,
+ const char *challenge_nonce, const int challenge_nonce_len,
+ const u_int32_t flags)
+{
int pl = 0;
- const char *encoded;
- memset(&ch, 0, sizeof(ntlm_challenge)); /* reset */
- memcpy(ch.hdr.signature, "NTLMSSP", 8); /* set the signature */
- ch.hdr.type = htole32(NTLM_CHALLENGE); /* this is a challenge */
- ntlm_add_to_payload(ch.payload, &pl, &ch.target, domain, strlen(domain),
- NTLM_CHALLENGE_HEADER_OFFSET);
- ch.flags = htole32(
- REQUEST_NON_NT_SESSION_KEY |
- CHALLENGE_TARGET_IS_DOMAIN |
- NEGOTIATE_ALWAYS_SIGN |
- NEGOTIATE_USE_NTLM |
- NEGOTIATE_USE_LM |
- NEGOTIATE_ASCII |
- 0
- );
- ch.context_low = 0; /* check this out */
- ch.context_high = 0;
- memcpy(ch.challenge, challenge_nonce, challenge_nonce_len);
- encoded = base64_encode_bin((char *) &ch, NTLM_CHALLENGE_HEADER_OFFSET + pl);
- return encoded;
+ memset(ch, 0, sizeof(ntlm_challenge)); /* reset */
+ memcpy(ch->hdr.signature, "NTLMSSP", 8); /* set the signature */
+ ch->hdr.type = htole32(NTLM_CHALLENGE); /* this is a challenge */
+ if (domain != NULL) {
+ ntlm_add_to_payload(&ch->hdr, ch->payload, &pl, &ch->target, domain, strlen(domain));
+ }
+ ch->flags = htole32(flags);
+ ch->context_low = 0; /* check this out */
+ ch->context_high = 0;
+ memcpy(ch->challenge, challenge_nonce, challenge_nonce_len);
+}
+
+/* ************************************************************************* */
+/* Authenticate Packet functions */
+/* ************************************************************************* */
+
+/**
+ * Unpack the strings in an NTLM authentication response from client.
+ * The caller is responsible for initializing the user and domain buffers
+ * this function will only insert data if the packet contains any. Otherwise
+ * the buffers will be left untouched.
+ *
+ * \retval -1 packet type is not an authentication packet.
+ * \retval 0 username present and maybe also domain.
+ * \retval 1 no username.
+ */
+int
+ntlm_unpack_auth(const ntlm_authenticate *auth, char *user, char *domain, const int32_t size)
+{
+ const char *p;
+ unsigned int s;
+ lstring rv;
+
+ if (ntlm_validate_packet(&auth->hdr, NTLM_AUTHENTICATE)) {
+ fprintf(stderr, "ntlmDecodeAuth: header check fails\n");
+ return -1;
+ }
+ debug("ntlmDecodeAuth: size of %d\n", size);
+ debug("ntlmDecodeAuth: flg %08x\n", auth->flags);
+ debug("ntlmDecodeAuth: usr o(%d) l(%d)\n", auth->user.offset, auth->user.len);
+
+ rv = ntlm_fetch_string(&auth->hdr, size, &auth->domain, auth->flags);
+ if (rv.l > 0) {
+ memcpy(rv.str, domain, rv.l);
+ domain[rv.l] = '\0';
+ debug("ntlm_unpack_auth: Domain '%s'.\n", domain);
+ }
+ if (rv.l >= size)
+ return 1;
+
+ rv = ntlm_fetch_string(&auth->hdr, size, &auth->user, auth->flags);
+ if (rv.l > 0) {
+ memcpy(rv.str, user, rv.l);
+ user[rv.l] = '\0';
+ debug("ntlm_unpack_auth: Username '%s'.\n", user);
+ } else
+ return 1;
+
+ return 0;
}