=== modified file 'configure.in' --- configure.in 2010-05-29 18:39:21 +0000 +++ configure.in 2010-05-31 09:38:35 +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-05-31 09:32:19 +0000 +++ doc/release-notes/release-3.2.sgml 2010-05-31 09:42:15 +0000 @@ -123,6 +123,7 @@ NTLM Authentication protocol helpers

+ fakeauth_auth - ntlm_fake_auth - Perform NTLMSSP to recover the username but don't verify the password. ntlm_auth - ntlm_smb_lm_auth - Perform SMB LanManager domain-less authentication over NTLM protocol. === 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-05-31 09:39:26 +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-02 05:00:03 +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 - * - * 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 - -/* 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 - -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 -#include -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-02 11:24:29 +0000 @@ -1,7 +1,38 @@ /* + * $Id$ * + * AUTHOR: Andrew Doran * AUTHOR: Robert Collins - * + * AUTHOR: Guido Serassio: + * + * 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 . 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 - -#if HAVE_STDIO_H -#include -#endif -#if HAVE_STDLIB_H -#include -#endif -#if HAVE_UNISTD_H -#include #endif #if HAVE_STRING_H #include @@ -46,7 +72,18 @@ #if HAVE_GETOPT_H #include #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); +#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 #define ERR "ERR\n" #define OK "OK\n" @@ -54,15 +91,17 @@ #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 ad@interlude.eu.org - 07/1999 */ /* XXX this is not done cleanly... */ +int ntlmCheckNegotiation(ntlm_negotiate *neg); +int ntlmAuthenticate(ntlm_authenticate *neg); + 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 +124,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,149 +170,23 @@ } } - -/* - * 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) +ntlmDecodeAuth(ntlm_authenticate *auth, char *buf, size_t size) { const char *p; char *origbuf; - int s; + unsigned int s; + lstring rv; + static char my_buf[512]; if (!buf) { return 1; } origbuf = buf; - if (ntlmCheckHeader(&auth->hdr, NTLM_AUTHENTICATE)) { + if (ntlm_validate_packet(&auth->hdr, NTLM_AUTHENTICATE)) { fprintf(stderr, "ntlmDecodeAuth: header check fails\n"); return -1; } @@ -281,7 +194,12 @@ 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) + rv = ntlm_fetch_string(&auth->hdr, size, &auth->domain, auth->flags); + if (rv.l > 0) { + memcpy(rv.str, my_buf, rv.l); + my_buf[rv.l] = '\0'; + p = my_buf; + } else p = authenticate_ntlm_domain; debug("ntlmDecodeAuth: Domain '%s'.\n", p); @@ -296,7 +214,12 @@ buf += (s - 1); *buf++ = '\\'; /* Using \ is more consistent with MS-proxy */ - if ( (p = ntlmGetString(&auth->hdr, &auth->user, auth->flags)) == NULL) + rv = ntlm_fetch_string(&auth->hdr, size, &auth->user, auth->flags); + if (rv.l > 0) { + memcpy(rv.str, my_buf, rv.l); + my_buf[rv.l] = '\0'; + p = my_buf; + } else return 1; if ((s = strlen(p) + 1) >= size) @@ -376,8 +299,8 @@ char buf[BUFFER_SIZE]; int buflen = 0; char user[256], *p, *decoded = NULL; - struct ntlm_challenge chal; - struct ntlm_negotiate *nego; + ntlm_challenge chal; + ntlm_negotiate *nego; char helper_command[3]; int len; char *data = NULL; @@ -403,32 +326,36 @@ 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*)decoded, ((strlen(buf) - 3) * 3) / 4); } else debug("Got '%s' from Squid\n", buf); if (strncasecmp(buf, "YR", 2) == 0) { + char nonce[NTLM_NONCE_LEN]; + 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); + nego = (ntlm_negotiate *) decoded; + 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 *)decoded, (strlen(data) * 3) / 4); } 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)) { + } else if (!ntlm_validate_packet((ntlmhdr *) decoded, NTLM_AUTHENTICATE)) { + if (!ntlmDecodeAuth((ntlm_authenticate *) decoded, user, 256)) { lc(user); if (strip_domain_enabled) { strtok(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-02 05:00: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-02 12:19:24 +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-01 13:01:28 +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-01 13:02:56 +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-02 04:49:18 +0000 @@ -95,6 +95,9 @@ #define xmemmove(d,s,n) bcopy((s),(d),(n)) #endif +#if HAVE_CTYPE_H +#include +#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-02 12:12:59 +0000 @@ -57,6 +57,10 @@ /* 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 */ @@ -64,13 +68,12 @@ /* Here start the NTLMSSP definitions */ /* NTLM request types that we know about */ +#define NTLM_ANY 0 #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 @@ -118,6 +121,12 @@ 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 (decoded blob). */ +lstring ntlm_fetch_string(const ntlmhdr *packet, const int32_t packet_length, const strhdr *str, const u_int32_t flags); + /** Negotiation request sent by client */ typedef struct _ntlm_negotiate { ntlmhdr hdr; /**< "NTLMSSP" , LSWAP(0x1) */ @@ -127,17 +136,28 @@ char payload[256]; /**< String data */ } ntlm_negotiate; +#define NTLM_NONCE_LEN 8 + /** 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; +/** 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); + /** Authentication request sent by client in response to challenge */ typedef struct _ntlm_authenticate { ntlmhdr hdr; /**< "NTLMSSP" , LSWAP(0x3) */ @@ -151,11 +171,18 @@ 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); + +/* Other functions */ + void ntlm_add_to_payload(char *payload, int *payload_length, - strhdr * hdr, char *toadd, + strhdr * hdr, const char *toadd, int toadd_length, int base_offset); +/** Debug dump the given flags field to stderr */ +void ntlm_dump_ntlmssp_flags(const u_int32_t flags); + +#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-02 11:27:32 +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-02 12:12:43 +0000 @@ -1,6 +1,10 @@ /* * $Id$ * + * AUTHOR: Francesco Chemolli + * AUTHOR: Guido Serassio: + * AUTHOR: Amos Jeffries + * * * * * * * * * Legal stuff * * * * * * * * * (C) 2000 Francesco Chemolli , @@ -33,7 +37,6 @@ #include "ntlmauth.h" #include "util.h" /* for base64-related stuff */ -#if UNUSED_CODE /** Dumps NTLM flags to standard error for debugging purposes */ void ntlm_dump_ntlmssp_flags(u_int32_t flags) @@ -60,36 +63,65 @@ (flags & REQUEST_NON_NT_SESSION_KEY ? "Req_nonnt_sesskey " : "") ); } -#endif #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[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 > 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; } @@ -103,10 +135,9 @@ */ void ntlm_add_to_payload(char *payload, int *payload_length, - strhdr * hdr, char *toadd, + strhdr * hdr, const char *toadd, int toadd_length, int base_offset) { - int l = (*payload_length); memcpy(payload + l, toadd, toadd_length); @@ -116,37 +147,106 @@ (*payload_length) += toadd_length; } - -/** - * 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; +/* + * 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. + */ +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 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. + */ +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->payload, &pl, &ch->target, domain, strlen(domain), + NTLM_CHALLENGE_HEADER_OFFSET); + } + ch->flags = htole32(flags); + ch->context_low = 0; /* check this out */ + ch->context_high = 0; + memcpy(ch->challenge, challenge_nonce, challenge_nonce_len); +} + +/** + * 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); }