This patch is generated from the cygwin-svc-2_5 branch of s2_5 in squid Wed Sep 29 00:07:44 2004 GMT See http://devel.squid-cache.org/ Index: squid/acconfig.h diff -u squid/acconfig.h:1.13.2.3 squid/acconfig.h:1.13.4.4 --- squid/acconfig.h:1.13.2.3 Mon Jul 1 10:24:48 2002 +++ squid/acconfig.h Sat Jul 13 13:08:17 2002 @@ -151,6 +151,11 @@ /* Define if NTLM is allowed to fail gracefully when a helper has problems */ #undef NTLM_FAIL_OPEN +/* + * Define Windows NT & Windows 2000 run service mode + */ +#undef USE_WIN32_SERVICE + /******************************** * END OF CONFIGURABLE OPTIONS * ********************************/ Index: squid/acinclude.m4 diff -u squid/acinclude.m4:1.2.2.3 squid/acinclude.m4:1.1.60.4 --- squid/acinclude.m4:1.2.2.3 Fri Jun 21 07:50:49 2002 +++ squid/acinclude.m4 Tue Jul 16 05:06:49 2002 @@ -1,3 +1,123 @@ +dnl COMPILER WIN32 support ==================================== +# figure out how to run CC with access to the win32 api if present +# configure that as the CC program, +# WIN32 may be present with WINE, under cygwin, or under mingw, +# or cross compilers targeting those same three targets. +# as it happens, I can only test cygwin, so extra input here will be appreciated +# send bug reports to Robert Collins +# +# logic: is CC already configured? if not, call AC_PROG_CC. +# if so - try it. If that doesn't work ,try -mwin32. If that doesn't work, fail +# +# 2001-03-15 - Changed from yes/no to true/false -suggested by Lars J Aas +# * Change true to : - suggest by Alexandre Oliva +# * changed layout on the basis of autoconf mailing list: +# there are now two interfaces, a language specific one which sets +# or clears WIN32 && WIN32FLAGS as appropriate +# * m4 Syntax fixup: Akim Demaille +# +# All faults& bugs are mine - Robert + +AC_DEFUN([AC_PROG_CC_WIN32], [ +dnl AC_REQUIRE([AC_PROG_CC])dnl +AC_MSG_CHECKING([how to access the Win32 API]) +WIN32FLAGS= +AC_TRY_COMPILE(,[ +#ifndef WIN32 +# ifndef _WIN32 +# error WIN32 or _WIN32 not defined +# endif +#endif], [ +dnl found windows.h with the current config. +AC_MSG_RESULT([present by default]) +], [ +dnl try -mwin32 +ac_compile_save="$ac_compile" +dnl we change CC so config.log looks correct +save_CC="$CC" +ac_compile="$ac_compile -mwin32" +CC="$CC -mwin32" +AC_TRY_COMPILE(,[ +#ifndef WIN32 +# ifndef _WIN32 +# error WIN32 or _WIN32 not defined +# endif +#endif], [ +dnl found windows.h using -mwin32 +AC_MSG_RESULT([found via -mwin32]) +ac_compile="$ac_compile_save" +CC="$save_CC" +WIN32FLAGS="-mwin32" +], [ +ac_compile="$ac_compile_save" +CC="$save_CC" +AC_MSG_RESULT([not found]) +]) +]) + +]) + + +# figure out how to run CXX with access to the win32 api if present +# configure that as the CXX program, +# WIN32 may be present with WINE, under cygwin, or under mingw, +# or cross compilers targeting those same three targets. +# as it happens, I can only test cygwin, so extra input here will be appreciated +# send bug reports to Robert Collins + +AC_DEFUN([AC_PROG_CXX_WIN32], [ +dnl AC_REQUIRE([AC_PROG_CXX])dnl +AC_MSG_CHECKING([how to access the Win32 API]) +WIN32FLAGS= +AC_TRY_COMPILE(,[ +#ifndef WIN32 +# ifndef _WIN32 +# error WIN32 or _WIN32 not defined +# endif +#endif], [ +dnl found windows.h with the current config. +AC_MSG_RESULT([present by default]) +], [ +dnl try -mwin32 +ac_compile_save="$ac_compile" +dnl we change CC so config.log looks correct +save_CXX="$CXX" +ac_compile="$ac_compile -mwin32" +CXX="$CXX -mwin32" +AC_TRY_COMPILE(,[ +#ifndef WIN32 +# ifndef _WIN32 +# error WIN32 or _WIN32 not defined +# endif +#endif], [ +dnl found windows.h using -mwin32 +AC_MSG_RESULT([found via -mwin32]) +ac_compile="$ac_compile_save" +CXX="$save_CXX" +WIN32FLAGS="-mwin32" +], [ +ac_compile="$ac_compile_save" +CXX="$save_CXX" +AC_MSG_RESULT([not found]) +]) +]) + +]) + + +# high level interface for finding out compiler support for win32. +AC_DEFUN([AC_API_WIN32], [ + +AC_LANG_CASE( + [C], AC_PROG_CC_WIN32 [CFLAGS="$WIN32FLAGS $CFLAGS" + CPPFLAGS="$WIN32FLAGS $CPPFLAGS"], + [C++], AC_PROG_CXX_WIN32 [CXXFLAGS="$WIN32FLAGS $CXXFLAGS" + CPPFLAGS="$WIN32FLAGS $CPPFLAGS"], + [AC_FATAL([No macro support for WIN32 with ] _AC_LANG) ]) +]) + +dnl end compiler WIN32 support =========================================== + dnl AC_CHECK_SIZEOF_SYSTYPE is as the standard AC_CHECK_SIZEOF macro dnl but also capable of checking the size of system defined types, not dnl only compiler defined types. @@ -78,4 +198,3 @@ AC_DEFINE($1, $2) fi ]) - Index: squid/configure.in diff -u squid/configure.in:1.42.2.37 squid/configure.in:1.42.2.5.2.21 --- squid/configure.in:1.42.2.37 Sun May 4 19:19:16 2003 +++ squid/configure.in Mon May 12 11:31:39 2003 @@ -68,6 +68,9 @@ AC_DEFINE_UNQUOTED(CONFIG_HOST_TYPE, "$host") +dnl Can the CC program be asked to use the Win32 API? +AC_API_WIN32 + AC_DEFINE_UNQUOTED(SQUID_CONFIGURE_OPTIONS, "$ac_configure_args") dnl Gerben Wierda @@ -830,6 +833,15 @@ fi ]) +dnl Enable WIN32 Service compile mode +AC_ARG_ENABLE(win32-service, +[ --enable-win32-service Compile Squid as a WIN32 Service + Works only on Windows NT and Windows 2000 Platforms.], +[ if test "$enableval" = "yes" ; then + echo "Enabling WIN32 run service mode" + AC_DEFINE(USE_WIN32_SERVICE) + fi +]) dnl Select auth schemes modules to build AC_ARG_ENABLE(auth, @@ -2106,7 +2118,7 @@ else AC_MSG_RESULT("no") echo "Will use our own inet_ntoa()." - LIBOBJS="$LIBOBJS inet_ntoa.o" + AC_LIBOBJ="$AC_LIBOBJ inet_ntoa.o" # echo "WARNING: This looks bad, and probably prevents Squid from working." # echo " If you're on IRIX and using GCC 2.8, you probably need" # echo " to use the IRIX C compiler instead." @@ -2274,6 +2286,7 @@ helpers/basic_auth/NCSA/Makefile \ helpers/basic_auth/PAM/Makefile \ helpers/basic_auth/SMB/Makefile \ + helpers/basic_auth/win32_locallogon/Makefile \ helpers/basic_auth/YP/Makefile \ helpers/basic_auth/getpwnam/Makefile \ helpers/basic_auth/multi-domain-NTLM/Makefile \ @@ -2286,6 +2299,7 @@ helpers/ntlm_auth/no_check/Makefile \ helpers/ntlm_auth/SMB/Makefile \ helpers/ntlm_auth/SMB/smbval/Makefile \ + helpers/ntlm_auth/NTLMSSP-WIN32/Makefile \ helpers/ntlm_auth/winbind/Makefile \ helpers/external_acl/Makefile \ helpers/external_acl/ip_user/Makefile \ @@ -2293,4 +2307,5 @@ helpers/external_acl/unix_group/Makefile \ helpers/external_acl/wbinfo_group/Makefile \ helpers/external_acl/winbind_group/Makefile \ + helpers/external_acl/win32_group/Makefile \ ]) Index: squid/doc/win32-relnotes.txt diff -u /dev/null squid/doc/win32-relnotes.txt:1.1.34.3 --- /dev/null Tue Sep 28 17:12:18 2004 +++ squid/doc/win32-relnotes.txt Tue Jul 16 05:06:49 2002 @@ -0,0 +1,69 @@ +WIN32 Squid Relese Notes + + +Windows Service run mode + +To enable the service mode, use the --enable-win32-service configure option +When in Windows service mode the -N Squid switch is disabled, and default run mode of +Squid is no daemon (=no service) mode, so is possible to run Squid from command line +for debug purpose with all command line options available. + +The service installation is made with -i command line switch, it's possible to use +-f switch at the same time for specify a different config-file settings for the Squid +Service that is stored on Registry. +A new -n switch specify the Windows Service Name, so multiple Squid instance are allowed. +"SquidNT" is the default when the switch is not used. + +So the install service syntax is "squid -i [-f file] [-n name]". + +To start as service is used a "hidden" --ntservice:service-name command line switch, +where service-name is the name specified with -n options at service install time. + +Service uninstallation is made with -r command line switch plus the appropriate +-n switch. + +The -k switch family must be used with the appropriate -f and -n switches, so the syntax is: + +squid -k command [-f file] -n service-name + +where service-name is the name specified with -n options at service install time. + +To use Squid original command line, the new -O switch must be used, the sintax is: + +squid -O cmdline [-n service-name] + +If multiple service command line options must be specified, use quote. The -n switch is +needed only when non default service name is in use. + +Example: + +squid -O "-D -a 8080" -n squidsvc + + +PSAPI.DLL (Process Status Helper) Considerations + +The process status helper functions make it easier for you to obtain information about +processes and device drivers running on Microsoft® Windows NT®/Windows® 2000. These +functions are available in PSAPI.DLL, which is distributed in the Microsoft® Platform +Software Development Kit (SDK). The same information is generally available through the +performance data in the registry, but it is more difficult to get to it. PSAPI.DLL is +freely redistributable. + +PSAPI.DLL is available only on Windows NT, 2000 and XP. The implementation in Squid is +aware of this, and try to use it only on the rigth platform. + +On Windows NT PSAPI.DLL can be found as component of many applications, if you need it, +you can find it on Windows NT Resource KIT. If you have problem, you can You can +download it here: +http://download.microsoft.com/download/platformsdk/Redist/4.0.1371.1/NT4/EN-US/psinst.EXE + +On Windows 2000 it is available installing the Windows 2000 Support Tools, located on the +Support\Tools folder of the installation Windows 2000 CD-ROM. + + +Registry DNS lookup + +On Windows platforms, if no value is specified in the dns_nameservers option on +squid.conf or in the /etc/resolv.conf file, the list of DNS name servers are +taken from the Windows registry, both static and dynamic DHCP configurations +are supported. Index: squid/helpers/basic_auth/Makefile.am diff -u squid/helpers/basic_auth/Makefile.am:1.1.2.1 squid/helpers/basic_auth/Makefile.am:1.2.16.2 --- squid/helpers/basic_auth/Makefile.am:1.1.2.1 Fri Jun 28 07:46:19 2002 +++ squid/helpers/basic_auth/Makefile.am Tue Jul 16 05:06:49 2002 @@ -3,5 +3,5 @@ # $Id: squid-cygwin-svc-2_5-s2_5,v 1.2 2004/09/29 00:22:50 hno Exp $ # -DIST_SUBDIRS = getpwnam LDAP MSNT multi-domain-NTLM NCSA PAM SMB YP SASL winbind +DIST_SUBDIRS = getpwnam LDAP MSNT multi-domain-NTLM NCSA PAM SMB YP SASL winbind win32_locallogon SUBDIRS = @BASIC_AUTH_HELPERS@ Index: squid/helpers/basic_auth/win32_locallogon/.cvsignore diff -u /dev/null squid/helpers/basic_auth/win32_locallogon/.cvsignore:1.1.8.1 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/basic_auth/win32_locallogon/.cvsignore Mon Jul 15 04:25:27 2002 @@ -0,0 +1,2 @@ +.cvsignore +Makefile.in Index: squid/helpers/basic_auth/win32_locallogon/Makefile.am diff -u /dev/null squid/helpers/basic_auth/win32_locallogon/Makefile.am:1.1.8.2 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/basic_auth/win32_locallogon/Makefile.am Tue Jul 16 01:38:10 2002 @@ -0,0 +1,17 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-cygwin-svc-2_5-s2_5,v 1.2 2004/09/29 00:22:50 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + + +libexec_PROGRAMS = nt_auth + +nt_auth_SOURCES = NT_auth.c valid.c + +LDADD = -L$(top_builddir)/lib -lnetapi32 -ladvapi32 -lsspwin32 -lmiscutil + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src/ Index: squid/helpers/basic_auth/win32_locallogon/NT_auth.c diff -u /dev/null squid/helpers/basic_auth/win32_locallogon/NT_auth.c:1.1.8.2 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/basic_auth/win32_locallogon/NT_auth.c Sun Aug 11 08:57:25 2002 @@ -0,0 +1,170 @@ +/* + NT_auth - Version 2.0 + + Modified to act as a Squid authenticator module. + Removed all Pike stuff. + Returns OK for a successful authentication, or ERR upon error. + + Guido Serassio, Torino - Italy + + Uses code from - + Antonino Iannella 2000 + Andrew Tridgell 1997 + Richard Sharpe 1996 + Bill Welliver 1999 + + * 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. +*/ + +#include "squid.h" + +/* Check if we try to compile on a Windows Platform */ +#if defined(_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) + +#include "valid.h" + +static char NTGroup[256]; +char * NTAllowedGroup; +char * NTDisAllowedGroup; +int UseDisallowedGroup = 0; +int UseAllowedGroup = 0; + +/* + * options: + * -a can specify a Windows Local Group name allowed to authenticate. + * -d can specify a Windows Local Group name not allowed to authenticate. + * -D can specify the default Domain against to authenticate. + */ +char *my_program_name = NULL; + +void +usage() +{ + fprintf(stderr, + "%s usage:\n%s [-a UserGroup] [-d UserGroup] [-D DefaultDomain] \n" + "-a can specify a Windows Local Group name allowed to authenticate\n" + "-d can specify a Windows Local Group name not allowed to authenticate\n" + "-D can specify the default Domain against to authenticate\n" + "-h this message\n\n", + my_program_name, my_program_name); +} + +void +process_options(int argc, char *argv[]) +{ + int opt, had_error = 0; + while (-1 != (opt = getopt(argc, argv, "ha:d:D:"))) { + switch (opt) { + case 'a': + safe_free(NTAllowedGroup); + NTAllowedGroup=xstrdup(optarg); + UseAllowedGroup = 1; + break; + case 'd': + safe_free(NTDisAllowedGroup); + NTDisAllowedGroup=xstrdup(optarg); + UseDisallowedGroup = 1; + break; + case 'D': + strcpy(Default_NTDomain, optarg); + break; + case 'h': + usage(argv[0]); + exit(0); + case '?': + opt = optopt; + /* fall thru to default */ + default: + fprintf(stderr, "Unknown option: -%c. Exiting\n", opt); + had_error = 1; + } + } + if (had_error) { + usage(); + exit(1); + } +} + +/* Main program for simple authentication. + Scans and checks for Squid input, and attempts to validate the user. +*/ + +int +main(int argc, char **argv) + +{ + char wstr[256]; + char username[256]; + char password[256]; + char *p; + int err = 0; + + my_program_name = argv[0]; + process_options(argc, argv); + + if (LoadSecurityDll(SSP_BASIC) == NULL) { + fprintf(stderr, "FATAL, can't initialize SSPI, exiting.\n"); + exit(1); + } + atexit(UnloadSecurityDll); + + /* initialize FDescs */ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + while (1) { + /* Read whole line from standard input. Terminate on break. */ + if (fgets(wstr, 255, stdin) == NULL) + break; + + if (NULL == strchr(wstr, '\n')) { + err = 1; + continue; + } + if (err) { + fprintf(stderr, "Oversized message\n"); + goto error; + } + + if ((p = strchr(wstr, '\n')) != NULL) + *p = '\0'; /* strip \n */ + if ((p = strchr(wstr, '\r')) != NULL) + *p = '\0'; /* strip \r */ + /* Clear any current settings */ + username[0] = '\0'; + password[0] = '\0'; + sscanf(wstr, "%s %s", username, password); /* Extract parameters */ + + /* Check for invalid or blank entries */ + if ((username[0] == '\0') || (password[0] == '\0')) { + fprintf(stderr, "Invalid Request\n"); + puts("ERR"); + fflush(stdout); + continue; + } + if (Valid_User(username, password, NTGroup) == NTV_NO_ERROR) + puts("OK"); + else +error: + puts("ERR"); + err = 0; + fflush(stdout); + } + return 0; +} + +#else /* NON Windows Platform !!! */ + +#error NON WINDOWS PLATFORM + +#endif Index: squid/helpers/basic_auth/win32_locallogon/README.txt diff -u /dev/null squid/helpers/basic_auth/win32_locallogon/README.txt:1.1.8.2 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/basic_auth/win32_locallogon/README.txt Tue Jul 16 10:46:15 2002 @@ -0,0 +1,95 @@ +This is a simple authentication module for the Squid proxy server running on Windows NT +to authenticate users on an NT domain in native WIN32 mode. + +Usage is simple. It accepts a username and password on standard input +and will return OK if the username/password is valid for the domain/machine, +or ERR if there was some problem. +It's possible to authenticate against NT trusted domains specifyng the username +in the domain\username Microsoft notation. + + +============== +Program Syntax +============== + +nt_auth [-a UserGroup] [-d UserGroup] [-D DefaultDomain] + +-a can specify a Windows Local Group name allowed to authenticate. +-d can specify a Windows Local Group name not allowed to authenticate. +-D can specify the default Domain against to authenticate. + +This is released under the GNU General Public License and +is available from http://www.serassio.it. + + +============== +Allowing Users +============== + +Users that are allowed to access the web proxy must have the Windows NT +User Rights "logon from the network" and must be included in the NT LOCAL User Groups +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. + +Refer to Squid documentation for the required changes to squid.conf. + + +============ +Installation +============ + +Type 'make', then 'make install', then 'make clean'. + +The default is to install 'nt_auth' into /usr/local/squid/libexec. + +Refer to Squid documentation for the required changes to squid.conf. +You will need to set the following line to enable the authenticator: + +authenticate_program /usr/local/squid/bin/NT_auth + +You will need to set the following lines to enable authentication for +your access list - + + acl proxy_auth REQUIRED + http_access allow + +You will need to specify the absolute path to NT_auth in the +authenticate_program directive, and check the authenticate_children +and authenticate_ttl. + + +================== +Compilation issues +================== + +The Makefile assumes that GCC is in the current PATH. +NT_auth compile ONLY on CygWin Environment or MS VC++. + + +======= +Testing +======= + +I strongly urge that NT_auth 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 password +pairs separated by a space. Press ENTER to get an OK or ERR message. +Make sure pressing behaves the same as a carriage return. +Make sure pressing aborts the program. + +Test that entering no details does not result in an OK or ERR message. +Test that entering an invalid username and password results in an ERR message. +Note that if NT guest user access is allowed on the PDC, an OK message +may be returned instead of ERR. +Test that entering an valid username and password results in an OK message. +Test that entering a guest username and password returns the correct +response for the site's access policy. + + +=============== +Contact details +=============== + +To contact the maintainer of this package, e-mail on squidnt@serassio.it. +The latest version may be found on http://www.serassio.it/SquidNT.htm. Index: squid/helpers/basic_auth/win32_locallogon/valid.c diff -u /dev/null squid/helpers/basic_auth/win32_locallogon/valid.c:1.1.8.1 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/basic_auth/win32_locallogon/valid.c Mon Jul 15 04:25:27 2002 @@ -0,0 +1,166 @@ +/* + NT_auth - Version 2.0 + + Modified to act as a Squid authenticator module. + Removed all Pike stuff. + Returns OK for a successful authentication, or ERR upon error. + + Guido Serassio, Torino - Italy + + Uses code from - + Antonino Iannella 2000 + Andrew Tridgell 1997 + Richard Sharpe 1996 + Bill Welliver 1999 + + * 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. +*/ + +#include "squid.h" + +/* Check if we try to compile on a Windows Platform */ +#if defined(_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) + +#include +#if defined(_SQUID_CYGWIN_) +#include +#endif +#include +#include +#include "valid.h" + +char Default_NTDomain[256] = NTV_DEFAULT_DOMAIN; + +/* returns 1 on success, 0 on failure */ +int +Valid_Group(char *UserName, char *Group) +{ + int result = FALSE; + WCHAR wszUserName[256]; // Unicode user name + WCHAR wszGroup[256]; // 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++) { + assert(pTmpBuf != NULL); + 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; +} + +/* Valid_User return codes - + 0 - User authenticated successfully. + 1 - Server error. + 2 - Protocol error. + 3 - Logon error; Incorrect password or username given. +*/ + +int +Valid_User(char *UserName, char *Password, char *Group) +{ + int result = NTV_LOGON_ERROR; + char NTDomain[256]; + char *domain_qualify; + char DomainUser[256]; + char User[256]; + + strcpy(NTDomain, UserName); + if ((domain_qualify = strchr(NTDomain, '\\')) == NULL) { + strcpy(User, NTDomain); + strcpy(NTDomain, Default_NTDomain); + } else { + strcpy(User, domain_qualify + 1); + domain_qualify[0] = '\0'; + } + /* Log the client on to the local computer. */ + if (!SSPLogonUser(User, Password, NTDomain)) { + result = NTV_LOGON_ERROR; + } else { + result = NTV_NO_ERROR; + if (strcmp(NTDomain, NTV_DEFAULT_DOMAIN) == 0) + strcpy(DomainUser, User); + else { + strcpy(DomainUser, NTDomain); + strcat(DomainUser, "\\"); + strcat(DomainUser, User); + } + if (UseAllowedGroup) { + if (!Valid_Group(DomainUser, NTAllowedGroup)) { + result = NTV_LOGON_ERROR; + } + } + if (UseDisallowedGroup) { + if (Valid_Group(DomainUser, NTDisAllowedGroup)) { + result = NTV_LOGON_ERROR; + } + } + } + return result; +} +#else /* NON Windows Platform !!! */ + +#error NON WINDOWS PLATFORM + +#endif Index: squid/helpers/basic_auth/win32_locallogon/valid.h diff -u /dev/null squid/helpers/basic_auth/win32_locallogon/valid.h:1.1.8.2 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/basic_auth/win32_locallogon/valid.h Tue Jul 16 01:38:10 2002 @@ -0,0 +1,55 @@ +/* + NT_auth - Version 2.0 + + Modified to act as a Squid authenticator module. + Removed all Pike stuff. + Returns OK for a successful authentication, or ERR upon error. + + Guido Serassio, Torino - Italy + + Uses code from - + Antonino Iannella 2000 + Andrew Tridgell 1997 + Richard Sharpe 1996 + Bill Welliver 1999 + + * 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 _VALID_H_ +#define _VALID_H_ + +#include "sspwin32.h" + +/* SMB User verification function */ + +#define NTV_NO_ERROR 0 +#define NTV_SERVER_ERROR 1 +#define NTV_PROTOCOL_ERROR 2 +#define NTV_LOGON_ERROR 3 + +#ifndef LOGON32_LOGON_NETWORK +#define LOGON32_LOGON_NETWORK 3 +#endif + +#define NTV_DEFAULT_DOMAIN "." + +extern char * NTAllowedGroup; +extern char * NTDisAllowedGroup; +extern int UseDisallowedGroup; +extern int UseAllowedGroup; +extern char Default_NTDomain[256]; + +int Valid_User(char *,char *, char *); + +#endif Index: squid/helpers/external_acl/Makefile.am diff -u squid/helpers/external_acl/Makefile.am:1.2.2.2 squid/helpers/external_acl/Makefile.am:1.2.10.2 --- squid/helpers/external_acl/Makefile.am:1.2.2.2 Wed Jul 17 08:30:22 2002 +++ squid/helpers/external_acl/Makefile.am Mon Jul 15 03:35:59 2002 @@ -3,5 +3,5 @@ # $Id: squid-cygwin-svc-2_5-s2_5,v 1.2 2004/09/29 00:22:50 hno Exp $ # -DIST_SUBDIRS = ip_user ldap_group unix_group wbinfo_group winbind_group +DIST_SUBDIRS = ip_user ldap_group unix_group wbinfo_group winbind_group win32_group SUBDIRS = @EXTERNAL_ACL_HELPERS@ Index: squid/helpers/external_acl/win32_group/.cvsignore diff -u /dev/null squid/helpers/external_acl/win32_group/.cvsignore:1.1.4.1 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/external_acl/win32_group/.cvsignore Mon Jul 15 03:35:59 2002 @@ -0,0 +1,2 @@ +.cvsignore +Makefile.in Index: squid/helpers/external_acl/win32_group/Makefile.am diff -u /dev/null squid/helpers/external_acl/win32_group/Makefile.am:1.1.10.2 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/external_acl/win32_group/Makefile.am Tue Jul 16 02:08:54 2002 @@ -0,0 +1,17 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-cygwin-svc-2_5-s2_5,v 1.2 2004/09/29 00:22:50 hno Exp $ +# +# Uncomment and customize the following to suit your needs: +# + + +libexec_PROGRAMS = win32_check_group + +win32_check_group_SOURCES = win32_check_group.c + +INCLUDES = -I. -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_srcdir)/src + +LDADD = -L$(top_builddir)/lib -lmiscutil -lnetapi32 -ladvapi32 Index: squid/helpers/external_acl/win32_group/readme.txt diff -u /dev/null squid/helpers/external_acl/win32_group/readme.txt:1.1.10.1 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/external_acl/win32_group/readme.txt Mon Jul 15 03:35:59 2002 @@ -0,0 +1,71 @@ + +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, tipcally basic +or NTLM based on Windows NT/2000 domain users. +It reads two new line terminated argument from the standard input +(the domain username and group) and tries to match it against +the groups membership of the specified username. + + +============== +Program Syntax +============== + +win32_check_group [-Gd] + +-G start helper in Global Group mode +-d enable debug mode + + +================ +squid.conf usage +================ + +external_acl_type NT_global_group %LOGIN /usr/local/squid/libexec/win32_check_group -G +external_acl_type NT_local_group %LOGIN /usr/local/squid/libexec/win32_check_group + +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 must be quoted, for example "Domain Users" + +NOTES: +- The group name comparation is case sensitive, so group name + must be specified with same case as in the NT/2000 Domain. +- 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 behaves the same as a carriage return. +Make sure pressing 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@serassio.it Index: squid/helpers/external_acl/win32_group/win32_check_group.c diff -u /dev/null squid/helpers/external_acl/win32_group/win32_check_group.c:1.1.10.4 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/external_acl/win32_group/win32_check_group.c Tue Oct 22 12:34:22 2002 @@ -0,0 +1,511 @@ +/* + * $Id: squid-cygwin-svc-2_5-s2_5,v 1.2 2004/09/29 00:22:50 hno Exp $ + * + * This is a helper for the external ACL interface for Squid Cache + * Copyright (C) 2002 Guido Serassio + * Based on previous work of Rodrigo Albani de Campos + * + * It reads STDIN looking for a username that matches a NT/2000 global + * Domain group. + * Returns `OK' if the user belongs to the group or `ERR' otherwise, as + * described on http://devel.squid-cache.org/external_acl/config.html + * To compile this program, use: + * + * 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. + * + */ + +#include "squid.h" +#if defined(_SQUID_CYGWIN_) +#include +#endif +#undef assert +#include +#include +#include +#include + +#define BUFSIZE 8192 /* the stdin buffer size */ +int use_global = 0; +char debug_enabled = 0; +char *myname; +pid_t mypid; +char * machinedomain; + +#include "win32_check_group.h" + +static char * +strwordtok(char *buf, char **t) +{ + unsigned char *word = NULL; + unsigned char *p = (unsigned char *) buf; + unsigned char *d; + unsigned char ch; + int quoted = 0; + if (!p) + p = (unsigned char *) *t; + if (!p) + goto error; + while (*p && isspace(*p)) + p++; + if (!*p) + goto error; + word = d = p; + while ((ch = *p)) { + switch (ch) { + case '\\': + p++; + *d++ = ch = *p; + if (ch) + p++; + break; + case '"': + quoted = !quoted; + p++; + break; + default: + if (!quoted && isspace(*p)) { + p++; + goto done; + } + *d++ = *p++; + break; + } + } + done: + *d++ = '\0'; + error: + *t = (char *) p; + return (char *) word; +} + + +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: %d\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: %d\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: %d\n", netret); + return DomainName; +} + + +/* returns 1 on success, 0 on failure */ +int +Valid_Local_Group(char *UserName, char *Group) +{ + int result = 0; + WCHAR wszUserName[256]; // Unicode user name + WCHAR wszGroup[256]; // 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++) { + assert(pTmpBuf != NULL); + if (pTmpBuf == NULL) { + result = 0; + break; + } + if (wcscmp(pTmpBuf->lgrui0_name, wszGroup) == 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_Group(char *UserName, char *Group) +{ + int result = 0; + WCHAR wszUserName[256]; // Unicode user name + WCHAR wszGroup[256]; // Unicode Group + WCHAR wszLocalDomain[256]; // Unicode Local Domain + WCHAR wszUserDomain[256]; // Unicode User Domain + + char NTDomain[256]; + char *domain_qualify; + char User[256]; + + LPCWSTR LclDCptr = NULL; + LPCWSTR UsrDCptr = NULL; + LPGROUP_USERS_INFO_0 pBuf = NULL; + LPGROUP_USERS_INFO_0 pTmpBuf; + DWORD dwLevel = 0; + DWORD dwPrefMaxLen = -1; + DWORD dwEntriesRead = 0; + DWORD dwTotalEntries = 0; + NET_API_STATUS nStatus; + DWORD i; + DWORD dwTotalCount = 0; + + strcpy(NTDomain, UserName); + if ((domain_qualify = strchr(NTDomain, '\\')) == NULL) { + return result; + } else { + strcpy(User, domain_qualify + 1); + domain_qualify[0] = '\0'; + _strlwr(NTDomain); + } + +/* 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, Group, + strlen(Group) + 1, wszGroup, sizeof(wszGroup) / sizeof(wszGroup[0])); + MultiByteToWideChar(CP_ACP, 0, machinedomain, + strlen(machinedomain) + 1, wszLocalDomain, sizeof(wszLocalDomain) / sizeof(wszLocalDomain[0])); + + nStatus = NetGetAnyDCName( + NULL, + wszLocalDomain, + (LPBYTE *) & LclDCptr); + + if (nStatus == NERR_Success) { + if (strcmp(NTDomain, machinedomain) != 0) { + MultiByteToWideChar(CP_ACP, 0, NTDomain, + strlen(NTDomain) + 1, wszUserDomain, sizeof(wszUserDomain) / sizeof(wszUserDomain[0])); + nStatus = NetGetAnyDCName( + LclDCptr, + wszUserDomain, + (LPBYTE *) & UsrDCptr); + if (nStatus != NERR_Success) { + fprintf(stderr, "%s Can't find DC for domain %s\n", myname, NTDomain); + if (LclDCptr != NULL) + NetApiBufferFree((LPVOID) LclDCptr); + if (UsrDCptr != NULL) + NetApiBufferFree((LPVOID) UsrDCptr); + return result; + } + } else + UsrDCptr = LclDCptr; + + /* + * 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 = NetUserGetGroups(UsrDCptr, + wszUserName, + dwLevel, + (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 (wcscmp(pTmpBuf->grui0_name, wszGroup) == 0) { + result = 1; + break; + } + pTmpBuf++; + dwTotalCount++; + } + } + } else + result = 0; + } else { + fprintf(stderr, "%s Can't find DC for domain %s\n", myname, machinedomain); + } + /* + * Free the allocated memory. + */ + if (pBuf != NULL) + NetApiBufferFree(pBuf); + if (LclDCptr != NULL) + NetApiBufferFree((LPVOID) LclDCptr); + if (UsrDCptr != NULL) + NetApiBufferFree((LPVOID) UsrDCptr); + return result; +} + +static void +usage(char *program) +{ + fprintf(stderr,"Usage: %s [-d] [-h]\n" + " -d enable debugging\n" + " -G enable Domain Global group mode\n" + " -h this message\n", + program); +} + +void +process_options(int argc, char *argv[]) +{ + int opt; + + opterr = 0; + while (-1 != (opt = getopt(argc, argv, "Gdh"))) { + switch (opt) { + case 'G': + use_global = 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, *t; + char buf[BUFSIZE]; + char *username; + char *group; + int err = 0; + + 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); + } + + debug("External ACL win32 group helper build " __DATE__ ", " __TIME__ + " starting up...\n"); + + /* Main Loop */ + while (fgets (buf, BUFSIZE, stdin)) + { + if (NULL == strchr(buf, '\n')) { + err = 1; + continue; + } + if (err) { + fprintf(stderr, "Oversized message\n"); + 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,sizeof(buf)); + + if (buf[0] == '\0') { + fprintf(stderr, "Invalid Request\n"); + goto error; + } + + username = strwordtok(buf, &t); + group = strwordtok(NULL, &t); + + if ((use_global ? Valid_Global_Group(username, group) : Valid_Local_Group(username, group))) { + printf ("OK\n"); + } else { +error: + printf ("ERR\n"); + } + err = 0; + } + return 0; +} Index: squid/helpers/external_acl/win32_group/win32_check_group.h diff -u /dev/null squid/helpers/external_acl/win32_group/win32_check_group.h:1.1.4.1 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/external_acl/win32_group/win32_check_group.h Mon Jul 15 03:35:59 2002 @@ -0,0 +1,78 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli, Robert Collins and Andrew Doran + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +#undef debug + +/************* CONFIGURATION ***************/ +/* + * define this if you want debugging + */ +#ifndef DEBUG +#define DEBUG +#endif + +/************* END CONFIGURATION ***************/ + +#include + +/* Debugging stuff */ + +#ifdef __GNUC__ /* this is really a gcc-ism */ +#ifdef DEBUG +#include +#include +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 + Index: squid/helpers/ntlm_auth/Makefile.am diff -u squid/helpers/ntlm_auth/Makefile.am:1.1.2.1 squid/helpers/ntlm_auth/Makefile.am:1.2.16.2 --- squid/helpers/ntlm_auth/Makefile.am:1.1.2.1 Fri Jun 28 07:46:21 2002 +++ squid/helpers/ntlm_auth/Makefile.am Tue Jul 16 02:07:00 2002 @@ -3,5 +3,5 @@ # $Id: squid-cygwin-svc-2_5-s2_5,v 1.2 2004/09/29 00:22:50 hno Exp $ # -DIST_SUBDIRS = fakeauth no_check SMB winbind +DIST_SUBDIRS = fakeauth no_check SMB winbind NTLMSSP-WIN32 SUBDIRS = @NTLM_AUTH_HELPERS@ Index: squid/helpers/ntlm_auth/NTLMSSP-WIN32/.cvsignore diff -u /dev/null squid/helpers/ntlm_auth/NTLMSSP-WIN32/.cvsignore:1.1.6.2 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/ntlm_auth/NTLMSSP-WIN32/.cvsignore Tue Jul 16 05:06:49 2002 @@ -0,0 +1,2 @@ +.cvsignore +Makefile.in Index: squid/helpers/ntlm_auth/NTLMSSP-WIN32/Makefile.am diff -u /dev/null squid/helpers/ntlm_auth/NTLMSSP-WIN32/Makefile.am:1.1.6.1 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/ntlm_auth/NTLMSSP-WIN32/Makefile.am Tue Jul 16 02:07:00 2002 @@ -0,0 +1,14 @@ +# +# Makefile for the Squid Object Cache server +# +# $Id: squid-cygwin-svc-2_5-s2_5,v 1.2 2004/09/29 00:22:50 hno Exp $ +# + +libexec_PROGRAMS = ntlm_auth + +ntlm_auth_SOURCES = libntlmssp.c ntlm_auth.c ntlm.h + +INCLUDES = -I. -I$(top_srcdir)/include -I$(top_srcdir)/src + +LDADD = -L$(top_builddir)/lib -lntlmauth -lsspwin32 -lnetapi32 \ + -ladvapi32 -lmiscutil $(CRYPTLIB) $(XTRA_LIBS) Index: squid/helpers/ntlm_auth/NTLMSSP-WIN32/libntlmssp.c diff -u /dev/null squid/helpers/ntlm_auth/NTLMSSP-WIN32/libntlmssp.c:1.1.6.1 --- /dev/null Tue Sep 28 17:12:24 2004 +++ squid/helpers/ntlm_auth/NTLMSSP-WIN32/libntlmssp.c Tue Jul 16 02:07:00 2002 @@ -0,0 +1,382 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli and Robert Collins + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +typedef unsigned char uchar; + +#include "squid.h" +#include "ntlm.h" +#include +#include +#include + +#ifdef DEBUG +#define debug_dump_ntlmssp_flags dump_ntlmssp_flags +#else /* DEBUG */ +#define debug_dump_ntlmssp_flags(X) /* empty */ +#endif /* DEBUG */ + +#define ENCODED_PASS_LEN 24 +static char challenge[NONCE_LEN]; +static char lmencoded_empty_pass[ENCODED_PASS_LEN], + ntencoded_empty_pass[ENCODED_PASS_LEN]; + +/* returns 1 on success, 0 on failure */ +int +Valid_Group(char *UserName, char *Group) +{ + int result = FALSE; + WCHAR wszUserName[256]; // Unicode user name + WCHAR wszGroup[256]; // 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++) { + assert(pTmpBuf != NULL); + 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; +} + +/* returns 0 on success, > 0 on failure */ +static int +init_challenge(void) +{ + static unsigned hash; + int r; + int i; + + r = (int) rand(); + r = (hash ^ r) + r; + for (i = 0; i < NONCE_LEN; i++) { + challenge[i] = r; + r = (r >> 2) ^ r; + } + hash = r; + return 0; +} + +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: %d\n", status); + } else { + + /* + * You have a handle to the policy object. Now, get the + * domain information using LsaQueryInformationPolicy. + */ + status = LsaQueryInformationPolicy(PolicyHandle, + PolicyPrimaryDomainInformation, + &ppdiDomainInfo); + if (status) { + debug("LsaQueryInformationPolicy Error: %d\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: %d\n", netret); + return DomainName; +} + +const char * +make_challenge(void) +{ + static char ComputerName[MAX_COMPUTERNAME_LENGTH + 1]; + static char * DomainName; + DWORD CNsize = MAX_COMPUTERNAME_LENGTH + 1; + + GetComputerName(ComputerName, &CNsize); + uc(ComputerName); + if ((DomainName=GetDomainName()) == NULL) + return NULL; + uc(DomainName); + debug("ComputerName:%s DomainName: %s",ComputerName,DomainName); + if (init_challenge() > 0) + return NULL; + return ntlm_make_challenge(DomainName, ComputerName, challenge, NONCE_LEN); +} + +int ntlm_errno; +static char credentials[1024]; /* we can afford to waste */ + + +/* Fetches the user's credentials from the challenge. + * Returns NULL if domain or user is not defined + * No identity control is performed. + * WARNING! The result is static storage, shared with ntlm_check_auth + */ +char * +fetch_credentials(ntlm_authenticate * auth, int auth_length) +{ + char *p = credentials; + lstring tmp; + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->domain); + if (tmp.str == NULL) + return NULL; + memcpy(p, tmp.str, tmp.l); + p += tmp.l; + *p++ = '\\'; + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->user); + if (tmp.str == NULL) + return NULL; + *(p + tmp.l) = '\0'; + return credentials; +} + +/* 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 pass[25] /*, encrypted_pass[40] */; + char *domain = credentials; + char *user; + lstring tmp; + +/* debug("fetching domain\n"); */ + 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_LOGON_ERROR; + return NULL; + } + memcpy(domain, tmp.str, tmp.l); + user = domain + tmp.l; + *user++ = '\0'; + +/* debug("fetching user name\n"); */ + 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_LOGON_ERROR; + return NULL; + } + memcpy(user, tmp.str, tmp.l); + *(user + tmp.l) = '\0'; + + + /* Authenticating against the NT response doesn't seem to work... */ + tmp = ntlm_fetch_string((char *) auth, auth_length, &auth->lmresponse); + if (tmp.str == NULL || tmp.l == 0) { + fprintf(stderr, "No auth at all. Returning no-auth\n"); + ntlm_errno = NTLM_LOGON_ERROR; + return NULL; + } + + memcpy(pass, tmp.str, tmp.l); + pass[25] = '\0'; + +#if 1 + debug ("Empty LM pass detection: user: '%s', ours:'%s', his: '%s'" + "(length: %d)\n", + user,lmencoded_empty_pass,tmp.str,tmp.l); + if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) { + fprintf(stderr,"Empty LM password supplied for user %s\\%s. " + "No-auth\n",domain,user); + ntlm_errno=NTLM_LOGON_ERROR; + return NULL; + } + + tmp = ntlm_fetch_string ((char *) auth, auth_length, &auth->ntresponse); + if (tmp.str != NULL && tmp.l != 0) { + debug ("Empty NT pass detection: user: '%s', ours:'%s', his: '%s'" + "(length: %d)\n", + user,ntencoded_empty_pass,tmp.str,tmp.l); + if (memcmp(tmp.str,lmencoded_empty_pass,ENCODED_PASS_LEN)==0) { + fprintf(stderr,"Empty NT password supplied for user %s\\%s. " + "No-auth\n",domain,user); + ntlm_errno=NTLM_LOGON_ERROR; + return NULL; + } + } +#endif + + /* TODO: check against empty password!!!!! */ + + + + debug("checking domain: '%s', user: '%s', pass='%s'\n", domain, user, pass); + rv = SSPLogonUser(user, pass, domain); + + debug("Login attempt had result %d\n", rv); + + if (!rv) { /* failed */ + ntlm_errno = ss; + return NULL; + } + *(user - 1) = '\\'; /* hack. Performing, but ugly. */ + + 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; +} Index: squid/helpers/ntlm_auth/NTLMSSP-WIN32/ntlm.h diff -u /dev/null squid/helpers/ntlm_auth/NTLMSSP-WIN32/ntlm.h:1.1.6.2 --- /dev/null Tue Sep 28 17:12:25 2004 +++ squid/helpers/ntlm_auth/NTLMSSP-WIN32/ntlm.h Sun Aug 11 08:57:25 2002 @@ -0,0 +1,108 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli, Robert Collins and Andrew Doran + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +#ifndef _NTLM_H_ +#define _NTLM_H_ + +#include "sspwin32.h" +#include +#include +#include +#include "ntlmauth.h" +#undef debug + +/************* CONFIGURATION ***************/ +/* + * define this if you want debugging + */ +#ifndef DEBUG +#define DEBUG +#endif + +/************* END CONFIGURATION ***************/ + +#include + +/* Debugging stuff */ + +#ifdef __GNUC__ /* this is really a gcc-ism */ +#ifdef DEBUG +#include +#include +static char *__foo; +extern char debug_enabled; +#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__ */ +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, "ntlm-auth[%d]: ",getpid()); + 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 + +extern char * NTAllowedGroup; +extern char * NTDisAllowedGroup; +extern int UseDisallowedGroup; +extern int UseAllowedGroup; +extern int ntlm_errno; + +#define NTLM_NO_ERROR SEC_E_OK +#define NTLM_SERVER_ERROR SEC_E_NOT_SUPPORTED +#define NTLM_PROTOCOL_ERROR SEC_E_INCOMPLETE_MESSAGE +#define NTLM_LOGON_ERROR SEC_E_LOGON_DENIED +#define NTLM_UNTRUSTED_DOMAIN SEC_E_NO_AUTHENTICATING_AUTHORITY +#define NTLM_BAD_PROTOCOL SEC_E_BAD_PKGID +#define NTLM_NOT_CONNECTED SEC_E_SECPKG_NOT_FOUND +#define NTLM_BAD_NTGROUP -1 + +extern void uc(char *); + +const char *make_challenge(void); +extern char *ntlm_check_auth(ntlm_authenticate * auth, int auth_length); +extern char *fetch_credentials(ntlm_authenticate * auth, int auth_length); + +#endif /* _NTLM_H_ */ Index: squid/helpers/ntlm_auth/NTLMSSP-WIN32/ntlm_auth.c diff -u /dev/null squid/helpers/ntlm_auth/NTLMSSP-WIN32/ntlm_auth.c:1.1.6.4 --- /dev/null Tue Sep 28 17:12:25 2004 +++ squid/helpers/ntlm_auth/NTLMSSP-WIN32/ntlm_auth.c Sun Aug 11 09:46:29 2002 @@ -0,0 +1,321 @@ +/* + * $Id: squid-cygwin-svc-2_5-s2_5,v 1.2 2004/09/29 00:22:50 hno Exp $ + * + * This is a helper for NTLM Authentication for Squid Cache + * Copyright (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli and Robert Collins + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + + +#include "squid.h" +#include "ntlm.h" + +#define BUFFER_SIZE 10240 + + +#ifdef DEBUG +char error_messages_buffer[BUFFER_SIZE]; +#endif + +char load_balance = 0, protocol_pedantic = 0; +#ifdef NTLM_FAIL_OPEN +char last_ditch_enabled = 0; +#endif + +char debug_enabled=0; + + +char * NTAllowedGroup; +char * NTDisAllowedGroup; +int UseDisallowedGroup = 0; +int UseAllowedGroup = 0; + +/* makes a null-terminated string upper-case. Changes CONTENTS! */ +void +uc(char *string) +{ + char *p = string, c; + while ((c = *p)) { + *p = toupper(c); + p++; + } +} + +/* makes a null-terminated string lower-case. Changes CONTENTS! */ +static void +lc(char *string) +{ + char *p = string, c; + while ((c = *p)) { + *p = tolower(c); + p++; + } +} + +void +helperfail(const char *reason) +{ + SEND2("BH %s", reason); +} + +void +send_bh_or_ld(char *bhmessage, ntlm_authenticate * failedauth, int authlen) +{ +#ifdef NTLM_FAIL_OPEN + char *creds = NULL; + if (last_ditch_enabled) { + creds = fetch_credentials(failedauth, authlen); + if (creds) { + lc(creds); + SEND2("LD %s", creds); + } else { + SEND("NA last-ditch on, but no credentials"); + } + } else { +#endif + SEND2("BH %s", bhmessage); +#ifdef NTLM_FAIL_OPEN + } +#endif +} + +/* + * options: + * -v enables debugging statements if DEBUG was defined at build-time. + * -l if specified, changes behavior on failures to last-ditch. + * -a can specify a Windows Local Group name allowed to authenticate. + * -d can specify a Windows Local Group name not allowed to authenticate. + * domain\controller ... + */ +char *my_program_name = NULL; + +void +usage() +{ + fprintf(stderr, +#ifdef NTLM_FAIL_OPEN + "%s usage:\n%s [-v] [-a UserGroup] [-d UserGroup] [-l] [-h]\n" +#else + "%s usage:\n%s [-v] [-a UserGroup] [-d UserGroup] [-h]\n" +#endif + "-v enables verbose debugging.\n" +#ifdef NTLM_FAIL_OPEN + "-l if specified, changes behavior on failures to last-ditch\n" +#endif + "-a specify a Windows Local Group name allowed to authenticate\n" + "-d specify a Windows Local Group name not allowed to authenticate\n" + "-h this message\n\n", + my_program_name, my_program_name); +} + + +void +process_options(int argc, char *argv[]) +{ + int opt, had_error = 0; + + opterr =0; +#ifdef NTLM_FAIL_OPEN + while (-1 != (opt = getopt(argc, argv, "hvla:d:"))) { +#else + while (-1 != (opt = getopt(argc, argv, "hva:d:"))) { +#endif + switch (opt) { + case 'a': + safe_free(NTAllowedGroup); + NTAllowedGroup=xstrdup(optarg); + UseAllowedGroup = 1; + break; + case 'd': + safe_free(NTDisAllowedGroup); + NTDisAllowedGroup=xstrdup(optarg); + UseDisallowedGroup = 1; + break; +#ifdef NTLM_FAIL_OPEN + case 'l': + last_ditch_enabled = 1; + break; +#endif + case 'v': + debug_enabled=1; + break; + case 'h': + usage(); + exit(0); + case '?': + opt = optopt; + /* fall thru to default */ + default: + fprintf(stderr, "unknown option: -%c. Exiting\n", opt); + usage(); + had_error = 1; + } + } + if (had_error) + exit(1); +} + +/* tries connecting to the domain controllers in the "controllers" ring, + * with failover if the adequate option is specified. + */ +const char * +obtain_challenge() +{ + int j = 0; + const char *ch = NULL; + + debug("attempting challenge retrieval\n"); + ch = make_challenge(); + debug("make_challenge returned %p\n", ch); + if (ch) { + debug("Got it\n"); + return ch; /* All went OK, returning */ + } + return NULL; +} + + +void +manage_request() +{ + ntlmhdr *fast_header; + char buf[BUFFER_SIZE]; + char *c, *decoded, *cred; + int plen; + int oversized = 0; + +try_again: + if (fgets(buf, BUFFER_SIZE, stdin) == NULL) { + debug("fgets() failed! dying..... errno=%d (%s)\n", errno, + strerror(errno)); + exit(1); /* BIIG buffer */ + } + c = memchr(buf, '\n', BUFFER_SIZE); /* safer against overrun than strchr */ + if (c) { + if (oversized) { + helperfail("illegal request received"); + fprintf(stderr, "Illegal request received: '%s'\n", buf); + return; + } + *c = '\0'; + } else { + fprintf(stderr, "No newline in '%s'\n", buf); + oversized = 1; + goto try_again; + } + + debug("Got '%s' from Squid\n", buf); + + if (memcmp(buf, "YR", 2) == 0) { /* refresh-request */ + c = (char *) obtain_challenge(); + SEND2("TT %s", c); + return; + } + if (memcmp(buf, "KK ", 3) == 0) { /* authenticate-request */ + /* figure out what we got */ + decoded = base64_decode(buf + 3); + /* Note: we don't need to manage memory at this point, since + * base64_decode returns a pointer to static storage. + */ + + if (!decoded) { /* decoding failure, return error */ + SEND("NA Packet format error, couldn't base64-decode"); + return; + } + /* fast-track-decode request type. */ + fast_header = (struct _ntlmhdr *) decoded; + + /* sanity-check: it IS a NTLMSSP packet, isn't it? */ + if (memcmp(fast_header->signature, "NTLMSSP", 8) != 0) { + SEND("NA Broken authentication packet"); + return; + } + switch (fast_header->type) { + case NTLM_NEGOTIATE: + SEND("NA Invalid negotiation request received"); + return; + /* notreached */ + case NTLM_CHALLENGE: + SEND + ("NA Got a challenge. We refuse to have our authority disputed"); + return; + /* notreached */ + case NTLM_AUTHENTICATE: + /* check against SSPI */ + plen = strlen(buf) * 3 / 4; /* we only need it here. Optimization */ + cred = ntlm_check_auth((ntlm_authenticate *) decoded, plen); + if (cred == NULL) { + switch (ntlm_errno) { + case NTLM_LOGON_ERROR: + SEND("NA Logon Failure"); + return; + case NTLM_BAD_NTGROUP: + SEND("NA Incorrect Group Membership"); + return; + case NTLM_UNTRUSTED_DOMAIN: + SEND("NA No authority could be contacted for authentication"); + return; + default: + SEND("NA SSPI Error"); + return; + } + } + lc(cred); /* let's lowercase them for our convenience */ + SEND2("AF %s", cred); + return; + default: + helperfail("unknown authentication packet type"); + return; + } + return; + } else { /* not an auth-request */ + helperfail("illegal request received"); + fprintf(stderr, "Illegal request received: '%s'\n", buf); + return; + } + helperfail("detected protocol error"); + return; +/********* END ********/ +} + +int +main(int argc, char *argv[]) +{ + + debug("ntlm_auth build " __DATE__ ", " __TIME__ " starting up...\n"); + + my_program_name = argv[0]; + process_options(argc, argv); + debug("options processed OK\n"); + srand( (unsigned)time( NULL ) ); + + if (LoadSecurityDll(SSP_NTLM) == NULL) { + fprintf(stderr, "FATAL, can't initialize SSPI, exiting.\n"); + exit(1); + } + debug("SSPI initialized OK\n"); + + atexit(UnloadSecurityDll); + + /* initialize FDescs */ + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + while (1) { + manage_request(); + } + return 0; +} Index: squid/helpers/ntlm_auth/NTLMSSP-WIN32/readme.txt diff -u /dev/null squid/helpers/ntlm_auth/NTLMSSP-WIN32/readme.txt:1.1.6.1 --- /dev/null Tue Sep 28 17:12:25 2004 +++ squid/helpers/ntlm_auth/NTLMSSP-WIN32/readme.txt Tue Jul 16 02:07:00 2002 @@ -0,0 +1,31 @@ +ntlm_auth.exe + +Native Windows NTLM authenticator for Squid 2.5 + +Usage: + +ntlm_auth [-v] [-a UserGroup] [-d UserGroup] [-l] + +-v enables debugging statements if DEBUG was defined at build-time. +-l if specified, changes behavior on failures to last-ditch. +-a can specify a Windows Local Group name allowed to authenticate. +-d can specify a Windows Local Group name not allowed to authenticate. + +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" and must be included in the NT LOCAL User Groups +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. + +Refer to Squid documentation for the required changes to squid.conf. + + +Contact details - + +To contact the maintainer of this package, e-mail on squidnt@serassio.it. +The latest version may be found on http://www.serassio.it/SquidNT.htm. Index: squid/include/sspwin32.h diff -u /dev/null squid/include/sspwin32.h:1.1.2.1 --- /dev/null Tue Sep 28 17:12:25 2004 +++ squid/include/sspwin32.h Tue Jul 16 01:36:43 2002 @@ -0,0 +1,45 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli, Robert Collins and Andrew Doran + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +#ifndef _LIBSSPWIN32_H_ +#define _LIBSSPWIN32_H_ +#define SECURITY_WIN32 +#define NTLM_PACKAGE_NAME "NTLM" + +#ifdef _SQUID_CYGWIN_ +#include +#define _T(x) TEXT(x) +#else +#include +#endif +#include +#include +#include + +#define WINNT_SECURITY_DLL "security.dll" +#define WIN9X_SECURITY_DLL "secur32.dll" + +#define SSP_BASIC 1 +#define SSP_NTLM 2 + +HMODULE LoadSecurityDll(int); +void UnloadSecurityDll(void); +BOOL WINAPI SSPLogonUser(PTSTR, PTSTR, PTSTR); + +extern SECURITY_STATUS ss; + +#endif /* LIBSSPWIN32_H_ */ Index: squid/lib/Makefile.am diff -u squid/lib/Makefile.am:1.4 squid/lib/Makefile.am:1.4.6.1 --- squid/lib/Makefile.am:1.4 Wed Nov 21 15:48:57 2001 +++ squid/lib/Makefile.am Tue Jul 16 01:35:13 2002 @@ -21,6 +21,7 @@ @LIBDLMALLOC@ \ libmiscutil.a \ libntlmauth.a \ + libsspwin32.a \ @LIBREGEX@ EXTRA_libmiscutil_a_SOURCES = \ md5.c \ @@ -57,5 +58,7 @@ ntlmauth.c libntlmauth_a_LIBADD = \ @LIBOBJS@ +libsspwin32_a_SOURCES = \ + sspwin32.c -INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src -I$(top_builddir)/src Index: squid/lib/rfc1123.c diff -u squid/lib/rfc1123.c:1.6 squid/lib/rfc1123.c:1.6.10.1 --- squid/lib/rfc1123.c:1.6 Thu Oct 18 13:52:10 2001 +++ squid/lib/rfc1123.c Wed Feb 27 11:44:04 2002 @@ -260,6 +260,7 @@ #elif defined (_timezone) #elif defined(_SQUID_AIX_) #elif defined(_SQUID_CYGWIN_) +#elif defined(_SQUID_MSWIN_) #else extern time_t timezone; #endif @@ -269,7 +270,7 @@ */ if (tm->tm_isdst > 0) dst = -3600; -#if defined ( _timezone) || defined(_SQUID_CYGWIN_) +#if defined ( _timezone) || defined(_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) t -= (_timezone + dst); #else t -= (timezone + dst); Index: squid/lib/sspwin32.c diff -u /dev/null squid/lib/sspwin32.c:1.1.2.1 --- /dev/null Tue Sep 28 17:12:25 2004 +++ squid/lib/sspwin32.c Tue Jul 16 01:35:13 2002 @@ -0,0 +1,411 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli, 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. + */ + +#include "squid.h" +#include "sspwin32.h" + + + +typedef struct _AUTH_SEQ { + BOOL fInitialized; + BOOL fHaveCredHandle; + BOOL fHaveCtxtHandle; + CredHandle hcred; + struct _SecHandle hctxt; +} AUTH_SEQ, *PAUTH_SEQ; + +static HMODULE hModule; +static int NTLM_mode = SSP_BASIC; +SECURITY_STATUS ss = SEC_E_OK; + +/* Function pointers */ +ACCEPT_SECURITY_CONTEXT_FN _AcceptSecurityContext = NULL; +ACQUIRE_CREDENTIALS_HANDLE_FN _AcquireCredentialsHandle = NULL; +COMPLETE_AUTH_TOKEN_FN _CompleteAuthToken = NULL; +DELETE_SECURITY_CONTEXT_FN _DeleteSecurityContext = NULL; +FREE_CONTEXT_BUFFER_FN _FreeContextBuffer = NULL; +FREE_CREDENTIALS_HANDLE_FN _FreeCredentialsHandle = NULL; +INITIALIZE_SECURITY_CONTEXT_FN _InitializeSecurityContext = NULL; +QUERY_SECURITY_PACKAGE_INFO_FN _QuerySecurityPackageInfo = NULL; + + +void UnloadSecurityDll(void) +{ + if (hModule) + FreeLibrary(hModule); + _AcceptSecurityContext = NULL; + _AcquireCredentialsHandle = NULL; + _CompleteAuthToken = NULL; + _DeleteSecurityContext = NULL; + _FreeContextBuffer = NULL; + _FreeCredentialsHandle = NULL; + _InitializeSecurityContext = NULL; + _QuerySecurityPackageInfo = NULL; + hModule = NULL; +} + + +HMODULE LoadSecurityDll(int mode) +{ + TCHAR lpszDLL[MAX_PATH]; + OSVERSIONINFO VerInfo; +/* + * Find out which security DLL to use, depending on + * whether we are on NT or Win95 or 2000 or XP or .NET Server + * We have to use security.dll on Windows NT 4.0. + * All other operating systems, we have to use Secur32.dll + */ + hModule = NULL; + if ((mode != SSP_BASIC) && (mode != SSP_NTLM)) + return hModule; + NTLM_mode = mode; + VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + if (!GetVersionEx (&VerInfo)) { /* If this fails, something has gone wrong */ + return hModule; + } + if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && + VerInfo.dwMajorVersion == 4 && + VerInfo.dwMinorVersion == 0) + { + lstrcpy (lpszDLL, _T(WINNT_SECURITY_DLL)); + } else { + lstrcpy (lpszDLL, _T(WIN9X_SECURITY_DLL)); + } + hModule = LoadLibrary(lpszDLL); + if (!hModule) + return hModule; + _AcceptSecurityContext = (ACCEPT_SECURITY_CONTEXT_FN) + GetProcAddress(hModule, "AcceptSecurityContext"); + if (!_AcceptSecurityContext) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } +#ifdef UNICODE + _AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN) + GetProcAddress(hModule, "AcquireCredentialsHandleW"); +#else + _AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN) + GetProcAddress(hModule, "AcquireCredentialsHandleA"); +#endif + if (!_AcquireCredentialsHandle) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } +/* CompleteAuthToken is not present on Windows 9x Secur32.dll + * Do not check for the availablity of the function if it is NULL + */ + _CompleteAuthToken = (COMPLETE_AUTH_TOKEN_FN) + GetProcAddress(hModule, "CompleteAuthToken"); + _DeleteSecurityContext = (DELETE_SECURITY_CONTEXT_FN) + GetProcAddress(hModule, "DeleteSecurityContext"); + if (!_DeleteSecurityContext) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } + _FreeContextBuffer = (FREE_CONTEXT_BUFFER_FN) + GetProcAddress(hModule, "FreeContextBuffer"); + if (!_FreeContextBuffer) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } + _FreeCredentialsHandle = (FREE_CREDENTIALS_HANDLE_FN) + GetProcAddress(hModule, "FreeCredentialsHandle"); + if (!_FreeCredentialsHandle) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } +#ifdef UNICODE + _InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN) + GetProcAddress(hModule, "InitializeSecurityContextW"); +#else + _InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN) + GetProcAddress(hModule, "InitializeSecurityContextA"); +#endif + if (!_InitializeSecurityContext) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } +#ifdef UNICODE + _QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN) + GetProcAddress(hModule, "QuerySecurityPackageInfoW"); +#else + _QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN) + GetProcAddress(hModule, "QuerySecurityPackageInfoA"); +#endif + if (!_QuerySecurityPackageInfo) { + UnloadSecurityDll(); + hModule = NULL; + } + return hModule; +} + + +BOOL GenClientContext(PAUTH_SEQ pAS, PSEC_WINNT_AUTH_IDENTITY pAuthIdentity, + PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone) +{ +/* + * Routine Description: + * + * Optionally takes an input buffer coming from the server and returns + * a buffer of information to send back to the server. Also returns + * an indication of whether or not the context is complete. + * + * Return Value: + * Returns TRUE if successful; otherwise FALSE. + */ + TimeStamp tsExpiry; + SecBufferDesc sbdOut; + SecBuffer sbOut; + SecBufferDesc sbdIn; + SecBuffer sbIn; + ULONG fContextAttr; + + if (!pAS->fInitialized) { + ss = _AcquireCredentialsHandle(NULL, _T(NTLM_PACKAGE_NAME), + SECPKG_CRED_OUTBOUND, NULL, (NTLM_mode == SSP_NTLM) ? NULL : pAuthIdentity, NULL, NULL, + &pAS->hcred, &tsExpiry); + if (ss < 0) { + fprintf(stderr, "AcquireCredentialsHandle failed with %08X\n", ss); + return FALSE; + } + pAS->fHaveCredHandle = TRUE; + } + + /* Prepare output buffer */ + sbdOut.ulVersion = 0; + sbdOut.cBuffers = 1; + sbdOut.pBuffers = &sbOut; + sbOut.cbBuffer = *pcbOut; + sbOut.BufferType = SECBUFFER_TOKEN; + sbOut.pvBuffer = pOut; + + /* Prepare input buffer */ + if (pAS->fInitialized) { + sbdIn.ulVersion = 0; + sbdIn.cBuffers = 1; + sbdIn.pBuffers = &sbIn; + sbIn.cbBuffer = cbIn; + sbIn.BufferType = SECBUFFER_TOKEN; + sbIn.pvBuffer = pIn; + } + ss = _InitializeSecurityContext(&pAS->hcred, + pAS->fInitialized ? &pAS->hctxt : NULL, NULL, 0, 0, + SECURITY_NATIVE_DREP, pAS->fInitialized ? &sbdIn : NULL, + 0, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry); + if (ss < 0) { + // + fprintf(stderr, "InitializeSecurityContext failed with %08X\n", ss); + return FALSE; + } + pAS->fHaveCtxtHandle = TRUE; + + /* If necessary, complete token */ + if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) { + if (_CompleteAuthToken) { + ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut); + if (ss < 0) { + fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss); + return FALSE; + } + } else { + fprintf (stderr, "CompleteAuthToken not supported.\n"); + return FALSE; + } + } + *pcbOut = sbOut.cbBuffer; + if (!pAS->fInitialized) + pAS->fInitialized = TRUE; + *pfDone = !(ss == SEC_I_CONTINUE_NEEDED + || ss == SEC_I_COMPLETE_AND_CONTINUE ); + return TRUE; +} + + +BOOL GenServerContext(PAUTH_SEQ pAS, PVOID pIn, DWORD cbIn, PVOID pOut, + PDWORD pcbOut, PBOOL pfDone) +{ +/* + * Routine Description: + * + * Takes an input buffer coming from the client and returns a buffer + * to be sent to the client. Also returns an indication of whether or + * not the context is complete. + * + * Return Value: + * + * Returns TRUE if successful; otherwise FALSE. + */ + + TimeStamp tsExpiry; + SecBufferDesc sbdOut; + SecBuffer sbOut; + SecBufferDesc sbdIn; + SecBuffer sbIn; + ULONG fContextAttr; + + if (!pAS->fInitialized) { + ss = _AcquireCredentialsHandle(NULL, _T("NTLM"), + SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &pAS->hcred, + &tsExpiry); + if (ss < 0) { + fprintf(stderr, "AcquireCredentialsHandle failed with %08X\n", ss); + return FALSE; + } + pAS->fHaveCredHandle = TRUE; + } + + /* Prepare output buffer */ + sbdOut.ulVersion = 0; + sbdOut.cBuffers = 1; + sbdOut.pBuffers = &sbOut; + sbOut.cbBuffer = *pcbOut; + sbOut.BufferType = SECBUFFER_TOKEN; + sbOut.pvBuffer = pOut; + + /* Prepare input buffer */ + sbdIn.ulVersion = 0; + sbdIn.cBuffers = 1; + sbdIn.pBuffers = &sbIn; + sbIn.cbBuffer = cbIn; + sbIn.BufferType = SECBUFFER_TOKEN; + sbIn.pvBuffer = pIn; + ss = _AcceptSecurityContext(&pAS->hcred, + pAS->fInitialized ? &pAS->hctxt : NULL, &sbdIn, (NTLM_mode == SSP_NTLM) ? ASC_REQ_DELEGATE : 0, + SECURITY_NATIVE_DREP, &pAS->hctxt, &sbdOut, &fContextAttr, + &tsExpiry); + if (ss < 0) { + fprintf(stderr, "AcceptSecurityContext failed with %08X\n", ss); + return FALSE; + } + pAS->fHaveCtxtHandle = TRUE; + + /* If necessary, complete token */ + if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) { + if (_CompleteAuthToken) { + ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut); + if (ss < 0) { + fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss); + return FALSE; + } + } else { + fprintf (stderr, "CompleteAuthToken not supported.\n"); + return FALSE; + } + } + *pcbOut = sbOut.cbBuffer; + if (!pAS->fInitialized) + pAS->fInitialized = TRUE; + *pfDone = !(ss = SEC_I_CONTINUE_NEEDED + || ss == SEC_I_COMPLETE_AND_CONTINUE); + return TRUE; +} + + +BOOL WINAPI SSPLogonUser(PTSTR szUser, PTSTR szPassword, PTSTR szDomain) +{ + AUTH_SEQ asServer = {0}; + AUTH_SEQ asClient = {0}; + BOOL fDone = FALSE; + BOOL fResult = FALSE; + DWORD cbOut = 0; + DWORD cbIn = 0; + DWORD cbMaxToken = 0; + PVOID pClientBuf = NULL; + PVOID pServerBuf = NULL; + PSecPkgInfo pSPI = NULL; + + SEC_WINNT_AUTH_IDENTITY ai; + + do { + if (!hModule) + break; + /* Get max token size */ + _QuerySecurityPackageInfo(_T("NTLM"), &pSPI); + cbMaxToken = pSPI->cbMaxToken; + _FreeContextBuffer(pSPI); + + /* Allocate buffers for client and server messages */ + pClientBuf = xcalloc(cbMaxToken, sizeof(char)); + pServerBuf = xcalloc(cbMaxToken, sizeof(char)); + + /* Initialize auth identity structure */ + ZeroMemory(&ai, sizeof(ai)); + ai.Domain = szDomain; + ai.DomainLength = lstrlen(szDomain); + ai.User = szUser; + ai.UserLength = lstrlen(szUser); + ai.Password = szPassword; + ai.PasswordLength = lstrlen(szPassword); +#if defined(UNICODE) || defined(_UNICODE) + ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; +#else + ai.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; +#endif + + /* Prepare client message (negotiate) */ + cbOut = cbMaxToken; + if (!GenClientContext(&asClient, &ai, NULL, 0, pClientBuf, &cbOut, &fDone)) + break; + + /* Prepare server message (challenge) */ + cbIn = cbOut; + cbOut = cbMaxToken; + if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut, + &fDone)) + break; +/* Most likely failure: AcceptServerContext fails with SEC_E_LOGON_DENIED + * in the case of bad szUser or szPassword. + * Unexpected Result: Logon will succeed if you pass in a bad szUser and + * the guest account is enabled in the specified domain. + */ + + /* Prepare client message (authenticate) */ + cbIn = cbOut; + cbOut = cbMaxToken; + if (!GenClientContext(&asClient, &ai, pServerBuf, cbIn, pClientBuf, &cbOut, + &fDone)) + break; + + /* Prepare server message (authentication) */ + cbIn = cbOut; + cbOut = cbMaxToken; + if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut, + &fDone)) + break; + fResult = TRUE; + } while(0); + + /* Clean up resources */ + if (asClient.fHaveCtxtHandle) + _DeleteSecurityContext(&asClient.hctxt); + if (asClient.fHaveCredHandle) + _FreeCredentialsHandle(&asClient.hcred); + if (asServer.fHaveCtxtHandle) + _DeleteSecurityContext(&asServer.hctxt); + if (asServer.fHaveCredHandle) + _FreeCredentialsHandle(&asServer.hcred); + xfree(pClientBuf); + xfree(pServerBuf); + + return fResult; +} Index: squid/src/cache_cf.c diff -u squid/src/cache_cf.c:1.38.6.11 squid/src/cache_cf.c:1.38.6.2.2.9 --- squid/src/cache_cf.c:1.38.6.11 Thu Feb 6 19:16:11 2003 +++ squid/src/cache_cf.c Mon May 12 11:31:42 2003 @@ -243,7 +243,7 @@ if ((fp = fopen(file_name, "r")) == NULL) fatalf("Unable to open configuration file: %s: %s", file_name, xstrerror()); -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(fileno(fp), O_TEXT); #endif cfg_filename = file_name; Index: squid/src/cache_diff.c diff -u squid/src/cache_diff.c:1.6 squid/src/cache_diff.c:1.6.70.1 --- squid/src/cache_diff.c:1.6 Fri Jan 12 00:20:32 2001 +++ squid/src/cache_diff.c Wed Feb 27 11:44:05 2002 @@ -137,7 +137,7 @@ fprintf(stderr, "cannot open %s: %s\n", fname, strerror(errno)); return 0; } -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(fileno(file), O_BINARY); #endif scanned_count = cacheIndexScan(idx, fname, file); Index: squid/src/cf_gen.c diff -u squid/src/cf_gen.c:1.10.6.2 squid/src/cf_gen.c:1.10.10.3 --- squid/src/cf_gen.c:1.10.6.2 Thu Aug 22 05:30:59 2002 +++ squid/src/cf_gen.c Sat Aug 24 00:23:48 2002 @@ -66,7 +66,7 @@ #if HAVE_ASSERT_H #include #endif -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) #include #endif #if HAVE_FCNTL_H @@ -158,7 +158,7 @@ perror(input_filename); exit(1); } -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(fileno(fp), O_TEXT); #endif state = sSTART; @@ -345,7 +345,7 @@ perror(output_filename); exit(1); } -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(fileno(fp), O_TEXT); #endif fprintf(fp, @@ -370,7 +370,7 @@ perror(conf_filename); exit(1); } -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(fileno(fp), O_TEXT); #endif gen_conf(entries, fp); Index: squid/src/client.c diff -u squid/src/client.c:1.8.6.4 squid/src/client.c:1.8.10.5 --- squid/src/client.c:1.8.6.4 Thu Jan 9 03:34:33 2003 +++ squid/src/client.c Mon Feb 3 07:54:14 2003 @@ -224,7 +224,7 @@ xstrerror()); exit(-1); } -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(put_fd, O_BINARY); #endif fstat(put_fd, &sb); Index: squid/src/debug.c diff -u squid/src/debug.c:1.9 squid/src/debug.c:1.9.6.2 --- squid/src/debug.c:1.9 Tue Dec 18 05:38:47 2001 +++ squid/src/debug.c Sat Mar 23 08:27:29 2002 @@ -177,7 +177,7 @@ fflush(stderr); debug_log = stderr; } -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_CYGWIN_)||defined(_SQUID_MSWIN_) setmode(fileno(debug_log), O_TEXT); #endif } @@ -237,6 +237,14 @@ snprintf(to, MAXPATHLEN, "%s.%d", debug_log_file, i); rename(from, to); } +/* + * You can't rename open files on Microsoft "operating systems" + * so we close before renaming. + */ +#ifdef _SQUID_MSWIN_ + if (debug_log != stderr) + fclose(debug_log); +#endif /* Rotate the current log to .0 */ if (Config.Log.rotateNumber > 0) { snprintf(to, MAXPATHLEN, "%s.%d", debug_log_file, 0); Index: squid/src/defines.h diff -u squid/src/defines.h:1.15.6.3 squid/src/defines.h:1.15.8.5 --- squid/src/defines.h:1.15.6.3 Thu Aug 8 13:18:40 2002 +++ squid/src/defines.h Sat Aug 10 07:32:58 2002 @@ -298,6 +298,21 @@ #define O_BINARY 0 #endif +/* CygWin & Windows NT Port */ +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) +#define _WIN_SQUID_SERVICE_CONTROL_STOP SERVICE_CONTROL_STOP +#define _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN SERVICE_CONTROL_SHUTDOWN +#define _WIN_SQUID_SERVICE_CONTROL_INTERROGATE SERVICE_CONTROL_INTERROGATE +#define _WIN_SQUID_SERVICE_CONTROL_ROTATE 128 +#define _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE 129 +#define _WIN_SQUID_SERVICE_CONTROL_DEBUG 130 +#define _WIN_SQUID_SERVICE_CONTROL_INTERRUPT 131 +#define _WIN_SQUID_DEFAULT_SERVICE_NAME "SquidNT" +#define _WIN_SQUID_SERVICE_OPTION "--ntservice" +#define _WIN_SQUID_RUN_MODE_INTERACTIVE 0 +#define _WIN_SQUID_RUN_MODE_SERVICE 1 +#endif + /* * Macro to find file access mode */ Index: squid/src/globals.h diff -u squid/src/globals.h:1.14.6.3 squid/src/globals.h:1.14.10.4 --- squid/src/globals.h:1.14.6.3 Mon Jan 13 19:14:58 2003 +++ squid/src/globals.h Mon Feb 3 07:54:46 2003 @@ -162,6 +162,10 @@ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) extern unsigned int WIN32_OS_version; /* 0 */ extern char *WIN32_OS_string; /* NULL */ +extern char *WIN32_Service_name; /* NULL */ +extern char *WIN32_Command_Line; /* NULL */ +extern char *WIN32_Service_Command_Line; /* NULL */ +extern unsigned int WIN32_run_mode; /* _WIN_SQUID_RUN_MODE_INTERACTIVE */ #endif #if HAVE_SBRK extern void *sbrk_start; /* 0 */ Index: squid/src/main.c diff -u squid/src/main.c:1.28.6.10 squid/src/main.c:1.28.6.1.2.7 --- squid/src/main.c:1.28.6.10 Mon May 5 19:18:48 2003 +++ squid/src/main.c Mon May 12 11:31:45 2003 @@ -35,11 +35,26 @@ #include "squid.h" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +#include +#include +static int opt_install_service = FALSE; +static int opt_remove_service = FALSE; +static int opt_signal_service = FALSE; +static int opt_command_line = FALSE; +extern void WIN32_svcstatusupdate(DWORD); +void WINAPI WIN32_svcHandler(DWORD); +#endif + /* for error reporting from xmalloc and friends */ extern void (*failure_notify) (const char *); static int opt_send_signal = -1; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +static int opt_no_daemon = 1; +#else static int opt_no_daemon = 0; +#endif static int opt_parse_cfg_only = 0; static int httpPortNumOverride = 1; static int icpPortNumOverride = 1; /* Want to detect "-u 0" */ @@ -53,8 +68,6 @@ static void mainRotate(void); static void mainReconfigure(void); -static SIGHDLR rotate_logs; -static SIGHDLR reconfigure; #if ALARM_UPDATES_TIME static SIGHDLR time_tick; #endif @@ -83,15 +96,27 @@ usage(void) { fprintf(stderr, +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + "Usage: %s [-dhirsvzCDFRVYX] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n" +#else "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n" +#endif " -a port Specify HTTP port number (default: %d).\n" " -d level Write debugging to stderr also.\n" " -f file Use given config-file instead of\n" " %s\n" " -h Print help message.\n" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + " -i Installs as a Windows Service (see -n option).\n" +#endif " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n" " Parse configuration file, then send signal to \n" " running copy (except -k parse) and exit.\n" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + " -n name Specify Windows Service name to use for service operations\n" + " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n" + " -r Removes a Windows Service (see -n option).\n" +#endif " -s Enable logging to syslog.\n" " -u port Specify ICP port number (default: %d), disable with 0.\n" " -v Print version.\n" @@ -99,7 +124,12 @@ " -C Do not catch fatal signals.\n" " -D Disable initial DNS tests.\n" " -F Don't serve any requests until store is rebuilt.\n" +#if !(defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_))) " -N No daemon mode.\n" +#else + " -O options\n" + " Set Windows Service Command line options in Registry.\n" +#endif " -R Do not set REUSEADDR on port.\n" " -S Double-check swap during rebuild.\n" " -V Virtual host httpd-accelerator.\n" @@ -115,7 +145,11 @@ extern char *optarg; int c; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + while ((c = getopt(argc, argv, "CDFO:RSVYXa:d:f:hik:m::n:rsu:vz?")) != -1) { +#else while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) { +#endif switch (c) { case 'C': opt_catch_signals = 0; @@ -126,9 +160,16 @@ case 'F': opt_foreground_rebuild = 1; break; +#if !(defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_))) case 'N': opt_no_daemon = 1; break; +#else + case 'O': + opt_command_line = 1; + WIN32_Command_Line = xstrdup(optarg); + break; +#endif case 'R': opt_reuseaddr = 0; break; @@ -158,6 +199,11 @@ case 'h': usage(); break; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + case 'i': + opt_install_service = TRUE; + break; +#endif case 'k': if ((int) strlen(optarg) < 1) usage(); @@ -205,6 +251,16 @@ fatal("Need to configure --enable-xmalloc-debug-trace to use -m option"); #endif } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + case 'n': + xfree(WIN32_Service_name); + WIN32_Service_name = xstrdup(optarg); + opt_signal_service = TRUE; + break; + case 'r': + opt_remove_service = TRUE; + break; +#endif case 's': #if HAVE_SYSLOG opt_syslog_enable = 1; @@ -220,6 +276,9 @@ break; case 'v': printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + printf("Compiled as Windows System Service.\n"); +#endif exit(0); /* NOTREACHED */ case 'z': @@ -234,7 +293,7 @@ } /* ARGSUSED */ -static void +void rotate_logs(int sig) { do_rotate = 1; @@ -257,7 +316,7 @@ #endif /* ARGSUSED */ -static void +void reconfigure(int sig) { do_reconfigure = 1; @@ -427,9 +486,9 @@ setEffectiveUser(void) { leave_suid(); /* Run as non privilegied user */ -#ifdef _SQUID_OS2_ +#if defined(_SQUID_OS2_) || defined(_SQUID_MSWIN_) return; -#endif +#else if (geteuid() == 0) { debug(0, 0) ("Squid is not safe to run as root! If you must\n"); debug(0, 0) ("start Squid as root, then you must configure\n"); @@ -437,6 +496,7 @@ debug(0, 0) ("'cache_effective_user' option in the config file.\n"); fatal("Don't run Squid as root, set 'cache_effective_user'!"); } +#endif } static void @@ -490,6 +550,14 @@ debug(1, 0) ("Starting Squid Cache version %s for %s...\n", version_string, CONFIG_HOST_TYPE); +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string); + debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line); + } + else + debug(1, 0) ("Running on %s\n",WIN32_OS_string); +#endif debug(1, 1) ("Process ID %d\n", (int) getpid()); debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD); @@ -582,16 +650,19 @@ configured_once = 1; } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.c */ +void WINAPI +SquidMain(int argc, char **argv) +#else int main(int argc, char **argv) +#endif { int errcount = 0; int n; /* # of GC'd objects */ int loop_delay; mode_t oldmask; -#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) - int WIN32_init_err; -#endif #if HAVE_SBRK sbrk_start = sbrk(0); @@ -602,8 +673,16 @@ Squid_MaxFD = FD_SETSIZE; #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) - if ((WIN32_init_err = WIN32_Subsystem_Init())) - return WIN32_init_err; +#ifdef USE_WIN32_SERVICE + if (WIN32_Subsystem_Init(&argc, &argv)) + return; +#else + { + int WIN32_init_err; + if ((WIN32_init_err = WIN32_Subsystem_Init())) + return WIN32_init_err; + } +#endif #endif /* call mallopt() before anything else */ @@ -644,8 +723,26 @@ squid_start = current_time; failure_notify = fatal_dump; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_START_PENDING); +#endif mainParseOptions(argc, argv); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + if (opt_install_service) { + WIN32_InstallService(); + return; + } + if (opt_remove_service) { + WIN32_RemoveService(); + return; + } + if (opt_command_line) { + WIN32_SetServiceCommandLine(); + return; + } +#endif + /* parse configuration file * note: in "normal" case this used to be called from mainInitialize() */ { @@ -664,7 +761,11 @@ parse_err = parseConfigFile(ConfigFile); if (opt_parse_cfg_only) +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return parse_err; +#endif } if (-1 == opt_send_signal) if (checkRunningPid()) @@ -695,7 +796,11 @@ setEffectiveUser(); debug(0, 0) ("Creating Swap Directories\n"); storeCreateSwapDirectories(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return 0; +#endif } if (!opt_no_daemon) watch_child(argv); @@ -715,8 +820,15 @@ fd_open(1, FD_LOG, "stdout"); fd_open(2, FD_LOG, "stderr"); } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_START_PENDING); +#endif mainInitialize(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_RUNNING); +#endif + /* main loop */ for (;;) { if (do_reconfigure) { @@ -734,6 +846,9 @@ do_shutdown = 0; shutting_down = 1; serverConnectionsClose(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_STOP_PENDING); +#endif eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1); } eventRun(); @@ -764,7 +879,11 @@ } } /* NOTREACHED */ +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return 0; +#endif } static void @@ -774,6 +893,11 @@ debug_log = stderr; pid = readPidFile(); if (pid > 1) { +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + if (opt_signal_service) + WIN32_sendSignal(opt_send_signal); + else { +#endif if (kill(pid, opt_send_signal) && /* ignore permissions if just running check */ !(opt_send_signal == 0 && errno == EPERM)) { @@ -782,6 +906,9 @@ opt_send_signal, (int) pid, xstrerror()); exit(1); } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + } +#endif } else { fprintf(stderr, "%s: ERROR: No running copy\n", appname); exit(1); Index: squid/src/mime.c diff -u squid/src/mime.c:1.11.6.2 squid/src/mime.c:1.11.10.3 --- squid/src/mime.c:1.11.6.2 Sun Nov 10 14:44:13 2002 +++ squid/src/mime.c Mon Feb 3 07:54:53 2003 @@ -297,7 +297,7 @@ debug(25, 1) ("mimeInit: %s: %s\n", filename, xstrerror()); return; } -#if defined (_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(fileno(fp), O_TEXT); #endif mimeFreeMemory(); Index: squid/src/pinger.c diff -u squid/src/pinger.c:1.4 squid/src/pinger.c:1.4.70.1 --- squid/src/pinger.c:1.4 Fri Jan 12 00:20:33 2001 +++ squid/src/pinger.c Tue Oct 1 12:48:55 2002 @@ -37,19 +37,94 @@ #if USE_ICMP +/* Native Windows port doesn't have netinet support, so we emulate it. + At this time, Cygwin lacks icmp support in its include files, so we need + to use the native Windows port definitions. + */ + +#if !defined(_SQUID_MSWIN_) && !defined(_SQUID_CYGWIN_) + #include #include #include #include +#define PINGER_TIMEOUT 10 + +static int socket_from_squid = 0; +static int socket_to_squid = 1; + +#else /* _SQUID_MSWIN_ or _SQUID_CYGWIN_ */ + +#ifdef _SQUID_MSWIN_ + +#include +#include + +#define PINGER_TIMEOUT 5 + +static SOCKET socket_to_squid = -1; +#define socket_from_squid socket_to_squid + +typedef unsigned char u_int8_t; + +#else /* _SQUID_CYGWIN_ */ + +#include +#include +#include +#include + +#define PINGER_TIMEOUT 10 + +static int socket_from_squid = 0; +static int socket_to_squid = 1; + +#endif + +#define ICMP_ECHO 8 +#define ICMP_ECHOREPLY 0 + +typedef struct iphdr +{ + u_int8_t ip_vhl:4; /* Length of the header in dwords */ + u_int8_t version:4; /* Version of IP */ + u_int8_t tos; /* Type of service */ + u_int16_t total_len; /* Length of the packet in dwords */ + u_int16_t ident; /* unique identifier */ + u_int16_t flags; /* Flags */ + u_int8_t ip_ttl; /* Time to live */ + u_int8_t proto; /* Protocol number (TCP, UDP etc) */ + u_int16_t checksum; /* IP checksum */ + u_int32_t source_ip; + u_int32_t dest_ip; +} +iphdr; + +/* ICMP header */ +typedef struct icmphdr +{ + u_int8_t icmp_type; /* ICMP packet type */ + u_int8_t icmp_code; /* Type sub code */ + u_int16_t icmp_cksum; + u_int16_t icmp_id; + u_int16_t icmp_seq; + u_int32_t timestamp; /* not part of ICMP, but we need it */ +} +icmphdr; + +#endif /* _SQUID_MSWIN_ */ + #ifndef _SQUID_LINUX_ #ifndef _SQUID_CYGWIN_ +#ifndef _SQUID_MSWIN_ #define icmphdr icmp #define iphdr ip #endif #endif +#endif -#if defined (_SQUID_LINUX_) || defined (_SQUID_CYGWIN_) +#if defined (_SQUID_LINUX_) #ifdef icmp_id #undef icmp_id #endif @@ -123,6 +198,38 @@ pingerOpen(void) { struct protoent *proto = NULL; +#ifdef _SQUID_MSWIN_ + WSADATA wsaData; + WSAPROTOCOL_INFO wpi; + char buf[sizeof(wpi)]; + int x; + struct sockaddr_in PS; + + WSAStartup(2, &wsaData); + + getCurrentTime(); + _db_init(NULL, "ALL,1"); + setmode(0, O_BINARY); + setmode(1, O_BINARY); + x = read(0, buf, sizeof(wpi)); + if (x < sizeof(wpi)) { + getCurrentTime(); + debug(42, 0) ("pingerOpen: read: FD 0: %s\n", xstrerror()); + write(1, "ERR\n", 4); + exit(1); + } + xmemcpy(&wpi, buf, sizeof(wpi)); + + write(1, "OK\n", 3); + x = read(0, buf, sizeof(PS)); + if (x < sizeof(PS)) { + getCurrentTime(); + debug(42, 0) ("pingerOpen: read: FD 0: %s\n", xstrerror()); + write(1, "ERR\n", 4); + exit(1); + } + xmemcpy(&PS, buf, sizeof(PS)); +#endif if ((proto = getprotobyname("icmp")) == 0) { debug(42, 0) ("pingerOpen: unknown protocol: icmp\n"); exit(1); @@ -134,12 +241,50 @@ } icmp_ident = getpid() & 0xffff; debug(42, 0) ("pinger: ICMP socket opened\n"); +#ifdef _SQUID_MSWIN_ + socket_to_squid = + WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, + &wpi, 0, 0); + if (socket_to_squid == INVALID_SOCKET) { + getCurrentTime(); + debug(42, 0) ("pingerOpen: WSASocket: %s\n", xstrerror()); + write(1, "ERR\n", 4); + exit(1); + } + x = connect(socket_to_squid, (struct sockaddr *) &PS, sizeof(PS)); + if (SOCKET_ERROR == x) { + getCurrentTime(); + debug(42, 0) ("pingerOpen: connect: %s\n", xstrerror()); + write(1, "ERR\n", 4); + exit(1); + } + write(1, "OK\n", 3); + memset(buf, 0, sizeof(buf)); + x = recv(socket_to_squid, buf, sizeof(buf), 0); + if (x < 3) { + debug(42, 0) ("icmpOpen: recv: %s\n", xstrerror()); + exit(1); + } + x = send(socket_to_squid, buf, strlen(buf), 0); + if (x < 3 || strncmp("OK\n", buf, 3)) { + debug(42, 0) ("icmpOpen: recv: %s\n", xstrerror()); + exit(1); + } + + getCurrentTime(); + debug(42, 0) ("pinger: Squid socket opened\n"); +#endif } void pingerClose(void) { close(icmp_sock); +#ifdef _SQUID_MSWIN_ + shutdown(socket_to_squid, SD_BOTH); + close(socket_to_squid); + socket_to_squid = -1; +#endif icmp_sock = -1; icmp_ident = 0; } @@ -267,7 +412,7 @@ } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); - answer = ~sum; + answer = (unsigned short) ~sum; return (answer); } @@ -307,7 +452,7 @@ int n; int guess_size; memset(&pecho, '\0', sizeof(pecho)); - n = recv(0, (char *) &pecho, sizeof(pecho), 0); + n = recv(socket_from_squid, (char *) &pecho, sizeof(pecho), 0); if (n < 0) return n; if (0 == n) { @@ -334,7 +479,7 @@ pingerSendtoSquid(pingerReplyData * preply) { int len = sizeof(pingerReplyData) - MAX_PKT_SZ + preply->psize; - if (send(1, (char *) preply, len, 0) < 0) { + if (send(socket_to_squid, (char *) preply, len, 0) < 0) { debug(50, 0) ("pinger: send: %s\n", xstrerror()); exit(1); } @@ -366,9 +511,13 @@ * cevans - do this first. It grabs a raw socket. After this we can * drop privs */ + pingerOpen(); setgid(getgid()); setuid(getuid()); +#ifdef _SQUID_MSWIN_ + atexit(pingerClose); +#endif if ((t = getenv("SQUID_DEBUG"))) debug_args = xstrdup(t); @@ -376,25 +525,29 @@ _db_init(NULL, debug_args); for (;;) { - tv.tv_sec = 10; + tv.tv_sec = PINGER_TIMEOUT; tv.tv_usec = 0; FD_ZERO(&R); - FD_SET(0, &R); + FD_SET(socket_from_squid, &R); FD_SET(icmp_sock, &R); x = select(icmp_sock + 1, &R, NULL, NULL, &tv); getCurrentTime(); if (x < 0) exit(1); - if (FD_ISSET(0, &R)) + if (FD_ISSET(socket_from_squid, &R)) if (pingerReadRequest() < 0) { debug(42, 0) ("Pinger exiting.\n"); exit(1); } if (FD_ISSET(icmp_sock, &R)) pingerRecv(); - if (10 + last_check_time < squid_curtime) { - if (send(1, (char *) &tv, 0, 0) < 0) + if (PINGER_TIMEOUT + last_check_time < squid_curtime) { + if (send(socket_to_squid, (char *) &tv, 0, 0) < 0) { +#ifdef _SQUID_MSWIN_ + debug(42, 0) ("Pinger exiting.\n"); +#endif exit(1); + } last_check_time = squid_curtime; } } Index: squid/src/protos.h diff -u squid/src/protos.h:1.41.6.14 squid/src/protos.h:1.41.6.3.2.11 --- squid/src/protos.h:1.41.6.14 Tue May 6 20:20:03 2003 +++ squid/src/protos.h Mon May 12 11:31:45 2003 @@ -787,6 +787,8 @@ extern void serverConnectionsClose(void); extern void shut_down(int); +extern void rotate_logs(int); +extern void reconfigure(int); extern void start_announce(void *unused); @@ -1328,8 +1330,17 @@ /* CygWin & Windows NT Port */ /* win32.c */ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) +#ifdef USE_WIN32_SERVICE +extern int WIN32_Subsystem_Init(int *, char ***); +#else extern int WIN32_Subsystem_Init(void); +#endif +extern void WIN32_sendSignal(int); +extern void WIN32_Abort(int); extern void WIN32_Exit(void); +extern void WIN32_SetServiceCommandLine(void); +extern void WIN32_InstallService(void); +extern void WIN32_RemoveService(void); #endif /* external_acl.c */ Index: squid/src/squid.h diff -u squid/src/squid.h:1.13.6.6 squid/src/squid.h:1.13.6.2.2.3 --- squid/src/squid.h:1.13.6.6 Sun Mar 9 19:23:44 2003 +++ squid/src/squid.h Mon May 12 11:31:46 2003 @@ -208,7 +208,7 @@ #if HAVE_LIMITS_H #include #endif -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) #include #endif Index: squid/src/stat.c diff -u squid/src/stat.c:1.13.6.7 squid/src/stat.c:1.13.8.3 --- squid/src/stat.c:1.13.6.7 Mon Jan 27 19:17:36 2003 +++ squid/src/stat.c Mon Feb 3 07:55:20 2003 @@ -459,6 +459,15 @@ runtime = 1.0; storeAppendPrintf(sentry, "Squid Object Cache: Version %s\n", version_string); +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + storeAppendPrintf(sentry,"\nRunning as %s Windows System Service on %s\n", + WIN32_Service_name, WIN32_OS_string); + storeAppendPrintf(sentry,"Service command line is: %s\n", WIN32_Service_Command_Line); + } + else + storeAppendPrintf(sentry,"Running on %s\n",WIN32_OS_string); +#endif storeAppendPrintf(sentry, "Start Time:\t%s\n", mkrfc1123(squid_start.tv_sec)); storeAppendPrintf(sentry, "Current Time:\t%s\n", Index: squid/src/tools.c diff -u squid/src/tools.c:1.19.6.5 squid/src/tools.c:1.19.10.5 --- squid/src/tools.c:1.19.6.5 Tue Apr 29 19:19:26 2003 +++ squid/src/tools.c Mon May 12 11:31:47 2003 @@ -926,6 +926,9 @@ xrename(const char *from, const char *to) { debug(21, 2) ("xrename: renaming %s to %s\n", from, to); +#ifdef _SQUID_MSWIN_ + remove(to); +#endif if (0 == rename(from, to)) return 0; debug(21, errno == ENOENT ? 2 : 1) ("xrename: Cannot rename %s to %s: %s\n", Index: squid/src/win32.c diff -u squid/src/win32.c:1.5.6.1 squid/src/win32.c:1.5.10.3 --- squid/src/win32.c:1.5.6.1 Wed Jun 26 13:45:14 2002 +++ squid/src/win32.c Tue Jul 16 05:06:49 2002 @@ -6,34 +6,219 @@ * * (C) 2001 Guido Serassio , * inspired by previous work by Romeo Anghelache & Eric Stern. - * 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. + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * 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. + * 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 WIN32_C +#define WIN32_C + #include "squid.h" /* This code compiles only CygWin & Windows NT Port */ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) #include +#ifdef _SQUID_MSWIN_ +#if HAVE_WIN32_PSAPI +#include +#endif +#include +#endif static unsigned int GetOSVersion(); +void WIN32_svcstatusupdate(DWORD); +void WINAPI WIN32_svcHandler(DWORD); +static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int); +static int WIN32_create_key(void); +static void WIN32_build_argv (char *); +void WINAPI SquidMain(DWORD, char **); + +/* The following code section is part of an EXPERIMENTAL native */ +/* Windows NT/2000 Squid port - Compiles only on MS Visual C++ */ +#if defined(_SQUID_MSWIN_) +static int Win32SockInit(void); +static void Win32SockCleanup(void); +LPCRITICAL_SECTION dbg_mutex = NULL; +#endif /* End native Windows NT EXPERIMENTAL PORT */ + +static SERVICE_STATUS svcStatus; +static SERVICE_STATUS_HANDLE svcHandle; +static int WIN32_argc; +static char ** WIN32_argv; +static char * WIN32_module_name; + +#define VENDOR "GNU" +#if defined(_SQUID_MSWIN_) +#define SOFTWARENAME "SquidNT" +#else +#define SOFTWARENAME "Squid" +#endif +#define WIN32_VERSION "2.5" +#define COMMANDLINE "CommandLine" +#define CONFIGFILE "ConfigFile" +#undef ChangeServiceConfig2 +typedef BOOL (WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID); +#ifdef UNICODE +#define CHANGESERVICECONFIG2 "ChangeServiceConfig2W" +#else +#define CHANGESERVICECONFIG2 "ChangeServiceConfig2A" +#endif +static SC_ACTION Squid_SCAction[] = { { SC_ACTION_RESTART, 60000 } }; +static SERVICE_DESCRIPTION Squid_ServiceDescription = { SOFTWARENAME " " VERSION " WWW Proxy Server" }; +static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = { 0, NULL, NULL, 1, Squid_SCAction }; +static char REGKEY[256]="SOFTWARE\\"VENDOR"\\"SOFTWARENAME"\\"WIN32_VERSION"\\"; +static char *keys[] = { + "SOFTWARE", /* key[0] */ + VENDOR, /* key[1] */ + SOFTWARENAME, /* key[2] */ + WIN32_VERSION, /* key[3] */ + NULL, /* key[4] */ + NULL /* key[5] */ +}; /* ====================================================================== */ /* LOCAL FUNCTIONS */ /* ====================================================================== */ +static int +WIN32_create_key(void) +{ + int index; + HKEY hKey; + HKEY hKeyNext; + int retval; + LONG rv; + + hKey = HKEY_LOCAL_MACHINE; + index = 0; + retval = 0; + + /* Walk the tree, creating at each stage if necessary */ + while (keys[index]) { + unsigned long result; + rv = RegCreateKeyEx(hKey, keys[index], /* subkey */ + 0, /* reserved */ + NULL, /* class */ + REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyNext, &result); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCreateKeyEx(%s),%d\n", keys[index], (int) rv); + retval = -4; + } + /* Close the old key */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCloseKey %d\n", (int) rv); + if (retval == 0) { + /* Keep error status from RegCreateKeyEx, if any */ + retval = -4; + } + } + if (retval) { + break; + } + hKey = hKeyNext; + index++; + } + if (keys[index] == NULL) { + /* Close the final key we opened, if we walked the entire + * tree + */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCloseKey %d\n", (int) rv); + if (retval == 0) { + /* Keep error status from RegCreateKeyEx, if any */ + retval = -4; + } + } + } + return retval; +} + +static int +WIN32_StoreKey(const char *key, DWORD type, unsigned char *value, + int value_size) +{ + LONG rv; + HKEY hKey; + int retval; + + rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey); + if (rv == ERROR_FILE_NOT_FOUND) { + /* Key could not be opened -- try to create it + */ + if (WIN32_create_key() < 0) { + /* Creation failed (error already reported) */ + return -4; + } + /* Now it has been created we should be able to open it + */ + rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey); + if (rv == ERROR_FILE_NOT_FOUND) { + debug(1, 1) ("Registry does not contain key %s after creation", + REGKEY); + return -1; + } + } + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, (int) rv); + return -4; + } + /* Now set the value and data */ + rv = RegSetValueEx(hKey, key, /* value key name */ + 0, /* reserved */ + type, /* type */ + value, /* value data */ + (DWORD) value_size); /* for size of "value" */ + retval = 0; /* Return value */ + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegQueryValueEx(key %s),%d\n", key, (int) rv); + retval = -4; + } else { + debug(1, 1) ("Registry stored HKLM\\%s\\%s value %s\n", + REGKEY, + key, + type == REG_SZ ? value : (unsigned char *) "(not displayable)"); + } + /* Make sure we close the key even if there was an error storing + * the data + */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCloseKey HKLM\\%s, %d\n", REGKEY, (int) rv); + if (retval == 0) { + /* Keep error status from RegQueryValueEx, if any */ + retval = -4; + } + } + return retval; +} + static unsigned int GetOSVersion() { @@ -87,24 +272,554 @@ return _WIN_OS_UNKNOWN; } +/* Build argv, argc from string passed from Windows. */ +static void WIN32_build_argv(char *cmd) +{ + int argvlen = 0; + char *word; + + WIN32_argc = 1; + WIN32_argv = (char **) xmalloc ((WIN32_argc+1) * sizeof (char *)); + WIN32_argv[0]=xstrdup(WIN32_module_name); +/* Scan command line until there is nothing left. */ + while (*cmd) { + /* Ignore spaces */ + if (xisspace(*cmd)) { + cmd++; + continue; + } + /* Found the beginning of an argument. */ + word = cmd; + while (*cmd) { + cmd++; /* Skip over this character */ + if (xisspace(*cmd)) /* End of argument if space */ + break; + } + if (*cmd) + *cmd++ = '\0'; /* Terminate `word' */ + /* See if we need to allocate more space for argv */ + if (WIN32_argc >= argvlen) { + argvlen = WIN32_argc + 1; + WIN32_argv = (char **) xrealloc (WIN32_argv, (1 + argvlen) * sizeof (char *)); + } + /* Add word to argv file. */ + WIN32_argv[WIN32_argc++] = word; + } + WIN32_argv[WIN32_argc] = NULL; +} + /* ====================================================================== */ /* PUBLIC FUNCTIONS */ /* ====================================================================== */ void +WIN32_Abort(int sig) +{ +#ifdef USE_WIN32_SERVICE + svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + svcStatus.dwServiceSpecificExitCode = 1; +#endif + WIN32_Exit(); +} + +void WIN32_Exit() { +#ifdef _SQUID_MSWIN_ + Win32SockCleanup(); +#endif +#ifdef USE_WIN32_SERVICE + svcStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(svcHandle, &svcStatus); +#endif +#ifdef _SQUID_MSWIN_ + if (dbg_mutex) + DeleteCriticalSection(dbg_mutex); +#endif _exit(0); } -int -WIN32_Subsystem_Init() +#ifdef USE_WIN32_SERVICE +int WIN32_Subsystem_Init(int * argc, char *** argv) +#else +int WIN32_Subsystem_Init() +#endif { WIN32_OS_version = GetOSVersion(); if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S)) return 1; if (atexit(WIN32_Exit) != 0) return 1; +#ifdef USE_WIN32_SERVICE + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + char path[512]; + HKEY hndKey; + if (signal(SIGABRT, WIN32_Abort) == SIG_ERR) + return 1; + /* Register the service Handler function */ + svcHandle = + RegisterServiceCtrlHandler(WIN32_Service_name, + WIN32_svcHandler); + if (svcHandle == 0) + return 1; + /* Set Process work dir to directory cointaining squid.exe */ + GetModuleFileName(NULL, path, 512); + WIN32_module_name=xstrdup(path); + path[strlen(path) - 10] = '\0'; + if (SetCurrentDirectory(path) == 0) + return 1; + safe_free(ConfigFile); + /* get config file from Windows Registry */ + if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY, &hndKey) == ERROR_SUCCESS) { + DWORD Type = 0; + DWORD Size = 0; + LONG Result; + Result = + RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size); + if (Result == ERROR_SUCCESS && Size) { + ConfigFile = xmalloc(Size); + RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, ConfigFile, + &Size); + } else + ConfigFile = xstrdup(DefaultConfigFile); + Size = 0; + Type = 0; + Result = + RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size); + if (Result == ERROR_SUCCESS && Size) { + WIN32_Service_Command_Line = xmalloc(Size); + RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, WIN32_Service_Command_Line, + &Size); + } else + WIN32_Service_Command_Line = xstrdup(""); + RegCloseKey(hndKey); + } else { + ConfigFile = xstrdup(DefaultConfigFile); + WIN32_Service_Command_Line = xstrdup(""); + } + WIN32_build_argv(WIN32_Service_Command_Line); + *argc = WIN32_argc; + *argv = WIN32_argv; + /* Set Service Status to SERVICE_START_PENDING */ + svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + svcStatus.dwCurrentState = SERVICE_START_PENDING; + svcStatus.dwControlsAccepted = + SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + svcStatus.dwWin32ExitCode = 0; + svcStatus.dwServiceSpecificExitCode = 0; + svcStatus.dwCheckPoint = 0; + svcStatus.dwWaitHint = 10000; + SetServiceStatus(svcHandle, &svcStatus); +#ifdef _SQUID_MSWIN_ + _setmaxstdio(Squid_MaxFD); +#endif + } +#endif +#ifdef _SQUID_MSWIN_ + Win32SockInit(); +#endif + return 0; +} + +#ifdef USE_WIN32_SERVICE +void +WIN32_svcstatusupdate(DWORD svcstate) +{ + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + svcStatus.dwCheckPoint++; + svcStatus.dwCurrentState = svcstate; + SetServiceStatus(svcHandle, &svcStatus); + } +} + +VOID WINAPI +WIN32_svcHandler(DWORD Opcode) +{ + DWORD status; + + switch (Opcode) { + case _WIN_SQUID_SERVICE_CONTROL_STOP: + case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN: +/* Do whatever it takes to stop here. */ + svcStatus.dwWin32ExitCode = 0; + svcStatus.dwCurrentState = SERVICE_STOP_PENDING; + svcStatus.dwCheckPoint = 0; + svcStatus.dwWaitHint = 10000; + shut_down(SIGTERM); + if (!SetServiceStatus(svcHandle, &svcStatus)) { + status = GetLastError(); + debug(1, 1) (" SetServiceStatus error %ld\n", status); + } + debug(1, 1) ("Leaving Squid service \n"); + return; + case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE: +/* Fall through to send current status. */ + if (!SetServiceStatus(svcHandle, &svcStatus)) { + status = GetLastError(); + debug(1, 1) (" SetServiceStatus error %ld\n", status); + } + break; + case _WIN_SQUID_SERVICE_CONTROL_ROTATE: + rotate_logs(SIGUSR1); + break; + case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE: + reconfigure(SIGHUP); + break; + case _WIN_SQUID_SERVICE_CONTROL_DEBUG: + sigusr2_handle(SIGUSR2); + break; + case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT: +/* Do whatever it takes to stop here. */ + svcStatus.dwWin32ExitCode = 0; + svcStatus.dwCurrentState = SERVICE_STOP_PENDING; + svcStatus.dwCheckPoint = 0; + svcStatus.dwWaitHint = 10000; + shut_down(SIGINT); + if (!SetServiceStatus(svcHandle, &svcStatus)) { + status = GetLastError(); + debug(1, 1) (" SetServiceStatus error %ld\n", status); + } + debug(1, 1) ("Leaving Squid service \n"); + break; + default: + debug(1, 1) ("Unrecognized opcode %ld\n", Opcode); + } + return; +} + +void +WIN32_RemoveService() +{ + SC_HANDLE schService; + SC_HANDLE schSCManager; + + if (!WIN32_Service_name) + WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); + strcat(REGKEY, WIN32_Service_name); + keys[4] = WIN32_Service_name; + schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ + NULL, /* database (NULL == default) */ + SC_MANAGER_ALL_ACCESS /* access required */ + ); + if (!schSCManager) + debug(1, 1) ("OpenSCManager failed"); + else { + schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS); + if (schService == NULL) + debug(1, 1) ("OpenService failed"); + /* Could not open the service */ + else { + /* try to stop the service */ + if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP, + &svcStatus)) { + sleep(1); + while (QueryServiceStatus(schService, &svcStatus)) { + if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) + sleep(1); + else + break; + } + } + /* now remove the service */ + if (DeleteService(schService) == 0) + fprintf(stderr,"DeleteService failed.\n"); + else + printf("Service %s deleted successfully.\n", + WIN32_Service_name); + CloseServiceHandle(schService); + } + CloseServiceHandle(schSCManager); + } +} + +void +WIN32_SetServiceCommandLine() +{ + if (!WIN32_Service_name) + WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); + strcat(REGKEY, WIN32_Service_name); + keys[4] = WIN32_Service_name; + /* Now store the Service Command Line in the registry */ + WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1); +} + +void +WIN32_InstallService() +{ + SC_HANDLE schService; + SC_HANDLE schSCManager; + char ServicePath[512]; + char szPath[512]; + int lenpath; + + if (!WIN32_Service_name) + WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); + strcat(REGKEY, WIN32_Service_name); + keys[4] = WIN32_Service_name; + if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) { + debug(1, 1) ("Can't get executable path"); + exit(1); + } + snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, WIN32_Service_name); + schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ + NULL, /* database (NULL == default) */ + SC_MANAGER_ALL_ACCESS /* access required */ + ); + if (!schSCManager) { + debug(1, 1) ("OpenSCManager failed"); + exit(1); + } + else { + schService = CreateService(schSCManager, /* SCManager database */ + WIN32_Service_name, /* name of service */ + WIN32_Service_name, /* name to display */ + SERVICE_ALL_ACCESS, /* desired access */ + SERVICE_WIN32_OWN_PROCESS, /* service type */ + SERVICE_AUTO_START, /* start type */ + SERVICE_ERROR_NORMAL, /* error control type */ + (const char *) szPath, /* service's binary */ + NULL, /* no load ordering group */ + NULL, /* no tag identifier */ + "Tcpip\0AFD\0", /* dependencies */ + NULL, /* LocalSystem account */ + NULL); /* no password */ + if (schService) { + if ((WIN32_OS_version == _WIN_OS_WIN2K) || (WIN32_OS_version == _WIN_OS_WINXP) + || (WIN32_OS_version == _WIN_OS_WINNET)) + { + HMODULE ADVAPI32Handle; + PFChangeServiceConfig2 ChangeServiceConfig2; + DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION; + + ADVAPI32Handle = GetModuleHandle("advapi32"); + ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2); + ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription); + dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS; + ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions); + } + CloseServiceHandle(schService); + /* Now store the config file location in the registry */ + if (!ConfigFile) + ConfigFile = xstrdup(DefaultConfigFile); + WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1); + printf("Squid Cache version %s for %s\n", version_string, + CONFIG_HOST_TYPE); + printf("installed successfully as %s Windows System Service.\n", + WIN32_Service_name); + printf + ("To run, start it from the Services Applet of Control Panel.\n"); + printf("Don't forget to edit squid.conf before starting it.\n\n"); + } else { + debug(1, 1) ("CreateService failed"); + exit(1); + } + CloseServiceHandle(schSCManager); + } +} + +void +WIN32_sendSignal(int WIN32_signal) +{ + SERVICE_STATUS ssStatus; + DWORD fdwAccess, fdwControl; + SC_HANDLE schService; + SC_HANDLE schSCManager; + + if (!WIN32_Service_name) + WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); + schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ + NULL, /* database (NULL == default) */ + SC_MANAGER_ALL_ACCESS /* access required */ + ); + if (!schSCManager) { + debug(1, 1) ("OpenSCManager failed"); + exit(1); + } + /* The required service object access depends on the control. */ + switch (WIN32_signal) { + case 0: /* SIGNULL */ + fdwAccess = SERVICE_INTERROGATE; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE; + break; + case SIGUSR1: + fdwAccess = SERVICE_USER_DEFINED_CONTROL; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE; + break; + case SIGUSR2: + fdwAccess = SERVICE_USER_DEFINED_CONTROL; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG; + break; + case SIGHUP: + fdwAccess = SERVICE_USER_DEFINED_CONTROL; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE; + break; + case SIGTERM: + fdwAccess = SERVICE_STOP; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP; + break; + case SIGINT: + case SIGKILL: + fdwAccess = SERVICE_USER_DEFINED_CONTROL; + fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT; + break; + default: + exit(1); + } + /* Open a handle to the service. */ + schService = OpenService(schSCManager, /* SCManager database */ + WIN32_Service_name, /* name of service */ + fdwAccess); /* specify access */ + if (schService == NULL) { + fprintf(stderr, "%s: ERROR: Could not open Service %s\n", appname, + WIN32_Service_name); + exit(1); + } else { + /* Send a control value to the service. */ + if (!ControlService(schService, /* handle of service */ + fdwControl, /* control value to send */ + &ssStatus)) { /* address of status info */ + fprintf(stderr, "%s: ERROR: Could not Control Service %s\n", + appname, WIN32_Service_name); + exit(1); + } else { + /* Print the service status. */ + printf("\nStatus of %s Service:\n", WIN32_Service_name); + printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType); + printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState); + printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted); + printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode); + printf(" Service Specific Exit Code: %ld\n", + ssStatus.dwServiceSpecificExitCode); + printf(" Check Point: %ld\n", ssStatus.dwCheckPoint); + printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint); + } + CloseServiceHandle(schService); + } + CloseServiceHandle(schSCManager); +} + +int main(int argc, char **argv) +{ + SERVICE_TABLE_ENTRY DispatchTable[] = { + {NULL, SquidMain}, + {NULL, NULL} + }; + char *c; + + if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)){ + WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE; + if (!(c=strchr(argv[1],':'))){ + fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]); + return 1; + } + WIN32_Service_name = xstrdup(c+1); + DispatchTable[0].lpServiceName=WIN32_Service_name; + strcat(REGKEY, WIN32_Service_name); + keys[4] = WIN32_Service_name; + if (!StartServiceCtrlDispatcher(DispatchTable)) { + fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n", + GetLastError()); + return 1; + } + } else { + WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE; + SquidMain(argc, argv); + } return 0; } #endif + +/* The following code section is part of an EXPERIMENTAL native */ +/* Windows NT/2000 Squid port - Compiles only on MS Visual C++ */ + +#if defined(_SQUID_MSWIN_) +static int s_iInitCount = 0; + +int WIN32_getrusage(int who, struct rusage *usage) +{ +#if HAVE_WIN32_PSAPI + if ((WIN32_OS_version == _WIN_OS_WINNT) || (WIN32_OS_version == _WIN_OS_WIN2K) + || (WIN32_OS_version == _WIN_OS_WINXP) || (WIN32_OS_version == _WIN_OS_WINNET)) + { + /* On Windows NT/2000 call PSAPI.DLL for process Memory */ + /* informations -- Guido Serassio */ + HANDLE hProcess; + PROCESS_MEMORY_COUNTERS pmc; + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | + PROCESS_VM_READ, + FALSE, GetCurrentProcessId()); + { + /* Microsoft Visual C++ doesn't have getrusage function, */ + /* so we get process CPU time information from PSAPI.DLL. */ + FILETIME ftCreate, ftExit, ftKernel, ftUser; + if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) + { + LONGLONG tUser64 = (*(LONGLONG *)&ftUser / 10); + LONGLONG tKernel64 = (*(LONGLONG *)&ftKernel / 10); + usage->ru_utime.tv_sec =(long)(tUser64 / 1000000); + usage->ru_stime.tv_sec =(long)(tKernel64 / 1000000); + usage->ru_utime.tv_usec =(long)(tUser64 % 1000000); + usage->ru_stime.tv_usec =(long)(tKernel64 % 1000000); + } + else + { + CloseHandle( hProcess ); + return -1; + } + } + if (GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) + { + usage->ru_maxrss=(DWORD)(pmc.WorkingSetSize /1024); + usage->ru_majflt=pmc.PageFaultCount; + } + else + { + CloseHandle( hProcess ); + return -1; + } + CloseHandle( hProcess ); + } +#endif + return 0; +} + +static int Win32SockInit(void) +{ + int iVersionRequested; + WSADATA wsaData; + int err; + + if (s_iInitCount > 0) { + s_iInitCount++; + return (0); + } + else if (s_iInitCount < 0) + return (s_iInitCount); + /* s_iInitCount == 0. Do the initailization */ + iVersionRequested = MAKEWORD(2, 0); + err = WSAStartup((WORD) iVersionRequested, &wsaData); + if (err) { + s_iInitCount = -1; + return (s_iInitCount); + } + if (LOBYTE(wsaData.wVersion) != 2 || + HIBYTE(wsaData.wVersion) != 0) { + s_iInitCount = -2; + WSACleanup(); + return (s_iInitCount); + } + debug(1,1)("Windows sockets initialised"); + s_iInitCount++; + return (s_iInitCount); +} + +static void Win32SockCleanup(void) +{ + if (--s_iInitCount == 0) + WSACleanup(); + return; +} +#endif /* End native Windows NT EXPERIMENTAL PORT */ +#endif + +#endif /* WIN32_C */ Index: squid/src/fs/aufs/store_dir_aufs.c diff -u squid/src/fs/aufs/store_dir_aufs.c:1.23.6.7 squid/src/fs/aufs/store_dir_aufs.c:1.23.6.1.2.6 --- squid/src/fs/aufs/store_dir_aufs.c:1.23.6.7 Thu Jan 9 03:34:34 2003 +++ squid/src/fs/aufs/store_dir_aufs.c Mon Feb 3 07:56:14 2003 @@ -918,7 +918,7 @@ debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); fatal("Failed to open swap log for reading"); } -#if defined(_SQUID_CYGWIN_) +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) setmode(fileno(fp), O_BINARY); #endif memset(&clean_sb, '\0', sizeof(struct stat)); Index: squid/src/fs/ufs/store_dir_ufs.c diff -u squid/src/fs/ufs/store_dir_ufs.c:1.21.6.7 squid/src/fs/ufs/store_dir_ufs.c:1.21.6.1.2.8 --- squid/src/fs/ufs/store_dir_ufs.c:1.21.6.7 Thu Jan 9 03:34:35 2003 +++ squid/src/fs/ufs/store_dir_ufs.c Mon Feb 3 07:56:26 2003 @@ -466,9 +466,9 @@ tmpe.hash.key = key; /* check sizes */ if (tmpe.swap_file_sz == 0) { - tmpe.swap_file_sz = sb.st_size; + tmpe.swap_file_sz = (size_t) sb.st_size; } else if (tmpe.swap_file_sz == sb.st_size - swap_hdr_len) { - tmpe.swap_file_sz = sb.st_size; + tmpe.swap_file_sz = (size_t) sb.st_size; } else if (tmpe.swap_file_sz != sb.st_size) { debug(47, 1) ("storeUfsDirRebuildFromDirectory: SIZE MISMATCH %ld!=%ld\n", (long int) tmpe.swap_file_sz, (long int) sb.st_size); @@ -861,7 +861,7 @@ char *new_path = xstrdup(storeUfsDirSwapLogFile(sd, ".new")); int fd; file_close(ufsinfo->swaplog_fd); -#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) +#if defined (_SQUID_OS2_) || defined (_SQUID_CYGWIN_) || defined (_SQUID_MSWIN_) if (unlink(swaplog_path) < 0) { debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); fatal("storeUfsDirCloseTmpSwapLog: unlink failed"); @@ -911,14 +911,11 @@ } ufsinfo->swaplog_fd = fd; /* open a read-only stream of the old log */ - fp = fopen(swaplog_path, "r"); + fp = fopen(swaplog_path, "rb"); if (fp == NULL) { debug(50, 0) ("%s: %s\n", swaplog_path, xstrerror()); fatal("Failed to open swap log for reading"); } -#if defined(_SQUID_CYGWIN_) - setmode(fileno(fp), O_BINARY); -#endif memset(&clean_sb, '\0', sizeof(struct stat)); if (stat(clean_path, &clean_sb) < 0) *clean_flag = 0; @@ -1064,7 +1061,7 @@ fd = state->fd; /* rename */ if (state->fd >= 0) { -#if defined(_SQUID_OS2_) || defined (_SQUID_CYGWIN_) +#if defined(_SQUID_OS2_) || defined(_SQUID_CYGWIN_) || defined(_SQUID_MSWIN_) file_close(state->fd); state->fd = -1; if (unlink(state->cur) < 0)