--------------------- PatchSet 2019 Date: 2005/10/30 16:48:08 Author: serassio Branch: nt Tag: (none) Log: Renamed Windows native NTLM helper from NTLMSSP-WIN32 to mswin_sspi Members: helpers/ntlm_auth/Makefile.am:1.3.16.2->1.3.16.3 helpers/ntlm_auth/NTLMSSP-WIN32/.cvsignore:1.1.2.1->1.1.2.2(DEAD) helpers/ntlm_auth/NTLMSSP-WIN32/Makefile.am:1.2.18.3->1.2.18.4(DEAD) helpers/ntlm_auth/NTLMSSP-WIN32/libntlmssp.c:1.2.18.8->1.2.18.9(DEAD) helpers/ntlm_auth/NTLMSSP-WIN32/ntlm.h:1.2.18.4->1.2.18.5(DEAD) helpers/ntlm_auth/NTLMSSP-WIN32/ntlm_auth.c:1.2.18.8->1.2.18.9(DEAD) helpers/ntlm_auth/NTLMSSP-WIN32/readme.txt:1.2.18.4->1.2.18.5(DEAD) helpers/ntlm_auth/mswin_sspi/.cvsignore:1.1->1.1.2.1 helpers/ntlm_auth/mswin_sspi/Makefile.am:1.1->1.1.2.1 helpers/ntlm_auth/mswin_sspi/libntlmssp.c:1.1->1.1.2.1 helpers/ntlm_auth/mswin_sspi/ntlm.h:1.1->1.1.2.1 helpers/ntlm_auth/mswin_sspi/ntlm_auth.c:1.1->1.1.2.1 helpers/ntlm_auth/mswin_sspi/readme.txt:1.1->1.1.2.1 Index: squid3/helpers/ntlm_auth/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid3/helpers/ntlm_auth/Makefile.am,v retrieving revision 1.3.16.2 retrieving revision 1.3.16.3 diff -u -r1.3.16.2 -r1.3.16.3 --- squid3/helpers/ntlm_auth/Makefile.am 2 Jul 2005 10:16:22 -0000 1.3.16.2 +++ squid3/helpers/ntlm_auth/Makefile.am 30 Oct 2005 16:48:08 -0000 1.3.16.3 @@ -1,7 +1,7 @@ # Makefile for storage modules in the Squid Object Cache server # -# $Id: Makefile.am,v 1.3.16.2 2005/07/02 10:16:22 serassio Exp $ +# $Id: Makefile.am,v 1.3.16.3 2005/10/30 16:48:08 serassio Exp $ # -DIST_SUBDIRS = fakeauth no_check SMB NTLMSSP-WIN32 +DIST_SUBDIRS = fakeauth no_check SMB mswin_sspi SUBDIRS = @NTLM_AUTH_HELPERS@ --- squid3/helpers/ntlm_auth/NTLMSSP-WIN32/.cvsignore Wed Feb 14 13:35:26 2007 +++ /dev/null Wed Feb 14 13:33:00 2007 @@ -1,4 +0,0 @@ -.cvsignore -Makefile.in -Makefile -.deps --- squid3/helpers/ntlm_auth/NTLMSSP-WIN32/Makefile.am Wed Feb 14 13:35:26 2007 +++ /dev/null Wed Feb 14 13:33:00 2007 @@ -1,16 +0,0 @@ -# -# Makefile for the Squid Object Cache server -# -# $Id: Makefile.am,v 1.2.18.3 2005/08/21 18:41:05 serassio Exp $ -# - -libexec_PROGRAMS = win32_ntlm_auth - -win32_ntlm_auth_SOURCES = libntlmssp.c ntlm_auth.c ntlm.h - -INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src - -LDADD = -L$(top_builddir)/lib -lntlmauth -lsspwin32 -lnetapi32 \ - -ladvapi32 -lmiscutil $(CRYPTLIB) $(XTRA_LIBS) - -EXTRA_DIST = readme.txt --- squid3/helpers/ntlm_auth/NTLMSSP-WIN32/libntlmssp.c Wed Feb 14 13:35:26 2007 +++ /dev/null Wed Feb 14 13:33:00 2007 @@ -1,379 +0,0 @@ -/* - * (C) 2002 Guido Serassio - * Based on previous work of Francesco Chemolli and Robert Collins - * Distributed freely under the terms of the GNU General Public License, - * version 2. See the file COPYING for licensing details - * - * 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. - */ - -typedef unsigned char uchar; - -#include "util.h" -#include "ntlm.h" -#if HAVE_CTYPE_H -#include -#endif -#include -#include - -/* returns 1 on success, 0 on failure */ -int -Valid_Group(char *UserName, char *Group) -{ - int result = FALSE; - WCHAR wszUserName[UNLEN+1]; // Unicode user name - WCHAR wszGroup[GNLEN+1]; // Unicode Group - - LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; - LPLOCALGROUP_USERS_INFO_0 pTmpBuf; - DWORD dwLevel = 0; - DWORD dwFlags = LG_INCLUDE_INDIRECT; - DWORD dwPrefMaxLen = -1; - DWORD dwEntriesRead = 0; - DWORD dwTotalEntries = 0; - NET_API_STATUS nStatus; - DWORD i; - DWORD dwTotalCount = 0; - -/* Convert ANSI User Name and Group to Unicode */ - - MultiByteToWideChar(CP_ACP, 0, UserName, - strlen(UserName) + 1, wszUserName, - sizeof(wszUserName) / sizeof(wszUserName[0])); - MultiByteToWideChar(CP_ACP, 0, Group, - strlen(Group) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0])); - - /* - * Call the NetUserGetLocalGroups function - * specifying information level 0. - * - * The LG_INCLUDE_INDIRECT flag specifies that the - * function should also return the names of the local - * groups in which the user is indirectly a member. - */ - nStatus = NetUserGetLocalGroups(NULL, - wszUserName, - dwLevel, - dwFlags, - (LPBYTE *) & pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries); - /* - * If the call succeeds, - */ - if (nStatus == NERR_Success) { - if ((pTmpBuf = pBuf) != NULL) { - for (i = 0; i < dwEntriesRead; i++) { - if (pTmpBuf == NULL) { - result = FALSE; - break; - } - if (wcscmp(pTmpBuf->lgrui0_name, wszGroup) == 0) { - result = TRUE; - break; - } - pTmpBuf++; - dwTotalCount++; - } - } - } else - result = FALSE; -/* - * Free the allocated memory. - */ - if (pBuf != NULL) - NetApiBufferFree(pBuf); - return result; -} - - -char * AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr) -{ - size_t len; - static char * target; - - len = LsaStr.Length/sizeof(WCHAR) + 1; - - /* allocate buffer for str + null termination */ - safe_free(target); - target = (char *)xmalloc(len); - if (target == NULL) - return NULL; - - /* copy unicode buffer */ - WideCharToMultiByte(CP_ACP, 0, LsaStr.Buffer, LsaStr.Length, target, len, NULL, NULL ); - - /* add null termination */ - target[len-1] = '\0'; - return target; -} - - -char * GetDomainName(void) - -{ - LSA_HANDLE PolicyHandle; - LSA_OBJECT_ATTRIBUTES ObjectAttributes; - NTSTATUS status; - PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo; - PWKSTA_INFO_100 pwkiWorkstationInfo; - DWORD netret; - char * DomainName = NULL; - - /* - * Always initialize the object attributes to all zeroes. - */ - memset(&ObjectAttributes, '\0', sizeof(ObjectAttributes)); - - /* - * You need the local workstation name. Use NetWkstaGetInfo at level - * 100 to retrieve a WKSTA_INFO_100 structure. - * - * The wki100_computername field contains a pointer to a UNICODE - * string containing the local computer name. - */ - netret = NetWkstaGetInfo(NULL, 100, (LPBYTE *)&pwkiWorkstationInfo); - if (netret == NERR_Success) { - /* - * We have the workstation name in: - * pwkiWorkstationInfo->wki100_computername - * - * Next, open the policy object for the local system using - * the LsaOpenPolicy function. - */ - status = LsaOpenPolicy( - NULL, - &ObjectAttributes, - GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION, - &PolicyHandle - ); - - /* - * Error checking. - */ - if (status) { - debug("OpenPolicy Error: %ld\n", status); - } else { - - /* - * You have a handle to the policy object. Now, get the - * domain information using LsaQueryInformationPolicy. - */ - status = LsaQueryInformationPolicy(PolicyHandle, - PolicyPrimaryDomainInformation, - (void **)&ppdiDomainInfo); - if (status) { - debug("LsaQueryInformationPolicy Error: %ld\n", status); - } else { - - /* Get name in useable format */ - DomainName = AllocStrFromLSAStr(ppdiDomainInfo->Name); - - /* - * Check the Sid pointer, if it is null, the - * workstation is either a stand-alone computer - * or a member of a workgroup. - */ - if (ppdiDomainInfo->Sid) { - - /* - * Member of a domain. Display it in debug mode. - */ - debug("Member of Domain %s\n",DomainName); - } else { - DomainName = NULL; - } - } - } - - /* - * Clean up all the memory buffers created by the LSA and - * Net* APIs. - */ - NetApiBufferFree(pwkiWorkstationInfo); - LsaFreeMemory((LPVOID)ppdiDomainInfo); - } else - debug("NetWkstaGetInfo Error: %ld\n", netret); - return DomainName; -} - - -int ntlm_errno; - - -/* returns NULL on failure, or a pointer to - * the user's credentials (domain\\username) - * upon success. WARNING. It's pointing to static storage. - * In case of problem sets as side-effect ntlm_errno to one of the - * codes defined in ntlm.h - */ -char * -ntlm_check_auth(ntlm_authenticate * auth, int auth_length) -{ - int rv; - char domain[DNLEN+1]; - char user[UNLEN+1]; - static char credentials[DNLEN+UNLEN+2]; /* we can afford to waste */ - - lstring tmp; - - if (!NTLM_LocalCall) { - - tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain); - - if (tmp.str == NULL || tmp.l == 0) { - debug("No domain supplied. Returning no-auth\n"); - ntlm_errno = NTLM_BAD_REQUEST; - return NULL; - } - if (Use_Unicode) { - /* copy unicode buffer */ - WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) tmp.str, tmp.l, domain, DNLEN, NULL, NULL ); - /* add null termination */ - domain[tmp.l / sizeof(WCHAR)] = '\0'; - } else { - if (tmp.l > DNLEN) { - debug("Domain string exceeds %d bytes, rejecting\n", DNLEN); - ntlm_errno = NTLM_BAD_REQUEST; - return NULL; - } - memcpy(domain, tmp.str, tmp.l); - domain[tmp.l] = '\0'; - } - tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user); - if (tmp.str == NULL || tmp.l == 0) { - debug("No username supplied. Returning no-auth\n"); - ntlm_errno = NTLM_BAD_REQUEST; - return NULL; - } - if (Use_Unicode) { - /* copy unicode buffer */ - WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) tmp.str, tmp.l, user, UNLEN, NULL, NULL ); - /* add null termination */ - user[tmp.l / sizeof(WCHAR)] = '\0'; - } else { - if (tmp.l > UNLEN) { - debug("Username string exceeds %d bytes, rejecting\n", UNLEN); - ntlm_errno = NTLM_BAD_REQUEST; - return NULL; - } - memcpy(user, tmp.str, tmp.l); - user[tmp.l] = '\0'; - } - debug("checking domain: '%s', user: '%s'\n", domain, user); - - } else - debug("checking local user\n"); - - rv = SSP_ValidateCredentials(auth, auth_length, credentials); - - debug("Login attempt had result %d\n", rv); - - if (!rv) { /* failed */ - ntlm_errno = NTLM_SSPI_ERROR; - return NULL; - } - - if (UseAllowedGroup) { - if (!Valid_Group(credentials, NTAllowedGroup)) { - ntlm_errno = NTLM_BAD_NTGROUP; - debug("User %s not in allowed Group %s\n", credentials, NTAllowedGroup); - return NULL; - } - } - if (UseDisallowedGroup) { - if (Valid_Group(credentials, NTDisAllowedGroup)) { - ntlm_errno = NTLM_BAD_NTGROUP; - debug("User %s is in denied Group %s\n", credentials, NTDisAllowedGroup); - return NULL; - } - } - - debug("credentials: %s\n", credentials); - return credentials; -} - - -const char * -ntlm_make_negotiate(void) -{ - ntlm_negotiate ne; - const char *encoded; - memset(&ne, 0, sizeof(ntlm_negotiate)); /* reset */ - memcpy(ne.signature, "NTLMSSP", 8); /* set the signature */ - ne.type = le32toh(NTLM_NEGOTIATE); /* this is a challenge */ - ne.flags = le32toh( - NEGOTIATE_ALWAYS_SIGN | - NEGOTIATE_USE_NTLM | - NEGOTIATE_USE_LM | - NEGOTIATE_ASCII | - 0 - ); - encoded = base64_encode_bin((char *) &ne, NEGOTIATE_LENGTH); - debug("Negotiate packet not supplied - self generated\n"); - return encoded; -} - - -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 (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); - } - } -} - --- squid3/helpers/ntlm_auth/NTLMSSP-WIN32/ntlm.h Wed Feb 14 13:35:26 2007 +++ /dev/null Wed Feb 14 13:33:00 2007 @@ -1,115 +0,0 @@ -/* - * (C) 2002 Guido Serassio - * Based on previous work of Francesco Chemolli, Robert Collins and Andrew Doran - * - * Distributed freely under the terms of the GNU General Public License, - * version 2. See the file COPYING for licensing details - * - * 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_ - -#include "sspwin32.h" -#include -#include -#include -#include "ntlmauth.h" -#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; -#ifdef 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 (debug_enabled || fail_debug_enabled) { - va_list args; - - va_start(args,format); - fprintf(stderr, "ntlm-auth[%d]: ",getpid()); - vfprintf(stderr, format, args); - va_end(args); -#ifdef 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 - -extern char * NTAllowedGroup; -extern char * NTDisAllowedGroup; -extern int UseDisallowedGroup; -extern int UseAllowedGroup; -extern int ntlm_errno; - -#define NTLM_NO_ERROR 0 -#define NTLM_SSPI_ERROR 1 -#define NTLM_BAD_NTGROUP 2 -#define NTLM_BAD_REQUEST 3 - -#define NEGOTIATE_LENGTH 16 - -extern void uc(char *); - -extern const char * ntlm_make_negotiate(void); -extern char *ntlm_check_auth(ntlm_authenticate * auth, int auth_length); -extern void hex_dump(void *, int); - -#define safe_free(x) if (x) { free(x); x = NULL; } - -#endif /* _NTLM_H_ */ --- squid3/helpers/ntlm_auth/NTLMSSP-WIN32/ntlm_auth.c Wed Feb 14 13:35:26 2007 +++ /dev/null Wed Feb 14 13:33:00 2007 @@ -1,421 +0,0 @@ -/* - * win32_ntlm_auth: helper for NTLM Authentication for Squid Cache - * - * (C)2002,2003 Guido Serassio - Acme Consulting S.r.l. - * - * Authors: - * Guido Serassio - * Acme Consulting S.r.l., Italy - * - * With contributions from others mentioned in the change history section - * below. - * - * Based on previous work of Francesco Chemolli and Robert Collins. - * - * Dependencies: Windows NT4 SP4 and later. - * - * 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. - * - * History: - * - * Version 1.21 - * 21-02-2004 Guido Serassio - * Removed control of use of NTLM NEGOTIATE packet from - * command line, now the support is automatic. - * Version 1.20 - * 30-11-2003 Guido Serassio - * Added support for NTLM local calls. - * Added control of use of NTLM NEGOTIATE packet from - * command line. - * Updated documentation. - * Version 1.10 - * 07-09-2003 Guido Serassio - * Now is true NTLM authenticator. - * More debug info. - * Updated documentation. - * Version 1.0 - * 29-06-2002 Guido Serassio - * First release. - * - * - */ - -#include "util.h" -#if HAVE_GETOPT_H -#include -#endif -#include "ntlm.h" -#if HAVE_CTYPE_H -#include -#endif - -#define BUFFER_SIZE 10240 - -#ifdef NTLM_FAIL_OPEN -int last_ditch_enabled = 0; -#endif - -int debug_enabled = 0; -int NTLM_packet_debug_enabled = 0; - -static int have_challenge; - -char * NTAllowedGroup; -char * NTDisAllowedGroup; -int UseDisallowedGroup = 0; -int UseAllowedGroup = 0; -#ifdef FAIL_DEBUG -int fail_debug_enabled = 0; -#endif - -/* makes a null-terminated string upper-case. Changes CONTENTS! */ -void -uc(char *string) -{ - char *p = string, c; - while ((c = *p)) { - *p = toupper(c); - p++; - } -} - -/* makes a null-terminated string lower-case. Changes CONTENTS! */ -static void -lc(char *string) -{ - char *p = string, c; - while ((c = *p)) { - *p = tolower(c); - p++; - } -} - -void -helperfail(const char *reason) -{ -#ifdef FAIL_DEBUG - fail_debug_enabled =1; -#endif - SEND2("BH %s", reason); -} - -/* - options: - -d enable debugging. - -v enable verbose NTLM packet debugging. - -l if specified, changes behavior on failures to last-ditch. - -A can specify a Windows Local Group name allowed to authenticate. - -D can specify a Windows Local Group name not allowed to authenticate. - */ -char *my_program_name = NULL; - -void -usage() -{ - fprintf(stderr, -#ifdef NTLM_FAIL_OPEN - "Usage: %s [-d] [-v] [-A|D LocalUserGroup] [-l] [-h]\n" -#else - "Usage: %s [-d] [-v] [-A|D LocalUserGroup] [-h]\n" -#endif - " -d enable debugging.\n" - " -v enable verbose NTLM packet debugging.\n" -#ifdef NTLM_FAIL_OPEN - " -l if specified, changes behavior on failures to last-ditch\n" -#endif - " -A specify a Windows Local Group name allowed to authenticate\n" - " -D specify a Windows Local Group name not allowed to authenticate\n" - " -h this message\n\n", - my_program_name); -} - - -void -process_options(int argc, char *argv[]) -{ - int opt, had_error = 0; - - opterr =0; -#ifdef NTLM_FAIL_OPEN - while (-1 != (opt = getopt(argc, argv, "hdvlA:D:"))) { -#else - while (-1 != (opt = getopt(argc, argv, "hdvA:D:"))) { -#endif - switch (opt) { - case 'A': - safe_free(NTAllowedGroup); - NTAllowedGroup=xstrdup(optarg); - UseAllowedGroup = 1; - break; - case 'D': - safe_free(NTDisAllowedGroup); - NTDisAllowedGroup=xstrdup(optarg); - UseDisallowedGroup = 1; - break; -#ifdef NTLM_FAIL_OPEN - case 'l': - last_ditch_enabled = 1; - break; -#endif - 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); -} - - -const char * -obtain_challenge(ntlm_negotiate * nego, int nego_length) -{ - const char *ch = NULL; - - debug("attempting SSPI challenge retrieval\n"); - ch = SSP_MakeChallenge(nego, nego_length); - if (ch) { - debug("Got it\n"); - return ch; /* All went OK, returning */ - } - return NULL; -} - - -int -manage_request() -{ - ntlmhdr *fast_header; - char buf[BUFFER_SIZE]; - char helper_command[3]; - char *c, *decoded, *cred; - int plen; - int oversized = 0; - char * ErrorMessage; - -try_again: - if (fgets(buf, BUFFER_SIZE, stdin) == NULL) - return 0; - - c = memchr(buf, '\n', BUFFER_SIZE); /* safer against overrun than strchr */ - if (c) { - if (oversized) { - helperfail("illegal request received"); - fprintf(stderr, "Illegal request received: '%s'\n", buf); - return 1; - } - *c = '\0'; - } else { - fprintf(stderr, "No newline in '%s'\n", buf); - oversized = 1; - goto try_again; - } - if ((strlen(buf) > 3) && NTLM_packet_debug_enabled) { - decoded = base64_decode(buf + 3); - strncpy(helper_command, buf, 2); - 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 (memcmp(buf, "YR", 2) == 0) { /* refresh-request */ - /* figure out what we got */ - if (strlen(buf) > 3) - decoded = base64_decode(buf + 3); - else - decoded = base64_decode(ntlm_make_negotiate()); - /* Note: we don't need to manage memory at this point, since - * base64_decode returns a pointer to static storage. - */ - if (!decoded) { /* decoding failure, return error */ - SEND("NA Packet format error, couldn't base64-decode"); - return 1; - } - /* fast-track-decode request type. */ - fast_header = (struct _ntlmhdr *) decoded; - - /* sanity-check: it IS a NTLMSSP packet, isn't it? */ - if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { - SEND("NA Broken authentication packet"); - return 1; - } - switch (fast_header->type) { - case NTLM_NEGOTIATE: - /* Obtain challenge against SSPI */ - if (strlen(buf) > 3) - plen = (strlen(buf) - 3) * 3 / 4; /* we only need it here. Optimization */ - else - plen = NEGOTIATE_LENGTH; - if ((c = (char *) obtain_challenge((ntlm_negotiate *) decoded, plen)) != NULL ) - { - if (NTLM_packet_debug_enabled) { - printf("TT %s\n",c); - decoded = base64_decode(c); - debug("sending 'TT' to squid with data:\n"); - hex_dump(decoded, (strlen(c) * 3) / 4); - if (NTLM_LocalCall) - debug("NTLM Local Call detected\n"); - } else { - SEND2("TT %s", c); - } - have_challenge = 1; - } else - helperfail("can't obtain challenge"); - return 1; - /* notreached */ - case NTLM_CHALLENGE: - SEND - ("NA Got a challenge. We refuse to have our authority disputed"); - return 1; - /* notreached */ - case NTLM_AUTHENTICATE: - SEND("NA Got authentication request instead of negotiate request"); - return 1; - /* notreached */ - default: - helperfail("unknown refresh-request packet type"); - return 1; - } - return 1; - } - if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */ - if (!have_challenge) { - helperfail("invalid challenge"); - return 1; - } - /* figure out what we got */ - decoded = base64_decode(buf + 3); - /* Note: we don't need to manage memory at this point, since - * base64_decode returns a pointer to static storage. - */ - - if (!decoded) { /* decoding failure, return error */ - SEND("NA Packet format error, couldn't base64-decode"); - return 1; - } - /* fast-track-decode request type. */ - fast_header = (struct _ntlmhdr *) decoded; - - /* sanity-check: it IS a NTLMSSP packet, isn't it? */ - if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { - SEND("NA Broken authentication packet"); - return 1; - } - switch (fast_header->type) { - case NTLM_NEGOTIATE: - SEND("NA Invalid negotiation request received"); - return 1; - /* notreached */ - case NTLM_CHALLENGE: - SEND - ("NA Got a challenge. We refuse to have our authority disputed"); - return 1; - /* notreached */ - case NTLM_AUTHENTICATE: - /* check against SSPI */ - plen = (strlen(buf) - 3) * 3 / 4; /* we only need it here. Optimization */ - cred = ntlm_check_auth((ntlm_authenticate *) decoded, plen); - have_challenge = 0; - if (cred == NULL) { -#ifdef FAIL_DEBUG - fail_debug_enabled =1; -#endif - switch (ntlm_errno) { - case NTLM_BAD_NTGROUP: - SEND("NA Incorrect Group Membership"); - return 1; - case NTLM_BAD_REQUEST: - SEND("NA Incorrect Request Format"); - return 1; - case NTLM_SSPI_ERROR: - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language - (LPTSTR) &ErrorMessage, - 0, - NULL); - if (ErrorMessage[strlen(ErrorMessage) - 1] == '\n') - ErrorMessage[strlen(ErrorMessage) - 1] = '\0'; - if (ErrorMessage[strlen(ErrorMessage) - 1] == '\r') - ErrorMessage[strlen(ErrorMessage) - 1] = '\0'; - SEND2("NA %s", ErrorMessage); - LocalFree(ErrorMessage); - return 1; - default: - SEND("NA Unknown Error"); - return 1; - } - } - lc(cred); /* let's lowercase them for our convenience */ - SEND2("AF %s", cred); - return 1; - default: - helperfail("unknown authentication packet type"); - return 1; - } - return 1; - } else { /* not an auth-request */ - helperfail("illegal request received"); - fprintf(stderr, "Illegal request received: '%s'\n", buf); - return 1; - } - helperfail("detected protocol error"); - return 1; -/********* END ********/ -} - -int -main(int argc, char *argv[]) -{ - my_program_name = argv[0]; - - process_options(argc, argv); - - debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name); - - if (LoadSecurityDll(SSP_NTLM) == NULL) { - fprintf(stderr, "FATAL, can't initialize SSPI, exiting.\n"); - exit(1); - } - debug("SSPI initialized OK\n"); - - atexit(UnloadSecurityDll); - - /* initialize FDescs */ - setbuf(stdout, NULL); - setbuf(stderr, NULL); - - while (manage_request()) { - /* everything is done within manage_request */ - } - exit(0); -} --- squid3/helpers/ntlm_auth/NTLMSSP-WIN32/readme.txt Wed Feb 14 13:35:26 2007 +++ /dev/null Wed Feb 14 13:33:00 2007 @@ -1,70 +0,0 @@ -win32_ntlm_auth.exe - -Native Windows NTLM/NTLMv2 authenticator for Squid 2.5 with -automatic support for NTLM NEGOTIATE packets. - -===== -Usage -===== - -win32_ntlm_auth [-d] [-v] [-A|D LocalUserGroup] [-h] - --d enables debugging. --v enables verbose NTLM packet debugging. --A specify a Windows Local Group name allowed to authenticate. --D specify a Windows Local Group name not allowed to authenticate. --h print program usage - -This is released under the GNU General Public License - -============== -Allowing Users -============== - -Users that are allowed to access the web proxy must have the Windows NT -User Rights "logon from the network". -Optionally the authenticator can verify the NT LOCAL group membership of -the user against the User Group specified in the Authenticator's command -line. -This can be accomplished creating a local user group on the NT machine, -grant the privilege, and adding users to it, it works only with MACHINE -Local Groups, not Domain Local Groups. -Better group checking is available with External Acl, see win32_check_group -documentation. - -The use of NTLM NEGOTIATE packet allow full NTLM/NTLMv2 support, but -Squid too must be configured to use NTLM NEGOTIATE, see squid.conf. - -Squid.conf typical minimal required changes: - -auth_param ntlm program c:/squid/libexec/win32_ntlm_auth.exe -auth_param ntlm children 5 -auth_param ntlm max_challenge_reuses 0 -auth_param ntlm max_challenge_lifetime 2 minutes -auth_param ntlm use_ntlm_negotiate on - -acl password proxy_auth REQUIRED - -http_access allow password -http_access deny all - -When using "use_ntlm_negotiate on" -max_challenge_reuses and max_challenge_lifetime parameters must be specified -but they are are ignored. - -Refer to Squid documentation for more details. - -Currently Internet Explorer has some problems with ftp:// URLs when handling -internal Squid FTP icons. The following squid.conf ACL works around this: - -acl internal_icons urlpath_regex -i /squid-internal-static/icons/ - -http_access allow our_networks internal_icons <== BEFORE authentication ACL !!! - - -=============== -Contact details -=============== - -To contact the maintainer of this package, e-mail on squidnt@acmeconsulting.it. -The latest version may be found on http://www.acmeconsulting.it/SquidNT.htm. --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/helpers/ntlm_auth/mswin_sspi/.cvsignore Wed Feb 14 13:35:26 2007 @@ -0,0 +1,4 @@ +.cvsignore +Makefile.in +Makefile +.deps --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/helpers/ntlm_auth/mswin_sspi/Makefile.am Wed Feb 14 13:35:26 2007 @@ -0,0 +1,16 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: Makefile.am,v 1.1.2.1 2005/10/30 16:48:08 serassio Exp $ +# + +libexec_PROGRAMS = mswin_ntlm_auth + +win32_ntlm_auth_SOURCES = libntlmssp.c ntlm_auth.c ntlm.h + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src + +LDADD = -L$(top_builddir)/lib -lntlmauth -lsspwin32 -lnetapi32 \ + -ladvapi32 -lmiscutil $(CRYPTLIB) $(XTRA_LIBS) + +EXTRA_DIST = readme.txt --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/helpers/ntlm_auth/mswin_sspi/libntlmssp.c Wed Feb 14 13:35:26 2007 @@ -0,0 +1,379 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli and Robert Collins + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * 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. + */ + +typedef unsigned char uchar; + +#include "util.h" +#include "ntlm.h" +#if HAVE_CTYPE_H +#include +#endif +#include +#include + +/* returns 1 on success, 0 on failure */ +int +Valid_Group(char *UserName, char *Group) +{ + int result = FALSE; + WCHAR wszUserName[UNLEN+1]; // Unicode user name + WCHAR wszGroup[GNLEN+1]; // Unicode Group + + LPLOCALGROUP_USERS_INFO_0 pBuf = NULL; + LPLOCALGROUP_USERS_INFO_0 pTmpBuf; + DWORD dwLevel = 0; + DWORD dwFlags = LG_INCLUDE_INDIRECT; + DWORD dwPrefMaxLen = -1; + DWORD dwEntriesRead = 0; + DWORD dwTotalEntries = 0; + NET_API_STATUS nStatus; + DWORD i; + DWORD dwTotalCount = 0; + +/* Convert ANSI User Name and Group to Unicode */ + + MultiByteToWideChar(CP_ACP, 0, UserName, + strlen(UserName) + 1, wszUserName, + sizeof(wszUserName) / sizeof(wszUserName[0])); + MultiByteToWideChar(CP_ACP, 0, Group, + strlen(Group) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0])); + + /* + * Call the NetUserGetLocalGroups function + * specifying information level 0. + * + * The LG_INCLUDE_INDIRECT flag specifies that the + * function should also return the names of the local + * groups in which the user is indirectly a member. + */ + nStatus = NetUserGetLocalGroups(NULL, + wszUserName, + dwLevel, + dwFlags, + (LPBYTE *) & pBuf, dwPrefMaxLen, &dwEntriesRead, &dwTotalEntries); + /* + * If the call succeeds, + */ + if (nStatus == NERR_Success) { + if ((pTmpBuf = pBuf) != NULL) { + for (i = 0; i < dwEntriesRead; i++) { + if (pTmpBuf == NULL) { + result = FALSE; + break; + } + if (wcscmp(pTmpBuf->lgrui0_name, wszGroup) == 0) { + result = TRUE; + break; + } + pTmpBuf++; + dwTotalCount++; + } + } + } else + result = FALSE; +/* + * Free the allocated memory. + */ + if (pBuf != NULL) + NetApiBufferFree(pBuf); + return result; +} + + +char * AllocStrFromLSAStr(LSA_UNICODE_STRING LsaStr) +{ + size_t len; + static char * target; + + len = LsaStr.Length/sizeof(WCHAR) + 1; + + /* allocate buffer for str + null termination */ + safe_free(target); + target = (char *)xmalloc(len); + if (target == NULL) + return NULL; + + /* copy unicode buffer */ + WideCharToMultiByte(CP_ACP, 0, LsaStr.Buffer, LsaStr.Length, target, len, NULL, NULL ); + + /* add null termination */ + target[len-1] = '\0'; + return target; +} + + +char * GetDomainName(void) + +{ + LSA_HANDLE PolicyHandle; + LSA_OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS status; + PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo; + PWKSTA_INFO_100 pwkiWorkstationInfo; + DWORD netret; + char * DomainName = NULL; + + /* + * Always initialize the object attributes to all zeroes. + */ + memset(&ObjectAttributes, '\0', sizeof(ObjectAttributes)); + + /* + * You need the local workstation name. Use NetWkstaGetInfo at level + * 100 to retrieve a WKSTA_INFO_100 structure. + * + * The wki100_computername field contains a pointer to a UNICODE + * string containing the local computer name. + */ + netret = NetWkstaGetInfo(NULL, 100, (LPBYTE *)&pwkiWorkstationInfo); + if (netret == NERR_Success) { + /* + * We have the workstation name in: + * pwkiWorkstationInfo->wki100_computername + * + * Next, open the policy object for the local system using + * the LsaOpenPolicy function. + */ + status = LsaOpenPolicy( + NULL, + &ObjectAttributes, + GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION, + &PolicyHandle + ); + + /* + * Error checking. + */ + if (status) { + debug("OpenPolicy Error: %ld\n", status); + } else { + + /* + * You have a handle to the policy object. Now, get the + * domain information using LsaQueryInformationPolicy. + */ + status = LsaQueryInformationPolicy(PolicyHandle, + PolicyPrimaryDomainInformation, + (void **)&ppdiDomainInfo); + if (status) { + debug("LsaQueryInformationPolicy Error: %ld\n", status); + } else { + + /* Get name in useable format */ + DomainName = AllocStrFromLSAStr(ppdiDomainInfo->Name); + + /* + * Check the Sid pointer, if it is null, the + * workstation is either a stand-alone computer + * or a member of a workgroup. + */ + if (ppdiDomainInfo->Sid) { + + /* + * Member of a domain. Display it in debug mode. + */ + debug("Member of Domain %s\n",DomainName); + } else { + DomainName = NULL; + } + } + } + + /* + * Clean up all the memory buffers created by the LSA and + * Net* APIs. + */ + NetApiBufferFree(pwkiWorkstationInfo); + LsaFreeMemory((LPVOID)ppdiDomainInfo); + } else + debug("NetWkstaGetInfo Error: %ld\n", netret); + return DomainName; +} + + +int ntlm_errno; + + +/* returns NULL on failure, or a pointer to + * the user's credentials (domain\\username) + * upon success. WARNING. It's pointing to static storage. + * In case of problem sets as side-effect ntlm_errno to one of the + * codes defined in ntlm.h + */ +char * +ntlm_check_auth(ntlm_authenticate * auth, int auth_length) +{ + int rv; + char domain[DNLEN+1]; + char user[UNLEN+1]; + static char credentials[DNLEN+UNLEN+2]; /* we can afford to waste */ + + lstring tmp; + + if (!NTLM_LocalCall) { + + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain); + + if (tmp.str == NULL || tmp.l == 0) { + debug("No domain supplied. Returning no-auth\n"); + ntlm_errno = NTLM_BAD_REQUEST; + return NULL; + } + if (Use_Unicode) { + /* copy unicode buffer */ + WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) tmp.str, tmp.l, domain, DNLEN, NULL, NULL ); + /* add null termination */ + domain[tmp.l / sizeof(WCHAR)] = '\0'; + } else { + if (tmp.l > DNLEN) { + debug("Domain string exceeds %d bytes, rejecting\n", DNLEN); + ntlm_errno = NTLM_BAD_REQUEST; + return NULL; + } + memcpy(domain, tmp.str, tmp.l); + domain[tmp.l] = '\0'; + } + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user); + if (tmp.str == NULL || tmp.l == 0) { + debug("No username supplied. Returning no-auth\n"); + ntlm_errno = NTLM_BAD_REQUEST; + return NULL; + } + if (Use_Unicode) { + /* copy unicode buffer */ + WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) tmp.str, tmp.l, user, UNLEN, NULL, NULL ); + /* add null termination */ + user[tmp.l / sizeof(WCHAR)] = '\0'; + } else { + if (tmp.l > UNLEN) { + debug("Username string exceeds %d bytes, rejecting\n", UNLEN); + ntlm_errno = NTLM_BAD_REQUEST; + return NULL; + } + memcpy(user, tmp.str, tmp.l); + user[tmp.l] = '\0'; + } + debug("checking domain: '%s', user: '%s'\n", domain, user); + + } else + debug("checking local user\n"); + + rv = SSP_ValidateCredentials(auth, auth_length, credentials); + + debug("Login attempt had result %d\n", rv); + + if (!rv) { /* failed */ + ntlm_errno = NTLM_SSPI_ERROR; + return NULL; + } + + if (UseAllowedGroup) { + if (!Valid_Group(credentials, NTAllowedGroup)) { + ntlm_errno = NTLM_BAD_NTGROUP; + debug("User %s not in allowed Group %s\n", credentials, NTAllowedGroup); + return NULL; + } + } + if (UseDisallowedGroup) { + if (Valid_Group(credentials, NTDisAllowedGroup)) { + ntlm_errno = NTLM_BAD_NTGROUP; + debug("User %s is in denied Group %s\n", credentials, NTDisAllowedGroup); + return NULL; + } + } + + debug("credentials: %s\n", credentials); + return credentials; +} + + +const char * +ntlm_make_negotiate(void) +{ + ntlm_negotiate ne; + const char *encoded; + memset(&ne, 0, sizeof(ntlm_negotiate)); /* reset */ + memcpy(ne.signature, "NTLMSSP", 8); /* set the signature */ + ne.type = le32toh(NTLM_NEGOTIATE); /* this is a challenge */ + ne.flags = le32toh( + NEGOTIATE_ALWAYS_SIGN | + NEGOTIATE_USE_NTLM | + NEGOTIATE_USE_LM | + NEGOTIATE_ASCII | + 0 + ); + encoded = base64_encode_bin((char *) &ne, NEGOTIATE_LENGTH); + debug("Negotiate packet not supplied - self generated\n"); + return encoded; +} + + +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 (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); + } + } +} + --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/helpers/ntlm_auth/mswin_sspi/ntlm.h Wed Feb 14 13:35:26 2007 @@ -0,0 +1,115 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli, Robert Collins and Andrew Doran + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * 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_ + +#include "sspwin32.h" +#include +#include +#include +#include "ntlmauth.h" +#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; +#ifdef 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 (debug_enabled || fail_debug_enabled) { + va_list args; + + va_start(args,format); + fprintf(stderr, "ntlm-auth[%d]: ",getpid()); + vfprintf(stderr, format, args); + va_end(args); +#ifdef 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 + +extern char * NTAllowedGroup; +extern char * NTDisAllowedGroup; +extern int UseDisallowedGroup; +extern int UseAllowedGroup; +extern int ntlm_errno; + +#define NTLM_NO_ERROR 0 +#define NTLM_SSPI_ERROR 1 +#define NTLM_BAD_NTGROUP 2 +#define NTLM_BAD_REQUEST 3 + +#define NEGOTIATE_LENGTH 16 + +extern void uc(char *); + +extern const char * ntlm_make_negotiate(void); +extern char *ntlm_check_auth(ntlm_authenticate * auth, int auth_length); +extern void hex_dump(void *, int); + +#define safe_free(x) if (x) { free(x); x = NULL; } + +#endif /* _NTLM_H_ */ --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/helpers/ntlm_auth/mswin_sspi/ntlm_auth.c Wed Feb 14 13:35:26 2007 @@ -0,0 +1,421 @@ +/* + * win32_ntlm_auth: helper for NTLM Authentication for Squid Cache + * + * (C)2002,2003 Guido Serassio - Acme Consulting S.r.l. + * + * Authors: + * Guido Serassio + * Acme Consulting S.r.l., Italy + * + * With contributions from others mentioned in the change history section + * below. + * + * Based on previous work of Francesco Chemolli and Robert Collins. + * + * Dependencies: Windows NT4 SP4 and later. + * + * 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. + * + * History: + * + * Version 1.21 + * 21-02-2004 Guido Serassio + * Removed control of use of NTLM NEGOTIATE packet from + * command line, now the support is automatic. + * Version 1.20 + * 30-11-2003 Guido Serassio + * Added support for NTLM local calls. + * Added control of use of NTLM NEGOTIATE packet from + * command line. + * Updated documentation. + * Version 1.10 + * 07-09-2003 Guido Serassio + * Now is true NTLM authenticator. + * More debug info. + * Updated documentation. + * Version 1.0 + * 29-06-2002 Guido Serassio + * First release. + * + * + */ + +#include "util.h" +#if HAVE_GETOPT_H +#include +#endif +#include "ntlm.h" +#if HAVE_CTYPE_H +#include +#endif + +#define BUFFER_SIZE 10240 + +#ifdef NTLM_FAIL_OPEN +int last_ditch_enabled = 0; +#endif + +int debug_enabled = 0; +int NTLM_packet_debug_enabled = 0; + +static int have_challenge; + +char * NTAllowedGroup; +char * NTDisAllowedGroup; +int UseDisallowedGroup = 0; +int UseAllowedGroup = 0; +#ifdef FAIL_DEBUG +int fail_debug_enabled = 0; +#endif + +/* makes a null-terminated string upper-case. Changes CONTENTS! */ +void +uc(char *string) +{ + char *p = string, c; + while ((c = *p)) { + *p = toupper(c); + p++; + } +} + +/* makes a null-terminated string lower-case. Changes CONTENTS! */ +static void +lc(char *string) +{ + char *p = string, c; + while ((c = *p)) { + *p = tolower(c); + p++; + } +} + +void +helperfail(const char *reason) +{ +#ifdef FAIL_DEBUG + fail_debug_enabled =1; +#endif + SEND2("BH %s", reason); +} + +/* + options: + -d enable debugging. + -v enable verbose NTLM packet debugging. + -l if specified, changes behavior on failures to last-ditch. + -A can specify a Windows Local Group name allowed to authenticate. + -D can specify a Windows Local Group name not allowed to authenticate. + */ +char *my_program_name = NULL; + +void +usage() +{ + fprintf(stderr, +#ifdef NTLM_FAIL_OPEN + "Usage: %s [-d] [-v] [-A|D LocalUserGroup] [-l] [-h]\n" +#else + "Usage: %s [-d] [-v] [-A|D LocalUserGroup] [-h]\n" +#endif + " -d enable debugging.\n" + " -v enable verbose NTLM packet debugging.\n" +#ifdef NTLM_FAIL_OPEN + " -l if specified, changes behavior on failures to last-ditch\n" +#endif + " -A specify a Windows Local Group name allowed to authenticate\n" + " -D specify a Windows Local Group name not allowed to authenticate\n" + " -h this message\n\n", + my_program_name); +} + + +void +process_options(int argc, char *argv[]) +{ + int opt, had_error = 0; + + opterr =0; +#ifdef NTLM_FAIL_OPEN + while (-1 != (opt = getopt(argc, argv, "hdvlA:D:"))) { +#else + while (-1 != (opt = getopt(argc, argv, "hdvA:D:"))) { +#endif + switch (opt) { + case 'A': + safe_free(NTAllowedGroup); + NTAllowedGroup=xstrdup(optarg); + UseAllowedGroup = 1; + break; + case 'D': + safe_free(NTDisAllowedGroup); + NTDisAllowedGroup=xstrdup(optarg); + UseDisallowedGroup = 1; + break; +#ifdef NTLM_FAIL_OPEN + case 'l': + last_ditch_enabled = 1; + break; +#endif + 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); +} + + +const char * +obtain_challenge(ntlm_negotiate * nego, int nego_length) +{ + const char *ch = NULL; + + debug("attempting SSPI challenge retrieval\n"); + ch = SSP_MakeChallenge(nego, nego_length); + if (ch) { + debug("Got it\n"); + return ch; /* All went OK, returning */ + } + return NULL; +} + + +int +manage_request() +{ + ntlmhdr *fast_header; + char buf[BUFFER_SIZE]; + char helper_command[3]; + char *c, *decoded, *cred; + int plen; + int oversized = 0; + char * ErrorMessage; + +try_again: + if (fgets(buf, BUFFER_SIZE, stdin) == NULL) + return 0; + + c = memchr(buf, '\n', BUFFER_SIZE); /* safer against overrun than strchr */ + if (c) { + if (oversized) { + helperfail("illegal request received"); + fprintf(stderr, "Illegal request received: '%s'\n", buf); + return 1; + } + *c = '\0'; + } else { + fprintf(stderr, "No newline in '%s'\n", buf); + oversized = 1; + goto try_again; + } + if ((strlen(buf) > 3) && NTLM_packet_debug_enabled) { + decoded = base64_decode(buf + 3); + strncpy(helper_command, buf, 2); + 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 (memcmp(buf, "YR", 2) == 0) { /* refresh-request */ + /* figure out what we got */ + if (strlen(buf) > 3) + decoded = base64_decode(buf + 3); + else + decoded = base64_decode(ntlm_make_negotiate()); + /* Note: we don't need to manage memory at this point, since + * base64_decode returns a pointer to static storage. + */ + if (!decoded) { /* decoding failure, return error */ + SEND("NA Packet format error, couldn't base64-decode"); + return 1; + } + /* fast-track-decode request type. */ + fast_header = (struct _ntlmhdr *) decoded; + + /* sanity-check: it IS a NTLMSSP packet, isn't it? */ + if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { + SEND("NA Broken authentication packet"); + return 1; + } + switch (fast_header->type) { + case NTLM_NEGOTIATE: + /* Obtain challenge against SSPI */ + if (strlen(buf) > 3) + plen = (strlen(buf) - 3) * 3 / 4; /* we only need it here. Optimization */ + else + plen = NEGOTIATE_LENGTH; + if ((c = (char *) obtain_challenge((ntlm_negotiate *) decoded, plen)) != NULL ) + { + if (NTLM_packet_debug_enabled) { + printf("TT %s\n",c); + decoded = base64_decode(c); + debug("sending 'TT' to squid with data:\n"); + hex_dump(decoded, (strlen(c) * 3) / 4); + if (NTLM_LocalCall) + debug("NTLM Local Call detected\n"); + } else { + SEND2("TT %s", c); + } + have_challenge = 1; + } else + helperfail("can't obtain challenge"); + return 1; + /* notreached */ + case NTLM_CHALLENGE: + SEND + ("NA Got a challenge. We refuse to have our authority disputed"); + return 1; + /* notreached */ + case NTLM_AUTHENTICATE: + SEND("NA Got authentication request instead of negotiate request"); + return 1; + /* notreached */ + default: + helperfail("unknown refresh-request packet type"); + return 1; + } + return 1; + } + if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */ + if (!have_challenge) { + helperfail("invalid challenge"); + return 1; + } + /* figure out what we got */ + decoded = base64_decode(buf + 3); + /* Note: we don't need to manage memory at this point, since + * base64_decode returns a pointer to static storage. + */ + + if (!decoded) { /* decoding failure, return error */ + SEND("NA Packet format error, couldn't base64-decode"); + return 1; + } + /* fast-track-decode request type. */ + fast_header = (struct _ntlmhdr *) decoded; + + /* sanity-check: it IS a NTLMSSP packet, isn't it? */ + if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { + SEND("NA Broken authentication packet"); + return 1; + } + switch (fast_header->type) { + case NTLM_NEGOTIATE: + SEND("NA Invalid negotiation request received"); + return 1; + /* notreached */ + case NTLM_CHALLENGE: + SEND + ("NA Got a challenge. We refuse to have our authority disputed"); + return 1; + /* notreached */ + case NTLM_AUTHENTICATE: + /* check against SSPI */ + plen = (strlen(buf) - 3) * 3 / 4; /* we only need it here. Optimization */ + cred = ntlm_check_auth((ntlm_authenticate *) decoded, plen); + have_challenge = 0; + if (cred == NULL) { +#ifdef FAIL_DEBUG + fail_debug_enabled =1; +#endif + switch (ntlm_errno) { + case NTLM_BAD_NTGROUP: + SEND("NA Incorrect Group Membership"); + return 1; + case NTLM_BAD_REQUEST: + SEND("NA Incorrect Request Format"); + return 1; + case NTLM_SSPI_ERROR: + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &ErrorMessage, + 0, + NULL); + if (ErrorMessage[strlen(ErrorMessage) - 1] == '\n') + ErrorMessage[strlen(ErrorMessage) - 1] = '\0'; + if (ErrorMessage[strlen(ErrorMessage) - 1] == '\r') + ErrorMessage[strlen(ErrorMessage) - 1] = '\0'; + SEND2("NA %s", ErrorMessage); + LocalFree(ErrorMessage); + return 1; + default: + SEND("NA Unknown Error"); + return 1; + } + } + lc(cred); /* let's lowercase them for our convenience */ + SEND2("AF %s", cred); + return 1; + default: + helperfail("unknown authentication packet type"); + return 1; + } + return 1; + } else { /* not an auth-request */ + helperfail("illegal request received"); + fprintf(stderr, "Illegal request received: '%s'\n", buf); + return 1; + } + helperfail("detected protocol error"); + return 1; +/********* END ********/ +} + +int +main(int argc, char *argv[]) +{ + my_program_name = argv[0]; + + process_options(argc, argv); + + debug("%s build " __DATE__ ", " __TIME__ " starting up...\n", my_program_name); + + if (LoadSecurityDll(SSP_NTLM) == NULL) { + fprintf(stderr, "FATAL, can't initialize SSPI, exiting.\n"); + exit(1); + } + debug("SSPI initialized OK\n"); + + atexit(UnloadSecurityDll); + + /* initialize FDescs */ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + while (manage_request()) { + /* everything is done within manage_request */ + } + exit(0); +} --- /dev/null Wed Feb 14 13:33:00 2007 +++ squid3/helpers/ntlm_auth/mswin_sspi/readme.txt Wed Feb 14 13:35:26 2007 @@ -0,0 +1,70 @@ +mswin_ntlm_auth.exe + +Native Windows NTLM/NTLMv2 authenticator for Squid with +automatic support for NTLM NEGOTIATE packets. + +===== +Usage +===== + +mswin_ntlm_auth [-d] [-v] [-A|D LocalUserGroup] [-h] + +-d enables debugging. +-v enables verbose NTLM packet debugging. +-A specify a Windows Local Group name allowed to authenticate. +-D specify a Windows Local Group name not allowed to authenticate. +-h print program usage + +This is released under the GNU General Public License + +============== +Allowing Users +============== + +Users that are allowed to access the web proxy must have the Windows NT +User Rights "logon from the network". +Optionally the authenticator can verify the NT LOCAL group membership of +the user against the User Group specified in the Authenticator's command +line. +This can be accomplished creating a local user group on the NT machine, +grant the privilege, and adding users to it, it works only with MACHINE +Local Groups, not Domain Local Groups. +Better group checking is available with External Acl, see mswin_check_group +documentation. + +The use of NTLM NEGOTIATE packet allow full NTLM/NTLMv2 support, but +Squid too must be configured to use NTLM NEGOTIATE, see squid.conf. + +Squid.conf typical minimal required changes: + +auth_param ntlm program c:/squid/libexec/mswin_ntlm_auth.exe +auth_param ntlm children 5 +auth_param ntlm max_challenge_reuses 0 +auth_param ntlm max_challenge_lifetime 2 minutes +auth_param ntlm use_ntlm_negotiate on + +acl password proxy_auth REQUIRED + +http_access allow password +http_access deny all + +When using "use_ntlm_negotiate on" +max_challenge_reuses and max_challenge_lifetime parameters must be specified +but they are are ignored. + +Refer to Squid documentation for more details. + +Currently Internet Explorer has some problems with ftp:// URLs when handling +internal Squid FTP icons. The following squid.conf ACL works around this: + +acl internal_icons urlpath_regex -i /squid-internal-static/icons/ + +http_access allow our_networks internal_icons <== BEFORE authentication ACL !!! + + +=============== +Contact details +=============== + +To contact the maintainer of this package, e-mail on squidnt@acmeconsulting.it. +The latest version may be found on http://www.acmeconsulting.it/SquidNT.htm.