From: serassio <> Date: Mon, 14 Aug 2006 23:13:21 +0000 (+0000) Subject: Bug #582: fake_auth ntlmGetString: bad ascii: ffffffb9 followed by FATAL: authenticat... X-Git-Tag: SQUID_3_0_PRE5~190 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0e6205b4f1d53562b36e8d6f315f54883b944fd7;p=thirdparty%2Fsquid.git Bug #582: fake_auth ntlmGetString: bad ascii: ffffffb9 followed by FATAL: authenticateNTLMHandleReply: called with no result string This is a major revision of fake_auth: - Added support for unicode char encoding - Added runtime debug functionality - Removed offending fprintf(stdout) - Removed obslete unused code sections The support for unicode char encoding allow the usage of high ascii characters in username with Windows NT/2000/XP/2003 clients. This still cannot work for obsolete Windows 9x clients. --- diff --git a/helpers/ntlm_auth/fakeauth/fakeauth_auth.c b/helpers/ntlm_auth/fakeauth/fakeauth_auth.c index 3421073287..c51535a593 100644 --- a/helpers/ntlm_auth/fakeauth/fakeauth_auth.c +++ b/helpers/ntlm_auth/fakeauth/fakeauth_auth.c @@ -10,13 +10,18 @@ * This code gets the username and returns it. No validation is done. * and by the way: it is a complete patch-up. Use the "real thing" NTLMSSP * if you can. - */ + * + * Revised by Guido Serassio: + * + * - Added negotiation of UNICODE char support + * - More detailed debugging info + * +*/ #include "config.h" #include "ntlmauth.h" #include "squid_endian.h" -#include "ntlm.h" #include "util.h" #include @@ -38,19 +43,86 @@ #if HAVE_PWD_H #include #endif - +#if HAVE_GETOPT_H +#include +#endif +#include "ntlm.h" #define ERR "ERR\n" #define OK "OK\n" -#if 0 -#define NTLM_STATIC_CHALLENGE "deadbeef" -#endif -static char *authenticate_ntlm_domain = "LIFELESSWKS"; +#define BUFFER_SIZE 10240 + +char *authenticate_ntlm_domain = "WORKGROUP"; +int debug_enabled = 0; +int NTLM_packet_debug_enabled = 0; /* NTLM authentication by ad@interlude.eu.org - 07/1999 */ /* XXX this is not done cleanly... */ +void +hex_dump(void *data, int size) +{ + /* dumps size bytes of *data to stdout. Looks like: + * [0000] 75 6E 6B 6E 6F 77 6E 20 + * 30 FF 00 00 00 00 39 00 unknown 0.....9. + * (in a single line of course) + */ + + if (!data) + return; + + if (debug_enabled) { + unsigned char *p = data; + unsigned char c; + int n; + char bytestr[4] = + {0}; + char addrstr[10] = + {0}; + char hexstr[16 * 3 + 5] = + {0}; + char charstr[16 * 1 + 5] = + {0}; + for (n = 1; n <= size; n++) { + if (n % 16 == 1) { + /* store address for this line */ + snprintf(addrstr, sizeof(addrstr), "%.4x", + ((unsigned int) p - (unsigned int) data)); + } + c = *p; + if (isalnum(c) == 0) { + c = '.'; + } + /* store hex str (for left side) */ + snprintf(bytestr, sizeof(bytestr), "%02X ", *p); + strncat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1); + + /* store char str (for right side) */ + snprintf(bytestr, sizeof(bytestr), "%c", c); + strncat(charstr, bytestr, sizeof(charstr) - strlen(charstr) - 1); + + if (n % 16 == 0) { + /* line completed */ + fprintf(stderr, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + hexstr[0] = 0; + charstr[0] = 0; + } else if (n % 8 == 0) { + /* half line: add whitespaces */ + strncat(hexstr, " ", sizeof(hexstr) - strlen(hexstr) - 1); + strncat(charstr, " ", sizeof(charstr) - strlen(charstr) - 1); + } + p++; /* next byte */ + } + + if (strlen(hexstr) > 0) { + /* print rest of buffer if not empty */ + fprintf(stderr, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + } + } +} + + /* makes a null-terminated string lower-case. Changes CONTENTS! */ static void lc(char *string) @@ -68,18 +140,23 @@ lc(char *string) * challenge strings can be guarenteed to be poor at best. */ void -ntlmMakeChallenge(struct ntlm_challenge *chal) +ntlmMakeChallenge(struct ntlm_challenge *chal, int32_t flags) { -#ifndef NTLM_STATIC_CHALLENGE static unsigned hash; int r; -#endif char *d; int i; + debug("ntlmMakeChallenge: flg %08x\n", flags); + memset(chal, 0, sizeof(*chal)); memcpy(chal->hdr.signature, "NTLMSSP", 8); - chal->flags = htole32(0x00018206); + 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->unknown[6] = htole16(0x003a); @@ -94,9 +171,6 @@ ntlmMakeChallenge(struct ntlm_challenge *chal) chal->target.maxlen = htole16(i); chal->target.len = chal->target.maxlen; -#ifdef NTLM_STATIC_CHALLENGE - memcpy(chal->challenge, NTLM_STATIC_CHALLENGE, 8); -#else r = (int) rand(); r = (hash ^ r) + r; @@ -106,7 +180,6 @@ ntlmMakeChallenge(struct ntlm_challenge *chal) } hash = r; -#endif } /* @@ -154,29 +227,28 @@ ntlmGetString(ntlmhdr * hdr, strhdr * str, int flags) fprintf(stderr, "ntlmGetString: insane: l:%d o:%d\n", l, o); return (NULL); } - if ((flags & 2) == 0) { + 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' || !isprint(c)) { + if (c > 254 || c == '\0') { fprintf(stderr, "ntlmGetString: bad uni: %04x\n", c); return (NULL); } *d++ = c; - fprintf(stderr, "ntlmGetString: conv: '%c'\n", c); } *d = 0; } else { - /* ASCII string */ + /* ASCII/OEM string */ sc = (char *) hdr + o; d = buf; for (; l; l--) { - if (*sc == '\0' || !isprint((int)(unsigned char)*sc)) { + if (*sc == '\0' || !isprint((int) (unsigned char) *sc)) { fprintf(stderr, "ntlmGetString: bad ascii: %04x\n", *sc); return (NULL); } @@ -203,28 +275,29 @@ ntlmDecodeAuth(struct ntlm_authenticate *auth, char *buf, size_t size) } origbuf = buf; if (ntlmCheckHeader(&auth->hdr, NTLM_AUTHENTICATE)) { - fprintf(stderr, "ntlmDecodeAuth: header check fails\n"); return -1; } -/* only on when you need to debug - * fprintf(stderr,"ntlmDecodeAuth: size of %d\n", size); - * fprintf(stderr,"ntlmDecodeAuth: flg %08x\n", auth->flags); - * fprintf(stderr,"ntlmDecodeAuth: usr o(%d) l(%d)\n", auth->user.offset, auth->user.len); - */ - if ((p = ntlmGetString(&auth->hdr, &auth->domain, 2)) == NULL) + 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); + + if ((p = ntlmGetString(&auth->hdr, &auth->domain, auth->flags)) == NULL) p = authenticate_ntlm_domain; -// fprintf(stderr,"ntlmDecodeAuth: Domain '%s'.\n",p); + + debug("ntlmDecodeAuth: Domain '%s'.\n", p); + if ((s = strlen(p) + 1) >= size) return 1; strcpy(buf, p); -// fprintf(stdout,"ntlmDecodeAuth: Domain '%s'.\n",buf); + + debug("ntlmDecodeAuth: Domain '%s'.\n", buf); size -= s; buf += (s - 1); *buf++ = '\\'; /* Using \ is more consistent with MS-proxy */ - p = ntlmGetString(&auth->hdr, &auth->user, 2); + p = ntlmGetString(&auth->hdr, &auth->user, auth->flags); if ((s = strlen(p) + 1) >= size) return 1; while (*p) @@ -232,81 +305,130 @@ ntlmDecodeAuth(struct ntlm_authenticate *auth, char *buf, size_t size) *buf++ = '\0'; size -= s; -// fprintf(stderr, "ntlmDecodeAuth: user: %s%s\n",origbuf, p); + debug("ntlmDecodeAuth: user: %s%s\n", origbuf, p); return 0; } +/* + * options: + * -d enable debugging. + * -v enable verbose NTLM packet debugging. + * -l if specified, changes behavior on failures to last-ditch. + */ +char *my_program_name = NULL; + +void +usage() +{ + fprintf(stderr, + "Usage: %s [-d] [-v] [-h]\n" + " -d enable debugging.\n" + " -v enable verbose NTLM packet debugging.\n" + " -h this message\n\n", + my_program_name); +} + + +void +process_options(int argc, char *argv[]) +{ + int opt, had_error = 0; + + opterr = 0; + while (-1 != (opt = getopt(argc, argv, "hdv"))) { + switch (opt) { + case 'd': + debug_enabled = 1; + break; + case 'v': + debug_enabled = 1; + NTLM_packet_debug_enabled = 1; + break; + case 'h': + usage(); + exit(0); + case '?': + opt = optopt; + /* fall thru to default */ + default: + fprintf(stderr, "unknown option: -%c. Exiting\n", opt); + usage(); + had_error = 1; + } + } + if (had_error) + exit(1); +} + + int -main() +main(int argc, char *argv[]) { - char buf[256]; - char user[256], *p, *cleartext; + char buf[BUFFER_SIZE]; + char user[256], *p, *decoded = NULL; struct ntlm_challenge chal; + struct ntlm_negotiate *nego; + char helper_command[3]; int len; char *data = NULL; setbuf(stdout, NULL); - while (fgets(buf, 256, stdin) != NULL) { + setbuf(stderr, NULL); + + my_program_name = argv[0]; + + process_options(argc, argv); + + debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name); + + while (fgets(buf, BUFFER_SIZE, stdin) != NULL) { user[0] = '\0'; /*no usercode */ if ((p = strchr(buf, '\n')) != NULL) *p = '\0'; /* strip \n */ -#if defined(NTLMHELPPROTOCOLV3) || !defined(NTLMHELPPROTOCOLV2) + if ((strlen(buf) > 3) && NTLM_packet_debug_enabled) { + decoded = base64_decode(buf + 3); + 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); + } else + debug("Got '%s' from Squid\n", buf); + if (strncasecmp(buf, "YR", 2) == 0) { - ntlmMakeChallenge(&chal); + if (strlen(buf) > 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); data = (char *) base64_encode_bin((char *) &chal, len); - printf("TT %s\n", data); + 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); + } else + SEND2("TT %s", data); } else if (strncasecmp(buf, "KK ", 3) == 0) { - cleartext = (char *) uudecode(buf + 3); - if (!ntlmCheckHeader((ntlmhdr *) cleartext, NTLM_AUTHENTICATE)) { - if (!ntlmDecodeAuth((struct ntlm_authenticate *) cleartext, user, 256)) { - lc(user); - printf("AF %s\n", user); - } else { - lc(user); - printf("NA invalid credentials%s\n", user); - } - } else { - lc(user); - printf("BH wrong packet type!%s\n", user); - } - } -#endif -#ifdef NTLMHELPPROTOCOLV2 -/* V2 of the protocol */ - if (strncasecmp(buf, "RESET", 5) == 0) { - printf("RESET OK\n"); - } else { - cleartext = (char *) uudecode(buf); - if (!ntlmCheckHeader((struct ntlmhdr *) cleartext, NTLM_NEGOTIATE)) { - ntlmMakeChallenge(&chal); - len = - sizeof(chal) - sizeof(chal.pad) + - le16toh(chal.target.maxlen); - data = (char *) base64_encode_bin((char *) &chal, len); - printf("CH %s\n", data); - } else if (!ntlmCheckHeader - ((struct ntlmhdr *) cleartext, NTLM_AUTHENTICATE)) { - if (!ntlmDecodeAuth - ((struct ntlm_authenticate *) cleartext, user, 256)) { + if (!ntlmCheckHeader((ntlmhdr *) decoded, NTLM_AUTHENTICATE)) { + if (!ntlmDecodeAuth((struct ntlm_authenticate *) decoded, user, 256)) { lc(user); - printf("OK %s\n", user); + SEND2("AF %s", user); } else { lc(user); - printf("ERR %s\n", user); + SEND2("NA invalid credentials, user=%s", user); } } else { lc(user); - printf("ERR %s\n", user); + SEND2("BH wrong packet type! user=%s", user); } } -#endif /*v2 */ } exit(0); } diff --git a/helpers/ntlm_auth/fakeauth/ntlm.h b/helpers/ntlm_auth/fakeauth/ntlm.h index b402aad8c7..af7d22beba 100644 --- a/helpers/ntlm_auth/fakeauth/ntlm.h +++ b/helpers/ntlm_auth/fakeauth/ntlm.h @@ -1,5 +1,5 @@ /* - * $Id: ntlm.h,v 1.6 2003/08/05 21:40:02 robertc Exp $ + * $Id: ntlm.h,v 1.7 2006/08/14 17:13:21 serassio Exp $ * * AUTHOR: Andrew Doran * @@ -44,9 +44,6 @@ #include "squid_endian.h" /* NTLM request types that we know about */ -#define NTLM_NEGOTIATE 1 -#define NTLM_CHALLENGE 2 -#define NTLM_AUTHENTICATE 3 #define NTLM_ANY 0 /* Negotiation request sent by client */ @@ -82,9 +79,83 @@ struct ntlm_authenticate { }; char *ntlmGetString(ntlmhdr * hdr, strhdr * str, int flags); -void ntlmMakeChallenge(struct ntlm_challenge *chal); +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 char *__foo; +#define debug(X...) if (debug_enabled) { \ + fprintf(stderr,"ntlm-auth[%d](%s:%d): ", 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[%d]: ", 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_ */