---------------------
PatchSet 2072 
Date: 2005/10/31 15:20:39
Author: serassio
Branch: nt
Tag: (none) 
Log:
Renamed win32_check_group external helper to mswin_check_lm_group

Members: 
	configure.in:1.26.2.68->1.26.2.69 
	helpers/external_acl/Makefile.am:1.3.16.2->1.3.16.3 
	helpers/external_acl/mswin_lm_group/.cvsignore:1.1->1.1.2.1 
	helpers/external_acl/mswin_lm_group/Makefile.am:1.1->1.1.2.1 
	helpers/external_acl/mswin_lm_group/readme.txt:1.1->1.1.2.1 
	helpers/external_acl/mswin_lm_group/win32_check_group.c:1.1->1.1.2.1 
	helpers/external_acl/mswin_lm_group/win32_check_group.h:1.1->1.1.2.1 
	helpers/external_acl/win32_group/.cvsignore:1.1.2.1->1.1.2.2(DEAD) 
	helpers/external_acl/win32_group/Makefile.am:1.2.18.4->1.2.18.5(DEAD) 
	helpers/external_acl/win32_group/readme.txt:1.2.18.6->1.2.18.7(DEAD) 
	helpers/external_acl/win32_group/win32_check_group.c:1.2.18.11->1.2.18.12(DEAD) 
	helpers/external_acl/win32_group/win32_check_group.h:1.2.18.3->1.2.18.4(DEAD) 

Index: squid3/configure.in
===================================================================
RCS file: /cvsroot/squid-sf//squid3/configure.in,v
retrieving revision 1.26.2.68
retrieving revision 1.26.2.69
diff -u -r1.26.2.68 -r1.26.2.69
--- squid3/configure.in	30 Oct 2005 19:37:34 -0000	1.26.2.68
+++ squid3/configure.in	31 Oct 2005 15:20:57 -0000	1.26.2.69
@@ -3,7 +3,7 @@
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.26.2.68 2005/10/30 19:37:34 serassio Exp $
+dnl  $Id: configure.in,v 1.26.2.69 2005/10/31 15:20:57 serassio Exp $
 dnl
 dnl
 dnl
@@ -13,7 +13,7 @@
 AC_CONFIG_AUX_DIR(cfgaux)
 AM_INIT_AUTOMAKE(squid, 3.0-PRE3-NT-CVS)
 AM_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.26.2.68 $)dnl
+AC_REVISION($Revision: 1.26.2.69 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AM_MAINTAINER_MODE
 
@@ -3017,7 +3017,7 @@
 	helpers/external_acl/ldap_group/Makefile \
 	helpers/external_acl/unix_group/Makefile \
 	helpers/external_acl/wbinfo_group/Makefile \
-	helpers/external_acl/win32_group/Makefile \
+	helpers/external_acl/mswin_lm_group/Makefile \
 	port/Makefile \
 	port/win32/Makefile \
 ])
Index: squid3/helpers/external_acl/Makefile.am
===================================================================
RCS file: /cvsroot/squid-sf//squid3/helpers/external_acl/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/external_acl/Makefile.am	2 Jul 2005 10:16:22 -0000	1.3.16.2
+++ squid3/helpers/external_acl/Makefile.am	31 Oct 2005 15:20:39 -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/31 15:20:39 serassio Exp $
 #
 
-DIST_SUBDIRS	= ip_user ldap_group unix_group wbinfo_group win32_group
+DIST_SUBDIRS	= ip_user ldap_group unix_group wbinfo_group mswin_lm_group
 SUBDIRS		= @EXTERNAL_ACL_HELPERS@
--- /dev/null	Wed Feb 14 13:33:00 2007
+++ squid3/helpers/external_acl/mswin_lm_group/.cvsignore	Wed Feb 14 13:35:28 2007
@@ -0,0 +1,4 @@
+.cvsignore
+Makefile.in
+Makefile
+.deps
--- /dev/null	Wed Feb 14 13:33:00 2007
+++ squid3/helpers/external_acl/mswin_lm_group/Makefile.am	Wed Feb 14 13:35:28 2007
@@ -0,0 +1,19 @@
+#
+#  Makefile for the Squid Object Cache server
+#
+#  $Id: Makefile.am,v 1.1.2.1 2005/10/31 15:20:39 serassio Exp $
+#
+#  Uncomment and customize the following to suit your needs:
+#
+
+
+libexec_PROGRAMS = mswin_check_lm_group
+
+mswin_check_lm_group_SOURCES = win32_check_group.c win32_check_group.h
+
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src
+
+LDADD   = -L$(top_builddir)/lib -lmiscutil -lnetapi32 -ladvapi32 \
+          -lntdll $(XTRA_LIBS)
+
+EXTRA_DIST = readme.txt
--- /dev/null	Wed Feb 14 13:33:00 2007
+++ squid3/helpers/external_acl/mswin_lm_group/readme.txt	Wed Feb 14 13:35:28 2007
@@ -0,0 +1,86 @@
+
+This is the readme.txt file for mswin_check_lm_group, an external
+helper fo the External ACL Scheme for Squid.
+
+
+This helper must be used in with an authentication scheme, tipically 
+basic or NTLM, based on Windows NT/2000 domain users. 
+It reads from the standard input the domain username and a list of groups
+and tries to match it against the groups membership of the specified
+username.
+
+
+==============
+Program Syntax
+==============
+
+mswin_check_lm_group [-D domain][-G][-P][-c][-d][-h]
+
+-D domain specify the default user's domain
+-G        start helper in Domain Global Group mode
+-P        use ONLY PDCs for group validation
+-c        use case insensitive compare
+-d        enable debugging
+-h        this message
+
+
+================
+squid.conf usage
+================
+
+external_acl_type NT_global_group %LOGIN c:/squid/libexec/mswin_check_lm_group.exe -G
+external_acl_type NT_local_group %LOGIN c:/squid/libexec/mswin_check_lm_group.exe
+
+acl GProxyUsers external NT_global_group GProxyUsers
+acl LProxyUsers external NT_local_group LProxyUsers
+acl password proxy_auth REQUIRED
+
+http_access allow password GProxyUsers
+http_access allow password LProxyUsers
+http_access deny all
+
+In the previous example all validated NT users member of GProxyUsers Global 
+domain group or member of LProxyUsers machine local group are allowed to 
+use the cache.
+
+Groups with spaces in name, for example "Domain Users", must be quoted and
+the acl data ("Domain Users") must be placed into a separate file included
+by specifying "/path/to/file". The previous example will be:
+
+acl ProxyUsers external NT_global_group "c:/squid/etc/DomainUsers"
+
+and the DomainUsers files will contain only the following line:
+
+"Domain Users"
+
+NOTES: 
+- The standard group name comparation is case sensitive, so group name
+  must be specified with same case as in the NT/2000 Domain.
+  It's possible to enable not case sensitive group name comparation (-c),
+  but on on some non - English locales, the results can be unexpected.
+- Native WIN32 NTLM and Basic Helpers must be used without the
+  -A & -D switches.
+
+Refer to Squid documentation for the more details on squid.conf.
+
+
+=======
+Testing
+=======
+
+I strongly reccomend that mswin_check_lm_group is tested prior to being used in a 
+production environment. It may behave differently on different platforms.
+To test it, run it from the command line. Enter username and group
+pairs separated by a space (username must entered with domain\\username
+syntax). Press ENTER to get an OK or ERR message.
+Make sure pressing <CTRL><D> behaves the same as a carriage return.
+Make sure pressing <CTRL><C> aborts the program.
+
+Test that entering no details does not result in an OK or ERR message.
+Test that entering an invalid username and group results in an ERR message.
+Test that entering an valid username and group results in an OK message.
+
+--
+Serassio Guido
+squidnt at acmeconsulting dot it
+
--- /dev/null	Wed Feb 14 13:33:00 2007
+++ squid3/helpers/external_acl/mswin_lm_group/win32_check_group.c	Wed Feb 14 13:35:28 2007
@@ -0,0 +1,606 @@
+/*
+ * win32_group: lookup group membership in a Windows NT/2000 domain
+ *
+ * (C)2002,2005 Guido Serassio - Acme Consulting S.r.l.
+ *
+ * Authors:
+ *  Guido Serassio <guido.serassio@acmeconsulting.it>
+ *  Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it>
+ *
+ * With contributions from others mentioned in the change history section
+ * below.
+ *
+ * In part based on check_group by Rodrigo Albani de Campos.
+ *
+ * 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.22
+ * 08-07-2005 Guido Serassio
+ *              Added -P option for force usage of PDCs for group validation.
+ *              Added support for '/' char as domain separator.
+ *              Fixed Bugzilla #1336. 
+ * Version 1.21
+ * 23-04-2005 Guido Serassio
+ *              Added -D option for specify default user's domain.
+ * Version 1.20.1
+ * 15-08-2004 Guido Serassio
+ *              Helper protocol changed to use URL escaped strings in Squid-3.0
+ *              (Original work of Henrik Nordstrom)
+ * Version 1.20
+ * 13-06-2004 Guido Serassio
+ *              Added support for running on a Domain Controller.
+ * Version 1.10
+ * 01-05-2003 Guido Serassio
+ *              Added option for case insensitive group name comparation.
+ *              More debug info.
+ *              Updated documentation.
+ *              Segfault bug fix (Bugzilla #574)
+ * Version 1.0
+ * 24-06-2002 Guido Serassio
+ *              Using the main function from check_group and sections
+ *              from wbinfo wrote win32_group
+ *
+ * This is a helper for the external ACL interface for Squid Cache
+ * 
+ * It reads from the standard input the domain username and a list of
+ * groups and tries to match it against the groups membership of the
+ * specified username.
+ *
+ * Returns `OK' if the user belongs to a group or `ERR' otherwise, as
+ * described on http://devel.squid-cache.org/external_acl/config.html
+ *
+ */
+
+#include "config.h"
+#ifdef _SQUID_CYGWIN_
+#include <wchar.h>
+int _wcsicmp(const wchar_t*, const wchar_t*);
+#endif
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+#undef assert
+#include <assert.h>
+#include <windows.h>
+#include <lm.h>
+#include <ntsecapi.h>
+
+#include "util.h"
+
+#define BUFSIZE 8192		/* the stdin buffer size */
+int use_global = 0;
+int use_PDC_only = 0;
+char debug_enabled = 0;
+char *myname;
+pid_t mypid;
+char * machinedomain;
+int use_case_insensitive_compare = 0;
+char * DefaultDomain = NULL;
+const char NTV_VALID_DOMAIN_SEPARATOR[] = "\\/";
+
+#include "win32_check_group.h"
+
+
+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,
+		(PVOID *)&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 0 on match, -1 if no match */
+static int wcstrcmparray(const wchar_t *str, const char **array)
+{
+    WCHAR wszGroup[GNLEN+1];	// Unicode Group
+
+    while (*array) {
+	MultiByteToWideChar(CP_ACP, 0, *array,
+	    strlen(*array) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0]));
+    	debug("Windows group: %S, Squid group: %S\n", str, wszGroup);
+	if ((use_case_insensitive_compare ? _wcsicmp(str, wszGroup) : wcscmp(str, wszGroup)) == 0)
+	    return 0;
+	array++;
+    }
+    return -1;
+}
+
+/* returns 1 on success, 0 on failure */
+int
+Valid_Local_Groups(char *UserName, const char **Groups)
+{
+    int result = 0;
+    char * Domain_Separator;
+    WCHAR wszUserName[UNLEN+1];	// Unicode user name
+
+    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;
+
+    if ((Domain_Separator = strchr(UserName, '/')) != NULL)
+        *Domain_Separator = '\\';
+    
+    debug("Valid_Local_Groups: checking group membership of '%s'.\n", UserName);
+    
+/* Convert ANSI User Name and Group to Unicode */
+
+    MultiByteToWideChar(CP_ACP, 0, UserName,
+	strlen(UserName) + 1, wszUserName, sizeof(wszUserName) / sizeof(wszUserName[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++) {
+		assert(pTmpBuf != NULL);
+		if (pTmpBuf == NULL) {
+		    result = 0;
+		    break;
+		}
+		if (wcstrcmparray(pTmpBuf->lgrui0_name, Groups) == 0) {
+		    result = 1;
+		    break;
+		}
+		pTmpBuf++;
+		dwTotalCount++;
+	    }
+	}
+    } else
+        result = 0;
+/*
+ * Free the allocated memory.
+ */
+    if (pBuf != NULL)
+	NetApiBufferFree(pBuf);
+    return result;
+}
+
+
+/* returns 1 on success, 0 on failure */
+int
+Valid_Global_Groups(char *UserName, const char **Groups)
+{
+    int result = 0;
+    WCHAR wszUserName[UNLEN+1];     // Unicode user name
+    WCHAR wszLocalDomain[DNLEN+1];  // Unicode Local Domain
+    WCHAR wszUserDomain[DNLEN+1];   // Unicode User Domain
+
+    char NTDomain[DNLEN+UNLEN+2];
+    char *domain_qualify;
+    char User[UNLEN+1];
+    size_t j;
+
+    LPWSTR LclDCptr = NULL;
+    LPWSTR UsrDCptr = NULL;
+    LPGROUP_USERS_INFO_0 pUsrBuf = NULL;
+    LPGROUP_USERS_INFO_0 pTmpBuf;
+    LPSERVER_INFO_101 pSrvBuf = NULL;
+    DWORD dwLevel = 0;
+    DWORD dwPrefMaxLen = -1;
+    DWORD dwEntriesRead = 0;
+    DWORD dwTotalEntries = 0;
+    NET_API_STATUS nStatus;
+    DWORD i;
+    DWORD dwTotalCount = 0;
+
+    strncpy(NTDomain, UserName, sizeof(NTDomain));
+
+    for (j=0; j < strlen(NTV_VALID_DOMAIN_SEPARATOR); j++) {
+        if ((domain_qualify = strchr(NTDomain, NTV_VALID_DOMAIN_SEPARATOR[j])) != NULL)
+            break;
+    }
+    if (domain_qualify == NULL) {
+	strcpy(User, NTDomain);
+	strcpy(NTDomain, DefaultDomain);
+    } else {
+	strcpy(User, domain_qualify + 1);
+	domain_qualify[0] = '\0';
+	strlwr(NTDomain);
+    }
+
+    debug("Valid_Global_Groups: checking group membership of '%s\\%s'.\n", NTDomain, User);
+
+    /* Convert ANSI User Name and Group to Unicode */
+
+    MultiByteToWideChar(CP_ACP, 0, User,
+	strlen(User) + 1, wszUserName,
+	sizeof(wszUserName) / sizeof(wszUserName[0]));
+    MultiByteToWideChar(CP_ACP, 0, machinedomain,
+	strlen(machinedomain) + 1, wszLocalDomain, sizeof(wszLocalDomain) / sizeof(wszLocalDomain[0]));
+
+
+/* Call the NetServerGetInfo function for local computer, specifying level 101. */
+    dwLevel = 101;
+    nStatus = NetServerGetInfo(NULL, dwLevel, (LPBYTE *)&pSrvBuf);
+    
+    if (nStatus == NERR_Success)
+    {
+        /* Check if we are running on a Domain Controller */
+        if ((pSrvBuf->sv101_type & SV_TYPE_DOMAIN_CTRL) ||
+            (pSrvBuf->sv101_type & SV_TYPE_DOMAIN_BAKCTRL))
+        {
+            LclDCptr = NULL;
+            debug("Running on a DC.\n");
+        }
+        else
+            nStatus = (use_PDC_only ? NetGetDCName(NULL, wszLocalDomain, (LPBYTE *) & LclDCptr) : NetGetAnyDCName(NULL, wszLocalDomain, (LPBYTE *) & LclDCptr));
+    } else {
+	fprintf(stderr, "%s NetServerGetInfo() failed.'\n", myname);
+        if (pSrvBuf != NULL)
+            NetApiBufferFree(pSrvBuf);
+        return result;
+    }
+
+    if (nStatus == NERR_Success) {
+        debug("Using '%S' as DC for '%S' local domain.\n", LclDCptr, wszLocalDomain);
+	
+        if (strcmp(NTDomain, machinedomain) != 0) {
+	    MultiByteToWideChar(CP_ACP, 0, NTDomain,
+		strlen(NTDomain) + 1, wszUserDomain, sizeof(wszUserDomain) / sizeof(wszUserDomain[0]));
+            nStatus = (use_PDC_only ? NetGetDCName(LclDCptr, wszUserDomain, (LPBYTE *) & UsrDCptr) : NetGetAnyDCName(LclDCptr, wszUserDomain, (LPBYTE *) & UsrDCptr));
+	        if (nStatus != NERR_Success) {
+		    fprintf(stderr, "%s Can't find DC for user's domain '%s'\n", myname, NTDomain);
+                    if (pSrvBuf != NULL)
+                        NetApiBufferFree(pSrvBuf);
+		    if (LclDCptr != NULL)
+		        NetApiBufferFree((LPVOID) LclDCptr);
+		    if (UsrDCptr != NULL)
+		        NetApiBufferFree((LPVOID) UsrDCptr);
+		    return result;
+	        }
+	} else
+	    UsrDCptr = LclDCptr;
+
+        debug("Using '%S' as DC for '%s' user's domain.\n", UsrDCptr, NTDomain);
+	/*
+	 * Call the NetUserGetGroups function 
+	     * specifying information level 0.
+	     */
+            dwLevel = 0;
+	    nStatus = NetUserGetGroups(UsrDCptr,
+		wszUserName,
+		dwLevel,
+		(LPBYTE *) & pUsrBuf,
+		dwPrefMaxLen,
+		&dwEntriesRead,
+		&dwTotalEntries);
+	    /*
+	     * If the call succeeds,
+	     */
+	if (nStatus == NERR_Success) {
+	    if ((pTmpBuf = pUsrBuf) != NULL) {
+		for (i = 0; i < dwEntriesRead; i++) {
+		    assert(pTmpBuf != NULL);
+		    if (pTmpBuf == NULL) {
+			result = 0;
+			break;
+		    }
+		    if (wcstrcmparray(pTmpBuf->grui0_name, Groups) == 0) {
+			result = 1;
+			break;
+		    }
+		    pTmpBuf++;
+		    dwTotalCount++;
+		}
+	    }
+        } else {
+	    result = 0;
+            fprintf(stderr, "%s NetUserGetGroups() failed.'\n", myname);
+        }
+    } else {
+	fprintf(stderr, "%s Can't find DC for local domain '%s'\n", myname, machinedomain);
+    }
+    /*
+     * Free the allocated memory.
+     */
+    if (pSrvBuf != NULL)
+        NetApiBufferFree(pSrvBuf);
+    if (pUsrBuf != NULL)
+        NetApiBufferFree(pUsrBuf);
+    if ((UsrDCptr != NULL) && (UsrDCptr != LclDCptr))
+        NetApiBufferFree((LPVOID) UsrDCptr);
+    if (LclDCptr != NULL)
+        NetApiBufferFree((LPVOID) LclDCptr);
+    return result;
+}
+
+static void
+usage(char *program)
+{
+    fprintf(stderr,"Usage: %s [-D domain][-G][-P][-c][-d][-h]\n"
+	    	" -D    default user Domain\n"
+	    	" -G    enable Domain Global group mode\n"
+	    	" -P    use ONLY PDCs for group validation\n"
+	    	" -c    use case insensitive compare\n"
+	    	" -d    enable debugging\n"
+		" -h    this message\n",
+		program);
+}
+
+void
+process_options(int argc, char *argv[])
+{
+    int opt;
+
+    opterr = 0;
+    while (-1 != (opt = getopt(argc, argv, "D:GPcdh"))) {
+	switch (opt) {
+	case 'D':
+	    DefaultDomain = xstrndup(optarg, DNLEN + 1);
+            strlwr(DefaultDomain);
+	    break;
+	case 'G':
+	    use_global = 1;
+	    break;
+	case 'P':
+	    use_PDC_only = 1;
+	    break;
+	case 'c':
+	    use_case_insensitive_compare = 1;
+	    break;
+	case 'd':
+	    debug_enabled = 1;
+	    break;
+	case 'h':
+	    usage(argv[0]);
+	    exit(0);
+	case '?':
+	    opt = optopt;
+	    /* fall thru to default */
+	default:
+	    fprintf(stderr, "%s Unknown option: -%c. Exiting\n", myname, opt);
+	    usage(argv[0]);
+	    exit(1);
+	    break;		/* not reached */
+	}
+    }
+    return;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+    char *p;
+    char buf[BUFSIZE];
+    char *username;
+    char *group;
+    int err = 0;
+    const char *groups[512];
+    int n;
+
+    if (argc > 0) {	/* should always be true */
+	myname=strrchr(argv[0],'/');
+	if (myname==NULL)
+	    myname=argv[0];
+    } else {
+        myname="(unknown)";
+    }
+    mypid=getpid();
+
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+
+    /* Check Command Line */
+    process_options(argc, argv);
+
+    if (use_global) {
+        if ((machinedomain = GetDomainName()) == NULL) {
+	    fprintf(stderr, "%s Can't read machine domain\n", myname);
+	    exit(1);
+	}
+	strlwr(machinedomain);
+        if (!DefaultDomain)
+            DefaultDomain = xstrdup(machinedomain);
+    }
+
+    debug("External ACL win32 group helper build " __DATE__ ", " __TIME__
+    " starting up...\n");
+    if (use_global)
+        debug("Domain Global group mode enabled using '%s' as default domain.\n", DefaultDomain);
+    if (use_case_insensitive_compare)
+        debug("Warning: running in case insensitive mode !!!\n");
+    if (use_PDC_only)
+        debug("Warning: using only PDCs for group validation !!!\n");
+
+    /* Main Loop */
+    while (fgets (buf, sizeof(buf), stdin))
+    {
+	if (NULL == strchr(buf, '\n')) {
+	    /* too large message received.. skip and deny */
+	    fprintf(stderr, "%s: ERROR: Too large: %s\n", argv[0], buf);
+	    while (fgets(buf, sizeof(buf), stdin)) {
+		fprintf(stderr, "%s: ERROR: Too large..: %s\n", argv[0], buf);
+		if (strchr(buf, '\n') != NULL)
+		    break;
+	    }
+	    goto error;
+	}
+	
+	if ((p = strchr(buf, '\n')) != NULL)
+	    *p = '\0';		/* strip \n */
+	if ((p = strchr(buf, '\r')) != NULL)
+	    *p = '\0';		/* strip \r */
+
+	debug("Got '%s' from Squid (length: %d).\n",buf,strlen(buf));
+
+	if (buf[0] == '\0') {
+	    fprintf(stderr, "Invalid Request\n");
+	    goto error;
+	}
+
+	username = strtok(buf, " ");
+	for (n = 0; (group = strtok(NULL, " ")) != NULL; n++) {
+	    rfc1738_unescape(group);
+	    groups[n] = group;
+	}
+	groups[n] = NULL;
+
+        if (NULL == username) {
+            fprintf(stderr, "Invalid Request\n");
+            goto error;
+        }
+	rfc1738_unescape(username);
+
+	if ((use_global ? Valid_Global_Groups(username, groups) : Valid_Local_Groups(username, groups))) {
+	    printf ("OK\n");
+	} else {
+error:
+	    printf ("ERR\n");
+	}
+	err = 0;
+    }
+    return 0;
+}
--- /dev/null	Wed Feb 14 13:33:00 2007
+++ squid3/helpers/external_acl/mswin_lm_group/win32_check_group.h	Wed Feb 14 13:35:28 2007
@@ -0,0 +1,79 @@
+/*
+ * (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.
+ */
+
+#undef debug
+
+/************* CONFIGURATION ***************/
+/*
+ * define this if you want debugging
+ */
+#ifndef DEBUG
+#define DEBUG
+#endif
+
+/************* END CONFIGURATION ***************/
+
+#include <sys/types.h>
+
+#define safe_free(x)	if (x) { free(x); x = NULL; }
+
+/* Debugging stuff */
+
+#ifdef __GNUC__			/* this is really a gcc-ism */
+#ifdef DEBUG
+#include <stdio.h>
+#include <unistd.h>
+static char *__foo;
+extern char debug_enabled;
+#define debug(X...) if (debug_enabled) { \
+                    fprintf(stderr,"%s[%d](%s:%d): ", myname, mypid, \
+                    ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\
+                    __LINE__);\
+                    fprintf(stderr,X); }
+#else /* DEBUG */
+#define debug(X...)		/* */
+#endif /* DEBUG */
+#else /* __GNUC__ */
+extern char debug_enabled;
+static void
+debug(char *format,...) 
+{
+#ifdef DEBUG
+#ifdef _SQUID_MSWIN_
+    if (debug_enabled) {
+	va_list args;
+
+	va_start(args,format);
+	fprintf(stderr, "%s[%d]: ", myname, mypid);
+	vfprintf(stderr, format, args);
+	fprintf(stderr, "\n");
+	va_end(args);
+    }
+#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
--- squid3/helpers/external_acl/win32_group/.cvsignore	Wed Feb 14 13:35:28 2007
+++ /dev/null	Wed Feb 14 13:33:00 2007
@@ -1,4 +0,0 @@
-.cvsignore
-Makefile.in
-Makefile
-.deps
--- squid3/helpers/external_acl/win32_group/Makefile.am	Wed Feb 14 13:35:28 2007
+++ /dev/null	Wed Feb 14 13:33:00 2007
@@ -1,19 +0,0 @@
-#
-#  Makefile for the Squid Object Cache server
-#
-#  $Id: Makefile.am,v 1.2.18.4 2005/09/15 09:43:53 serassio Exp $
-#
-#  Uncomment and customize the following to suit your needs:
-#
-
-
-libexec_PROGRAMS = win32_check_group
-
-win32_check_group_SOURCES = win32_check_group.c win32_check_group.h
-
-INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src
-
-LDADD   = -L$(top_builddir)/lib -lmiscutil -lnetapi32 -ladvapi32 \
-          -lntdll $(XTRA_LIBS)
-
-EXTRA_DIST = readme.txt
--- squid3/helpers/external_acl/win32_group/readme.txt	Wed Feb 14 13:35:28 2007
+++ /dev/null	Wed Feb 14 13:33:00 2007
@@ -1,86 +0,0 @@
-
-This is the readme.txt file for win32_check_group, an external
-helper fo the External ACL Scheme for Squid.
-
-
-This helper must be used in with an authentication scheme, tipically 
-basic or NTLM, based on Windows NT/2000 domain users. 
-It reads from the standard input the domain username and a list of groups
-and tries to match it against the groups membership of the specified
-username.
-
-
-==============
-Program Syntax
-==============
-
-win32_check_group [-D domain][-G][-P][-c][-d][-h]
-
--D domain specify the default user's domain
--G        start helper in Domain Global Group mode
--P        use ONLY PDCs for group validation
--c        use case insensitive compare
--d        enable debugging
--h        this message
-
-
-================
-squid.conf usage
-================
-
-external_acl_type NT_global_group %LOGIN c:/squid/libexec/win32_check_group.exe -G
-external_acl_type NT_local_group %LOGIN c:/squid/libexec/win32_check_group.exe
-
-acl GProxyUsers external NT_global_group GProxyUsers
-acl LProxyUsers external NT_local_group LProxyUsers
-acl password proxy_auth REQUIRED
-
-http_access allow password GProxyUsers
-http_access allow password LProxyUsers
-http_access deny all
-
-In the previous example all validated NT users member of GProxyUsers Global 
-domain group or member of LProxyUsers machine local group are allowed to 
-use the cache.
-
-Groups with spaces in name, for example "Domain Users", must be quoted and
-the acl data ("Domain Users") must be placed into a separate file included
-by specifying "/path/to/file". The previous example will be:
-
-acl ProxyUsers external NT_global_group "c:/squid/etc/DomainUsers"
-
-and the DomainUsers files will contain only the following line:
-
-"Domain Users"
-
-NOTES: 
-- The standard group name comparation is case sensitive, so group name
-  must be specified with same case as in the NT/2000 Domain.
-  It's possible to enable not case sensitive group name comparation (-c),
-  but on on some non - English locales, the results can be unexpected.
-- Native WIN32 NTLM and Basic Helpers must be used without the
-  -A & -D switches.
-
-Refer to Squid documentation for the more details on squid.conf.
-
-
-=======
-Testing
-=======
-
-I strongly urge that win32_check_group is tested prior to being used in a 
-production environment. It may behave differently on different platforms.
-To test it, run it from the command line. Enter username and group
-pairs separated by a space (username must entered with domain\\username
-syntax). Press ENTER to get an OK or ERR message.
-Make sure pressing <CTRL><D> behaves the same as a carriage return.
-Make sure pressing <CTRL><C> aborts the program.
-
-Test that entering no details does not result in an OK or ERR message.
-Test that entering an invalid username and group results in an ERR message.
-Test that entering an valid username and group results in an OK message.
-
---
-Serassio Guido
-squidnt at acmeconsulting dot it
-
--- squid3/helpers/external_acl/win32_group/win32_check_group.c	Wed Feb 14 13:35:28 2007
+++ /dev/null	Wed Feb 14 13:33:00 2007
@@ -1,606 +0,0 @@
-/*
- * win32_group: lookup group membership in a Windows NT/2000 domain
- *
- * (C)2002,2005 Guido Serassio - Acme Consulting S.r.l.
- *
- * Authors:
- *  Guido Serassio <guido.serassio@acmeconsulting.it>
- *  Acme Consulting S.r.l., Italy <http://www.acmeconsulting.it>
- *
- * With contributions from others mentioned in the change history section
- * below.
- *
- * In part based on check_group by Rodrigo Albani de Campos.
- *
- * 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.22
- * 08-07-2005 Guido Serassio
- *              Added -P option for force usage of PDCs for group validation.
- *              Added support for '/' char as domain separator.
- *              Fixed Bugzilla #1336. 
- * Version 1.21
- * 23-04-2005 Guido Serassio
- *              Added -D option for specify default user's domain.
- * Version 1.20.1
- * 15-08-2004 Guido Serassio
- *              Helper protocol changed to use URL escaped strings in Squid-3.0
- *              (Original work of Henrik Nordstrom)
- * Version 1.20
- * 13-06-2004 Guido Serassio
- *              Added support for running on a Domain Controller.
- * Version 1.10
- * 01-05-2003 Guido Serassio
- *              Added option for case insensitive group name comparation.
- *              More debug info.
- *              Updated documentation.
- *              Segfault bug fix (Bugzilla #574)
- * Version 1.0
- * 24-06-2002 Guido Serassio
- *              Using the main function from check_group and sections
- *              from wbinfo wrote win32_group
- *
- * This is a helper for the external ACL interface for Squid Cache
- * 
- * It reads from the standard input the domain username and a list of
- * groups and tries to match it against the groups membership of the
- * specified username.
- *
- * Returns `OK' if the user belongs to a group or `ERR' otherwise, as
- * described on http://devel.squid-cache.org/external_acl/config.html
- *
- */
-
-#include "config.h"
-#ifdef _SQUID_CYGWIN_
-#include <wchar.h>
-int _wcsicmp(const wchar_t*, const wchar_t*);
-#endif
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#if HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-#undef assert
-#include <assert.h>
-#include <windows.h>
-#include <lm.h>
-#include <ntsecapi.h>
-
-#include "util.h"
-
-#define BUFSIZE 8192		/* the stdin buffer size */
-int use_global = 0;
-int use_PDC_only = 0;
-char debug_enabled = 0;
-char *myname;
-pid_t mypid;
-char * machinedomain;
-int use_case_insensitive_compare = 0;
-char * DefaultDomain = NULL;
-const char NTV_VALID_DOMAIN_SEPARATOR[] = "\\/";
-
-#include "win32_check_group.h"
-
-
-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,
-		(PVOID *)&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 0 on match, -1 if no match */
-static int wcstrcmparray(const wchar_t *str, const char **array)
-{
-    WCHAR wszGroup[GNLEN+1];	// Unicode Group
-
-    while (*array) {
-	MultiByteToWideChar(CP_ACP, 0, *array,
-	    strlen(*array) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0]));
-    	debug("Windows group: %S, Squid group: %S\n", str, wszGroup);
-	if ((use_case_insensitive_compare ? _wcsicmp(str, wszGroup) : wcscmp(str, wszGroup)) == 0)
-	    return 0;
-	array++;
-    }
-    return -1;
-}
-
-/* returns 1 on success, 0 on failure */
-int
-Valid_Local_Groups(char *UserName, const char **Groups)
-{
-    int result = 0;
-    char * Domain_Separator;
-    WCHAR wszUserName[UNLEN+1];	// Unicode user name
-
-    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;
-
-    if ((Domain_Separator = strchr(UserName, '/')) != NULL)
-        *Domain_Separator = '\\';
-    
-    debug("Valid_Local_Groups: checking group membership of '%s'.\n", UserName);
-    
-/* Convert ANSI User Name and Group to Unicode */
-
-    MultiByteToWideChar(CP_ACP, 0, UserName,
-	strlen(UserName) + 1, wszUserName, sizeof(wszUserName) / sizeof(wszUserName[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++) {
-		assert(pTmpBuf != NULL);
-		if (pTmpBuf == NULL) {
-		    result = 0;
-		    break;
-		}
-		if (wcstrcmparray(pTmpBuf->lgrui0_name, Groups) == 0) {
-		    result = 1;
-		    break;
-		}
-		pTmpBuf++;
-		dwTotalCount++;
-	    }
-	}
-    } else
-        result = 0;
-/*
- * Free the allocated memory.
- */
-    if (pBuf != NULL)
-	NetApiBufferFree(pBuf);
-    return result;
-}
-
-
-/* returns 1 on success, 0 on failure */
-int
-Valid_Global_Groups(char *UserName, const char **Groups)
-{
-    int result = 0;
-    WCHAR wszUserName[UNLEN+1];     // Unicode user name
-    WCHAR wszLocalDomain[DNLEN+1];  // Unicode Local Domain
-    WCHAR wszUserDomain[DNLEN+1];   // Unicode User Domain
-
-    char NTDomain[DNLEN+UNLEN+2];
-    char *domain_qualify;
-    char User[UNLEN+1];
-    size_t j;
-
-    LPWSTR LclDCptr = NULL;
-    LPWSTR UsrDCptr = NULL;
-    LPGROUP_USERS_INFO_0 pUsrBuf = NULL;
-    LPGROUP_USERS_INFO_0 pTmpBuf;
-    LPSERVER_INFO_101 pSrvBuf = NULL;
-    DWORD dwLevel = 0;
-    DWORD dwPrefMaxLen = -1;
-    DWORD dwEntriesRead = 0;
-    DWORD dwTotalEntries = 0;
-    NET_API_STATUS nStatus;
-    DWORD i;
-    DWORD dwTotalCount = 0;
-
-    strncpy(NTDomain, UserName, sizeof(NTDomain));
-
-    for (j=0; j < strlen(NTV_VALID_DOMAIN_SEPARATOR); j++) {
-        if ((domain_qualify = strchr(NTDomain, NTV_VALID_DOMAIN_SEPARATOR[j])) != NULL)
-            break;
-    }
-    if (domain_qualify == NULL) {
-	strcpy(User, NTDomain);
-	strcpy(NTDomain, DefaultDomain);
-    } else {
-	strcpy(User, domain_qualify + 1);
-	domain_qualify[0] = '\0';
-	strlwr(NTDomain);
-    }
-
-    debug("Valid_Global_Groups: checking group membership of '%s\\%s'.\n", NTDomain, User);
-
-    /* Convert ANSI User Name and Group to Unicode */
-
-    MultiByteToWideChar(CP_ACP, 0, User,
-	strlen(User) + 1, wszUserName,
-	sizeof(wszUserName) / sizeof(wszUserName[0]));
-    MultiByteToWideChar(CP_ACP, 0, machinedomain,
-	strlen(machinedomain) + 1, wszLocalDomain, sizeof(wszLocalDomain) / sizeof(wszLocalDomain[0]));
-
-
-/* Call the NetServerGetInfo function for local computer, specifying level 101. */
-    dwLevel = 101;
-    nStatus = NetServerGetInfo(NULL, dwLevel, (LPBYTE *)&pSrvBuf);
-    
-    if (nStatus == NERR_Success)
-    {
-        /* Check if we are running on a Domain Controller */
-        if ((pSrvBuf->sv101_type & SV_TYPE_DOMAIN_CTRL) ||
-            (pSrvBuf->sv101_type & SV_TYPE_DOMAIN_BAKCTRL))
-        {
-            LclDCptr = NULL;
-            debug("Running on a DC.\n");
-        }
-        else
-            nStatus = (use_PDC_only ? NetGetDCName(NULL, wszLocalDomain, (LPBYTE *) & LclDCptr) : NetGetAnyDCName(NULL, wszLocalDomain, (LPBYTE *) & LclDCptr));
-    } else {
-	fprintf(stderr, "%s NetServerGetInfo() failed.'\n", myname);
-        if (pSrvBuf != NULL)
-            NetApiBufferFree(pSrvBuf);
-        return result;
-    }
-
-    if (nStatus == NERR_Success) {
-        debug("Using '%S' as DC for '%S' local domain.\n", LclDCptr, wszLocalDomain);
-	
-        if (strcmp(NTDomain, machinedomain) != 0) {
-	    MultiByteToWideChar(CP_ACP, 0, NTDomain,
-		strlen(NTDomain) + 1, wszUserDomain, sizeof(wszUserDomain) / sizeof(wszUserDomain[0]));
-            nStatus = (use_PDC_only ? NetGetDCName(LclDCptr, wszUserDomain, (LPBYTE *) & UsrDCptr) : NetGetAnyDCName(LclDCptr, wszUserDomain, (LPBYTE *) & UsrDCptr));
-	        if (nStatus != NERR_Success) {
-		    fprintf(stderr, "%s Can't find DC for user's domain '%s'\n", myname, NTDomain);
-                    if (pSrvBuf != NULL)
-                        NetApiBufferFree(pSrvBuf);
-		    if (LclDCptr != NULL)
-		        NetApiBufferFree((LPVOID) LclDCptr);
-		    if (UsrDCptr != NULL)
-		        NetApiBufferFree((LPVOID) UsrDCptr);
-		    return result;
-	        }
-	} else
-	    UsrDCptr = LclDCptr;
-
-        debug("Using '%S' as DC for '%s' user's domain.\n", UsrDCptr, NTDomain);
-	/*
-	 * Call the NetUserGetGroups function 
-	     * specifying information level 0.
-	     */
-            dwLevel = 0;
-	    nStatus = NetUserGetGroups(UsrDCptr,
-		wszUserName,
-		dwLevel,
-		(LPBYTE *) & pUsrBuf,
-		dwPrefMaxLen,
-		&dwEntriesRead,
-		&dwTotalEntries);
-	    /*
-	     * If the call succeeds,
-	     */
-	if (nStatus == NERR_Success) {
-	    if ((pTmpBuf = pUsrBuf) != NULL) {
-		for (i = 0; i < dwEntriesRead; i++) {
-		    assert(pTmpBuf != NULL);
-		    if (pTmpBuf == NULL) {
-			result = 0;
-			break;
-		    }
-		    if (wcstrcmparray(pTmpBuf->grui0_name, Groups) == 0) {
-			result = 1;
-			break;
-		    }
-		    pTmpBuf++;
-		    dwTotalCount++;
-		}
-	    }
-        } else {
-	    result = 0;
-            fprintf(stderr, "%s NetUserGetGroups() failed.'\n", myname);
-        }
-    } else {
-	fprintf(stderr, "%s Can't find DC for local domain '%s'\n", myname, machinedomain);
-    }
-    /*
-     * Free the allocated memory.
-     */
-    if (pSrvBuf != NULL)
-        NetApiBufferFree(pSrvBuf);
-    if (pUsrBuf != NULL)
-        NetApiBufferFree(pUsrBuf);
-    if ((UsrDCptr != NULL) && (UsrDCptr != LclDCptr))
-        NetApiBufferFree((LPVOID) UsrDCptr);
-    if (LclDCptr != NULL)
-        NetApiBufferFree((LPVOID) LclDCptr);
-    return result;
-}
-
-static void
-usage(char *program)
-{
-    fprintf(stderr,"Usage: %s [-D domain][-G][-P][-c][-d][-h]\n"
-	    	" -D    default user Domain\n"
-	    	" -G    enable Domain Global group mode\n"
-	    	" -P    use ONLY PDCs for group validation\n"
-	    	" -c    use case insensitive compare\n"
-	    	" -d    enable debugging\n"
-		" -h    this message\n",
-		program);
-}
-
-void
-process_options(int argc, char *argv[])
-{
-    int opt;
-
-    opterr = 0;
-    while (-1 != (opt = getopt(argc, argv, "D:GPcdh"))) {
-	switch (opt) {
-	case 'D':
-	    DefaultDomain = xstrndup(optarg, DNLEN + 1);
-            strlwr(DefaultDomain);
-	    break;
-	case 'G':
-	    use_global = 1;
-	    break;
-	case 'P':
-	    use_PDC_only = 1;
-	    break;
-	case 'c':
-	    use_case_insensitive_compare = 1;
-	    break;
-	case 'd':
-	    debug_enabled = 1;
-	    break;
-	case 'h':
-	    usage(argv[0]);
-	    exit(0);
-	case '?':
-	    opt = optopt;
-	    /* fall thru to default */
-	default:
-	    fprintf(stderr, "%s Unknown option: -%c. Exiting\n", myname, opt);
-	    usage(argv[0]);
-	    exit(1);
-	    break;		/* not reached */
-	}
-    }
-    return;
-}
-
-
-int
-main (int argc, char *argv[])
-{
-    char *p;
-    char buf[BUFSIZE];
-    char *username;
-    char *group;
-    int err = 0;
-    const char *groups[512];
-    int n;
-
-    if (argc > 0) {	/* should always be true */
-	myname=strrchr(argv[0],'/');
-	if (myname==NULL)
-	    myname=argv[0];
-    } else {
-        myname="(unknown)";
-    }
-    mypid=getpid();
-
-    setbuf(stdout, NULL);
-    setbuf(stderr, NULL);
-
-    /* Check Command Line */
-    process_options(argc, argv);
-
-    if (use_global) {
-        if ((machinedomain = GetDomainName()) == NULL) {
-	    fprintf(stderr, "%s Can't read machine domain\n", myname);
-	    exit(1);
-	}
-	strlwr(machinedomain);
-        if (!DefaultDomain)
-            DefaultDomain = xstrdup(machinedomain);
-    }
-
-    debug("External ACL win32 group helper build " __DATE__ ", " __TIME__
-    " starting up...\n");
-    if (use_global)
-        debug("Domain Global group mode enabled using '%s' as default domain.\n", DefaultDomain);
-    if (use_case_insensitive_compare)
-        debug("Warning: running in case insensitive mode !!!\n");
-    if (use_PDC_only)
-        debug("Warning: using only PDCs for group validation !!!\n");
-
-    /* Main Loop */
-    while (fgets (buf, sizeof(buf), stdin))
-    {
-	if (NULL == strchr(buf, '\n')) {
-	    /* too large message received.. skip and deny */
-	    fprintf(stderr, "%s: ERROR: Too large: %s\n", argv[0], buf);
-	    while (fgets(buf, sizeof(buf), stdin)) {
-		fprintf(stderr, "%s: ERROR: Too large..: %s\n", argv[0], buf);
-		if (strchr(buf, '\n') != NULL)
-		    break;
-	    }
-	    goto error;
-	}
-	
-	if ((p = strchr(buf, '\n')) != NULL)
-	    *p = '\0';		/* strip \n */
-	if ((p = strchr(buf, '\r')) != NULL)
-	    *p = '\0';		/* strip \r */
-
-	debug("Got '%s' from Squid (length: %d).\n",buf,strlen(buf));
-
-	if (buf[0] == '\0') {
-	    fprintf(stderr, "Invalid Request\n");
-	    goto error;
-	}
-
-	username = strtok(buf, " ");
-	for (n = 0; (group = strtok(NULL, " ")) != NULL; n++) {
-	    rfc1738_unescape(group);
-	    groups[n] = group;
-	}
-	groups[n] = NULL;
-
-        if (NULL == username) {
-            fprintf(stderr, "Invalid Request\n");
-            goto error;
-        }
-	rfc1738_unescape(username);
-
-	if ((use_global ? Valid_Global_Groups(username, groups) : Valid_Local_Groups(username, groups))) {
-	    printf ("OK\n");
-	} else {
-error:
-	    printf ("ERR\n");
-	}
-	err = 0;
-    }
-    return 0;
-}
--- squid3/helpers/external_acl/win32_group/win32_check_group.h	Wed Feb 14 13:35:28 2007
+++ /dev/null	Wed Feb 14 13:33:00 2007
@@ -1,79 +0,0 @@
-/*
- * (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.
- */
-
-#undef debug
-
-/************* CONFIGURATION ***************/
-/*
- * define this if you want debugging
- */
-#ifndef DEBUG
-#define DEBUG
-#endif
-
-/************* END CONFIGURATION ***************/
-
-#include <sys/types.h>
-
-#define safe_free(x)	if (x) { free(x); x = NULL; }
-
-/* Debugging stuff */
-
-#ifdef __GNUC__			/* this is really a gcc-ism */
-#ifdef DEBUG
-#include <stdio.h>
-#include <unistd.h>
-static char *__foo;
-extern char debug_enabled;
-#define debug(X...) if (debug_enabled) { \
-                    fprintf(stderr,"%s[%d](%s:%d): ", myname, mypid, \
-                    ((__foo=strrchr(__FILE__,'/'))==NULL?__FILE__:__foo+1),\
-                    __LINE__);\
-                    fprintf(stderr,X); }
-#else /* DEBUG */
-#define debug(X...)		/* */
-#endif /* DEBUG */
-#else /* __GNUC__ */
-extern char debug_enabled;
-static void
-debug(char *format,...) 
-{
-#ifdef DEBUG
-#ifdef _SQUID_MSWIN_
-    if (debug_enabled) {
-	va_list args;
-
-	va_start(args,format);
-	fprintf(stderr, "%s[%d]: ", myname, mypid);
-	vfprintf(stderr, format, args);
-	fprintf(stderr, "\n");
-	va_end(args);
-    }
-#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
