From: Amos Jeffries Date: Mon, 28 Jun 2010 10:51:55 +0000 (+1200) Subject: Upgrade mswin_sspi_auth to ntlm_sspi_auth X-Git-Tag: SQUID_3_2_0_1~111 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bc25525a843b387bd388f61595d0ec6e2d88f2bf;p=thirdparty%2Fsquid.git Upgrade mswin_sspi_auth to ntlm_sspi_auth * Make use of new libntlmauth API for several actions. TODO: C++ upgrade will need to be done in conjunction with someone who can assist testing the build. --- diff --git a/configure.in b/configure.in index 56d9d7fa4c..14daa51aad 100644 --- a/configure.in +++ b/configure.in @@ -1577,6 +1577,7 @@ if test "$enable_auth_ntlm" != "no" ; then done fi AC_MSG_NOTICE([NTLM auth helpers built: $NTLM_AUTH_HELPERS]) +AM_CONDITIONAL(ENABLE_AUTH_NTLM, test "$enable_auth_ntlm" != "no") AC_SUBST(NTLM_AUTH_HELPERS) AC_ARG_ENABLE(auth-negotiate, @@ -3819,7 +3820,7 @@ AC_CONFIG_FILES([\ helpers/ntlm_auth/fake/Makefile \ helpers/ntlm_auth/smb_lm/Makefile \ helpers/ntlm_auth/smb_lm/smbval/Makefile \ - helpers/ntlm_auth/mswin_sspi/Makefile \ + helpers/ntlm_auth/SSPI/Makefile \ helpers/negotiate_auth/Makefile \ helpers/negotiate_auth/kerberos/Makefile \ helpers/negotiate_auth/mswin_sspi/Makefile \ diff --git a/helpers/ntlm_auth/SSPI/Makefile.am b/helpers/ntlm_auth/SSPI/Makefile.am new file mode 100644 index 0000000000..7c6fd08311 --- /dev/null +++ b/helpers/ntlm_auth/SSPI/Makefile.am @@ -0,0 +1,17 @@ +include $(top_srcdir)/src/Common.am + +man_MANS = ntlm_sspi_auth.8 + +libexec_PROGRAMS = ntlm_sspi_auth + +ntlm_sspi_auth_SOURCES = ntlm_sspi_auth.cc + +LDADD = \ + -L$(top_builddir)/libntlmauth -lntlmauth \ + -L$(top_builddir)/lib -lsspwin32 \ + $(COMPAT_LIB) \ + -lnetapi32 \ + -ladvapi32 \ + $(XTRA_LIBS) + +EXTRA_DIST = ntlm_sspi_auth.8 config.test diff --git a/helpers/ntlm_auth/mswin_sspi/config.test b/helpers/ntlm_auth/SSPI/config.test similarity index 100% rename from helpers/ntlm_auth/mswin_sspi/config.test rename to helpers/ntlm_auth/SSPI/config.test diff --git a/helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8 b/helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8 new file mode 100644 index 0000000000..b66efefb6d --- /dev/null +++ b/helpers/ntlm_auth/SSPI/ntlm_sspi_auth.8 @@ -0,0 +1,123 @@ +.if !'po4a'hide' .TH ntlm_sspi_auth.exe 8 +. +.SH NAME +.if !'po4a'hide' .B ntlm_sspi_auth.exe +.if !'po4a'hide' \- +Native Windows NTLM/NTLMv2 authenticator for Squid with +automatic support for NTLM NEGOTIATE packets. +.PP +Version 1.22 +. +.SH SYNOPSIS +.if !'po4a'hide' .B ntlm_sspi_auth.exe +.if !'po4a'hide' .B "[\-dhv] [\-A " +Group Name +.if !'po4a'hide' .B "] [\-D " +Group Name +.if !'po4a'hide' .B "]" +. +.SH DESCRIPTION +.B ntlm_sspi_auth.exe +is an installed binary built on Windows systems. It provides native access to the +Security Service Provider Interface of Windows for authenticating with NTLM / NTLMv2. +It has automatic support for NTLM NEGOTIATE packets. +. +.SH OPTIONS +.if !'po4a'hide' .TP 12 +.if !'po4a'hide' .B \-d +Write debug info to stderr. +.if !'po4a'hide' .B \-h +Display the binary help and command line syntax info using stderr. +.if !'po4a'hide' .B \-v +Enables verbose NTLM packet debugging. +.if !'po4a'hide' .B \-A +Specify a Windows Local Group name allowed to authenticate. +.if !'po4a'hide' .B \-D +Specify a Windows Local Group name which is to be denied authentication. +. +.SH CONFIGURATION +.PP Allowing Users +.PP +Users that are allowed to access the web proxy must have the Windows NT +User Rights "logon from the network". +.PP +Optionally the authenticator can verify the NT LOCAL group membership of +the user against the User Group specified in the Authenticator's command +line. +.PP +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. +.PP +Better group checking is available with External Acl, see mswin_check_group +documentation. +.PP +.B squid.conf +typical minimal required changes: +.if !'po4a'hide' .RS +.if !'po4a'hide' auth_param ntlm program c:/squid/libexec/mswin_ntlm_auth.exe +.if !'po4a'hide' auth_param ntlm children 5 +.if !'po4a'hide' +.if !'po4a'hide' acl password proxy_auth REQUIRED +.if !'po4a'hide' +.if !'po4a'hide' http_access allow password +.if !'po4a'hide' http_access deny all +. +.PP Refer to Squid documentation for more details. +. +.PP +Internet Explorer has some problems with +.B ftp:// +URLs when handling internal Squid FTP icons. +The following +.B squid.conf +ACL works around this when placed before the authentication ACL: +.if !'po4a'hide' .RS +.if !'po4a'hide' acl internal_icons urlpath_regex -i /squid-internal-static/icons/ +.if !'po4a'hide' +.if !'po4a'hide' http_access allow our_networks internal_icons +. +.SH AUTHOR +This program was written by +.if !'po4a'hide' .I Guido Serassio +.PP +Based on prior work in by +.if !'po4a'hide' .I Francesco Chemolli +.if !'po4a'hide' .I Robert Collins +.PP +This manual was written by +.if !'po4a'hide' .I Guido Serassio +.if !'po4a'hide' .I Amos Jeffries +. +.SH COPYRIGHT +This program and documentation is copyright to the authors named above. +.PP +Distributed under the GNU General Public License (GNU GPL) version 2 or later (GPLv2+). +. +.SH QUESTIONS +Questions on the usage of this program can be sent to the +.I Squid Users mailing list +.if !'po4a'hide' +. +.SH REPORTING BUGS +Bug reports need to be made in English. +See http://wiki.squid-cache.org/SquidFaq/BugReporting for details of what you need to include with your bug report. +.PP +Report bugs or bug fixes using http://bugs.squid-cache.org/ +.PP +Report serious security bugs to +.I Squid Bugs +.PP +Report ideas for new improvements to the +.I Squid Developers mailing list +.if !'po4a'hide' +. +.SH SEE ALSO +.if !'po4a'hide' .BR squid "(8), " +.if !'po4a'hide' .BR GPL "(7), " +.br +The Squid FAQ wiki +.if !'po4a'hide' http://wiki.squid-cache.org/SquidFaq +.br +The Squid Configuration Manual +.if !'po4a'hide' http://www.squid-cache.org/Doc/config/ diff --git a/helpers/ntlm_auth/mswin_sspi/ntlm_auth.c b/helpers/ntlm_auth/SSPI/ntlm_sspi_auth.cc similarity index 53% rename from helpers/ntlm_auth/mswin_sspi/ntlm_auth.c rename to helpers/ntlm_auth/SSPI/ntlm_sspi_auth.cc index 31e76eaa0d..d047e617bc 100644 --- a/helpers/ntlm_auth/mswin_sspi/ntlm_auth.c +++ b/helpers/ntlm_auth/SSPI/ntlm_sspi_auth.cc @@ -1,5 +1,5 @@ /* - * mswin_ntlm_auth: helper for NTLM Authentication for Squid Cache + * ntlm_sspi_auth: helper for NTLM Authentication for Squid Cache * * (C)2002,2005 Guido Serassio - Acme Consulting S.r.l. * @@ -55,50 +55,286 @@ * */ +/************* CONFIGURATION ***************/ + +#define FAIL_DEBUG 0 + +/************* END CONFIGURATION ***************/ + +typedef unsigned char uchar; + +#include "config.h" +#include "helpers/defines.h" +#include "libntlmauth/ntlmauth.h" +#include "libntlmauth/support_bits.h" +#include "sspwin32.h" #include "util.h" -#if HAVE_GETOPT_H -#include -#endif -#include "ntlm.h" + +#include +#include +#include #if HAVE_CTYPE_H #include #endif +#if HAVE_GETOPT_H +#include +#endif +#include +#include #define BUFFER_SIZE 10240 -int debug_enabled = 0; int NTLM_packet_debug_enabled = 0; - static int have_challenge; - char * NTAllowedGroup; char * NTDisAllowedGroup; int UseDisallowedGroup = 0; int UseAllowedGroup = 0; + #if FAIL_DEBUG int fail_debug_enabled = 0; #endif -/* makes a null-terminated string upper-case. Changes CONTENTS! */ -void -uc(char *string) +/* returns 1 on success, 0 on failure */ +int +Valid_Group(char *UserName, char *Group) { - char *p = string, c; - while ((c = *p)) { - *p = xtoupper(c); - p++; - } + 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; } -/* makes a null-terminated string lower-case. Changes CONTENTS! */ -static void -lc(char *string) + +char * GetDomainName(void) + { - char *p = string, c; - while ((c = *p)) { - *p = xtolower(c); - p++; + 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; +} + +/* 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 libntlmauth/ntlmauth.h + */ +int +ntlm_check_auth(ntlm_authenticate * auth, char *user, char *domain, int auth_length) +{ + int x; + int rv; + char credentials[DNLEN+UNLEN+2]; /* we can afford to waste */ + lstring tmp; + + if (!NTLM_LocalCall) { + + user[0] = '\0'; + domain[0] = '\0'; + x = ntlm_unpack_auth(auth, user, domain, auth_length); + + if (x != NTLM_ERR_NONE) + return x; + + if (domain[0] == '\0') { + debug("No domain supplied. Returning no-auth\n"); + return NTLM_BAD_REQUEST; + } + if (user[0] == '\0') { + debug("No username supplied. Returning no-auth\n"); + return NTLM_BAD_REQUEST; + } + debug("checking domain: '%s', user: '%s'\n", domain, user); + + } else + debug("checking local user\n"); + + snprintf(credentials, DNLEN+UNLEN+2, "%s\\%s", domain, user); + + rv = SSP_ValidateNTLMCredentials(auth, auth_length, credentials); + + debug("Login attempt had result %d\n", rv); + + if (!rv) { /* failed */ + return NTLM_SSPI_ERROR; + } + + if (UseAllowedGroup) { + if (!Valid_Group(credentials, NTAllowedGroup)) { + debug("User %s not in allowed Group %s\n", credentials, NTAllowedGroup); + return NTLM_BAD_NTGROUP; + } } + if (UseDisallowedGroup) { + if (Valid_Group(credentials, NTDisAllowedGroup)) { + debug("User %s is in denied Group %s\n", credentials, NTDisAllowedGroup); + return NTLM_BAD_NTGROUP; + } + } + + debug("credentials: %s\n", credentials); + return NTLM_ERR_NONE; } void @@ -174,22 +410,6 @@ process_options(int argc, char *argv[]) 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() { @@ -200,6 +420,21 @@ manage_request() int plen; int oversized = 0; char * ErrorMessage; + static ntlm_negotiate local_nego; + char domain[DNLEN+1]; + char user[UNLEN+1]; + + /* NP: for some reason this helper sometimes needs to accept + * from clients that send no negotiate packet. */ + if (memcpy(local_nego.signature, "NTLMSSP", 8) != 0) { + memset(&local_nego, 0, sizeof(ntlm_negotiate)); /* reset */ + memcpy(local_nego.signature, "NTLMSSP", 8); /* set the signature */ + local_nego.type = le32toh(NTLM_NEGOTIATE); /* this is a challenge */ + local_nego.flags = le32toh(NTLM_NEGOTIATE_ALWAYS_SIGN | + NTLM_NEGOTIATE_USE_NTLM | + NTLM_NEGOTIATE_USE_LM | + NTLM_NEGOTIATE_ASCII ); + } try_again: if (fgets(buf, BUFFER_SIZE, stdin) == NULL) @@ -229,8 +464,10 @@ try_again: /* figure out what we got */ if (strlen(buf) > 3) decoded = base64_decode(buf + 3); - else - decoded = base64_decode(ntlm_make_negotiate()); + else { + debug("Negotiate packet not supplied - self generated\n"); + decoded = (char *) &local_nego; + } /* Note: we don't need to manage memory at this point, since * base64_decode returns a pointer to static storage. */ @@ -242,7 +479,7 @@ try_again: fast_header = (struct _ntlmhdr *) decoded; /* sanity-check: it IS a NTLMSSP packet, isn't it? */ - if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { + if (ntlm_validate_packet(fast_header, NTLM_ANY) != NTLM_ERR_NONE) { SEND("NA Broken authentication packet"); return 1; } @@ -252,8 +489,9 @@ try_again: 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 ) { + plen = sizeof(ntlmhdr) + sizeof u_int32_t); /* local_nego only has header and flags set. */ + debug("attempting SSPI challenge retrieval\n"); + if ((c = (char *) SSP_MakeChallenge((ntlm_negotiate *) decoded, plen)) != NULL ) { if (NTLM_packet_debug_enabled) { printf("TT %s\n",c); decoded = base64_decode(c); @@ -270,8 +508,7 @@ try_again: return 1; /* notreached */ case NTLM_CHALLENGE: - SEND - ("NA Got a challenge. We refuse to have our authority disputed"); + SEND("NA Got a challenge. We refuse to have our authority disputed"); return 1; /* notreached */ case NTLM_AUTHENTICATE: @@ -303,7 +540,7 @@ try_again: fast_header = (struct _ntlmhdr *) decoded; /* sanity-check: it IS a NTLMSSP packet, isn't it? */ - if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { + if (ntlm_validate_packet(fast_header, NTLM_ANY) != NTLM_ERR_NONE) { SEND("NA Broken authentication packet"); return 1; } @@ -320,13 +557,15 @@ try_again: 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); + err = ntlm_check_auth((ntlm_authenticate *) decoded, user, domain, plen); have_challenge = 0; - if (cred == NULL) { + if (err != NTLM_ERR_NONE) { #if FAIL_DEBUG fail_debug_enabled =1; #endif switch (ntlm_errno) { + case NTLM_ERR_NONE: + break; case NTLM_BAD_NTGROUP: SEND("NA Incorrect Group Membership"); return 1; @@ -356,8 +595,8 @@ try_again: return 1; } } - lc(cred); /* let's lowercase them for our convenience */ - SEND2("AF %s", cred); + /* let's lowercase them for our convenience */ + SEND3("AF %s\\%s", lc(domain), lc(user)); return 1; default: helperfail("unknown authentication packet type"); diff --git a/helpers/ntlm_auth/mswin_sspi/Makefile.am b/helpers/ntlm_auth/mswin_sspi/Makefile.am deleted file mode 100644 index 86c0adfe15..0000000000 --- a/helpers/ntlm_auth/mswin_sspi/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -include $(top_srcdir)/src/Common.am - -libexec_PROGRAMS = mswin_ntlm_auth - -mswin_ntlm_auth_SOURCES = libntlmssp.c ntlm_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 -lntlmauth \ - -lsspwin32 \ - -lnetapi32 \ - -ladvapi32 \ - $(XTRA_LIBS) - -EXTRA_DIST = readme.txt config.test diff --git a/helpers/ntlm_auth/mswin_sspi/libntlmssp.c b/helpers/ntlm_auth/mswin_sspi/libntlmssp.c deleted file mode 100644 index 1d3fded4f3..0000000000 --- a/helpers/ntlm_auth/mswin_sspi/libntlmssp.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * (C) 2002,2005 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_ValidateNTLMCredentials(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 (!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 (xisalnum(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); - } - } -} - diff --git a/helpers/ntlm_auth/mswin_sspi/ntlm.h b/helpers/ntlm_auth/mswin_sspi/ntlm.h deleted file mode 100644 index 6433ab4793..0000000000 --- a/helpers/ntlm_auth/mswin_sspi/ntlm.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * (C) 2002,2005 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; -#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 - -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_ */ diff --git a/helpers/ntlm_auth/mswin_sspi/readme.txt b/helpers/ntlm_auth/mswin_sspi/readme.txt deleted file mode 100644 index 326733318e..0000000000 --- a/helpers/ntlm_auth/mswin_sspi/readme.txt +++ /dev/null @@ -1,52 +0,0 @@ -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. - -Squid.conf typical minimal required changes: - -auth_param ntlm program c:/squid/libexec/mswin_ntlm_auth.exe -auth_param ntlm children 5 - -acl password proxy_auth REQUIRED - -http_access allow password -http_access deny all - -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 !!!