]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug #582: fake_auth ntlmGetString: bad ascii: ffffffb9 followed by FATAL: authenticat...
authorserassio <>
Mon, 14 Aug 2006 23:13:21 +0000 (23:13 +0000)
committerserassio <>
Mon, 14 Aug 2006 23:13:21 +0000 (23:13 +0000)
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.

helpers/ntlm_auth/fakeauth/fakeauth_auth.c
helpers/ntlm_auth/fakeauth/ntlm.h

index 34210732874bc40a66c870f79e594857bdf0383a..c51535a5933f468309ab11dcb43cc565a9de09d6 100644 (file)
  * 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: <guido.serassio@acmeconsulting.it>
+ *
+ * - 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 <ctype.h>
 
 #if HAVE_PWD_H
 #include <pwd.h>
 #endif
-
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#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);
 }
index b402aad8c78d6eed4343429b82ccb531e01018de..af7d22beba09d481fcccb0f6343ed654841af1b8 100644 (file)
@@ -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 <ad@interlude.eu.org>
  *
@@ -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 <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 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_ */