* 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.
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,
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 \
--- /dev/null
+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
--- /dev/null
+.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 <guido.serassio@acmeconsulting.it>
+.PP
+Based on prior work in by
+.if !'po4a'hide' .I Francesco Chemolli <kinkie@squid-cache.org>
+.if !'po4a'hide' .I Robert Collins <lifeless@squid-cache.org>
+.PP
+This manual was written by
+.if !'po4a'hide' .I Guido Serassio <guido.serassio@acmeconsulting.it>
+.if !'po4a'hide' .I Amos Jeffries <amosjeffries@squid-cache.org>
+.
+.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' <squid-users@squid-cache.org>
+.
+.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 <squid-bugs@squid-cache.org>
+.PP
+Report ideas for new improvements to the
+.I Squid Developers mailing list
+.if !'po4a'hide' <squid-dev@squid-cache.org>
+.
+.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/
/*
- * 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.
*
*
*/
+/************* 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 <getopt.h>
-#endif
-#include "ntlm.h"
+
+#include <windows.h>
+#include <sspi.h>
+#include <security.h>
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#include <lm.h>
+#include <ntsecapi.h>
#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
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()
{
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)
/* 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.
*/
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;
}
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);
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:
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;
}
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;
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");
+++ /dev/null
-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
+++ /dev/null
-/*
- * (C) 2002,2005 Guido Serassio <guido.serassio@acmeconsulting.it>
- * 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 <ctype.h>
-#endif
-#include <lm.h>
-#include <ntsecapi.h>
-
-/* 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);
- }
- }
-}
-
+++ /dev/null
-/*
- * (C) 2002,2005 Guido Serassio <guido.serassio@acmeconsulting.it>
- * 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 <windows.h>
-#include <sspi.h>
-#include <security.h>
-#include "ntlmauth.h"
-#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
-
-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
-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 !!!