]> git.ipfire.org Git - thirdparty/squid.git/blame - src/WinSvc.cc
Move ASN handling for ACL into ACL area.
[thirdparty/squid.git] / src / WinSvc.cc
CommitLineData
9c8434f6 1
2/*
262a0e14 3 * $Id$
9c8434f6 4 *
5 * Windows support
6 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
7 * inspired by previous work by Romeo Anghelache & Eric Stern.
8 *
9 * SQUID Web Proxy Cache http://www.squid-cache.org/
10 * ----------------------------------------------------------
11 *
12 * Squid is the result of efforts by numerous individuals from
13 * the Internet community; see the CONTRIBUTORS file for full
14 * details. Many organizations have provided support for Squid's
15 * development; see the SPONSORS file for full details. Squid is
16 * Copyrighted (C) 2001 by the Regents of the University of
17 * California; see the COPYRIGHT file for full details. Squid
18 * incorporates software developed and/or copyrighted by other
19 * sources; see the CREDITS file for full details.
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
26ac0430 25 *
9c8434f6 26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
26ac0430 30 *
9c8434f6 31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 *
35 */
36
37#include "squid.h"
38#include "squid_windows.h"
39
40#ifdef _SQUID_MSWIN_
41#ifndef _MSWSOCK_
42#include <mswsock.h>
43#endif
44#include <process.h>
45#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
46#include <crtdbg.h>
47#endif
48#endif
49
50static unsigned int GetOSVersion();
51void WIN32_svcstatusupdate(DWORD, DWORD);
52void WINAPI WIN32_svcHandler(DWORD);
53#if USE_WIN32_SERVICE
54static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int);
55static int WIN32_create_key(void);
56static void WIN32_build_argv (char *);
57#endif
58extern "C" void WINAPI SquidWinSvcMain(DWORD, char **);
59
60#if defined(_SQUID_MSWIN_)
61#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
62void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
63#endif
64static int Win32SockInit(void);
65static void Win32SockCleanup(void);
66SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex;
67void WIN32_ExceptionHandlerCleanup(void);
68static int s_iInitCount = 0;
353942c5
AJ
69static HANDLE NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
70#endif /* _SQUID_MSWIN_ */
9c8434f6 71
72static int Squid_Aborting = 0;
babd1fd5 73
74#undef NotifyAddrChange
75typedef DWORD(WINAPI * PFNotifyAddrChange) (OUT PHANDLE, IN LPOVERLAPPED);
76#define NOTIFYADDRCHANGE "NotifyAddrChange"
9c8434f6 77
78#if USE_WIN32_SERVICE
79static SERVICE_STATUS svcStatus;
80static SERVICE_STATUS_HANDLE svcHandle;
81static int WIN32_argc;
82static char ** WIN32_argv;
83static char * WIN32_module_name;
84
d2b4d181 85#define VENDOR "squid-cache.org"
9c8434f6 86static char VENDORString[] = VENDOR;
d2b4d181 87#define SOFTWARENAME PACKAGE_NAME
9c8434f6 88static char SOFTWARENAMEString[] = SOFTWARENAME;
9c8434f6 89#define SOFTWARE "SOFTWARE"
90static char SOFTWAREString[] = SOFTWARE;
91#define COMMANDLINE "CommandLine"
92#define CONFIGFILE "ConfigFile"
93#undef ChangeServiceConfig2
94typedef BOOL (WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID);
95#ifdef UNICODE
96#define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
97#else
98#define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
99#endif
100static SC_ACTION Squid_SCAction[] = { { SC_ACTION_RESTART, 60000 } };
101static char Squid_ServiceDescriptionString[] = SOFTWARENAME " " VERSION " WWW Proxy Server";
102static SERVICE_DESCRIPTION Squid_ServiceDescription = { Squid_ServiceDescriptionString };
103static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = { INFINITE, NULL, NULL, 1, Squid_SCAction };
d2b4d181 104static char REGKEY[256]=SOFTWARE"\\"VENDOR"\\"SOFTWARENAME"\\";
9c8434f6 105static char *keys[] = {
26ac0430
AJ
106 SOFTWAREString, /* key[0] */
107 VENDORString, /* key[1] */
108 SOFTWARENAMEString, /* key[2] */
d2b4d181
GS
109 NULL, /* key[3] */
110 NULL /* key[4] */
26ac0430 111};
9c8434f6 112#endif
113
114/* ====================================================================== */
115/* LOCAL FUNCTIONS */
116/* ====================================================================== */
117
118#if USE_WIN32_SERVICE
119static int
120WIN32_create_key(void)
121{
122 int index;
123 HKEY hKey;
124 HKEY hKeyNext;
125 int retval;
126 LONG rv;
127
128 hKey = HKEY_LOCAL_MACHINE;
129 index = 0;
130 retval = 0;
131
132 /* Walk the tree, creating at each stage if necessary */
133
134 while (keys[index]) {
135 unsigned long result;
136 rv = RegCreateKeyEx(hKey, keys[index], /* subkey */
137 0, /* reserved */
138 NULL, /* class */
139 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyNext, &result);
140
141 if (rv != ERROR_SUCCESS) {
142 fprintf(stderr, "RegCreateKeyEx(%s),%d\n", keys[index], (int) rv);
143 retval = -4;
144 }
145
146 /* Close the old key */
147 rv = RegCloseKey(hKey);
148
149 if (rv != ERROR_SUCCESS) {
150 fprintf(stderr, "RegCloseKey %d\n", (int) rv);
151
152 if (retval == 0) {
153 /* Keep error status from RegCreateKeyEx, if any */
154 retval = -4;
155 }
156 }
157
158 if (retval) {
159 break;
160 }
161
162 hKey = hKeyNext;
163 index++;
164 }
165
166 if (keys[index] == NULL) {
167 /* Close the final key we opened, if we walked the entire
168 * tree
169 */
170 rv = RegCloseKey(hKey);
171
172 if (rv != ERROR_SUCCESS) {
173 fprintf(stderr, "RegCloseKey %d\n", (int) rv);
174
175 if (retval == 0) {
176 /* Keep error status from RegCreateKeyEx, if any */
177 retval = -4;
178 }
179 }
180 }
181
182 return retval;
183}
184
185static int
186WIN32_StoreKey(const char *key, DWORD type, unsigned char *value,
187 int value_size)
188{
189 LONG rv;
190 HKEY hKey;
191 int retval;
192
193 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
194
195 if (rv == ERROR_FILE_NOT_FOUND) {
196 /* Key could not be opened -- try to create it
197 */
198
199 if (WIN32_create_key() < 0) {
200 /* Creation failed (error already reported) */
201 return -4;
202 }
203
204 /* Now it has been created we should be able to open it
205 */
206 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
207
208 if (rv == ERROR_FILE_NOT_FOUND) {
209 fprintf(stderr, "Registry does not contain key %s after creation\n",
210 REGKEY);
211 return -1;
212 }
213 }
214
215 if (rv != ERROR_SUCCESS) {
216 fprintf(stderr, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, (int) rv);
217 return -4;
218 }
219
220 /* Now set the value and data */
221 rv = RegSetValueEx(hKey, key, /* value key name */
222 0, /* reserved */
223 type, /* type */
224 value, /* value data */
225 (DWORD) value_size); /* for size of "value" */
226
227 retval = 0; /* Return value */
228
229 if (rv != ERROR_SUCCESS) {
230 fprintf(stderr, "RegQueryValueEx(key %s),%d\n", key, (int) rv);
231 retval = -4;
232 } else {
233 fprintf(stderr, "Registry stored HKLM\\%s\\%s value %s\n",
234 REGKEY,
235 key,
236 type == REG_SZ ? value : (unsigned char *) "(not displayable)");
237 }
238
239 /* Make sure we close the key even if there was an error storing
240 * the data
241 */
242 rv = RegCloseKey(hKey);
243
244 if (rv != ERROR_SUCCESS) {
245 fprintf(stderr, "RegCloseKey HKLM\\%s, %d\n", REGKEY, (int) rv);
246
247 if (retval == 0) {
248 /* Keep error status from RegQueryValueEx, if any */
249 retval = -4;
250 }
251 }
252
253 return retval;
254}
255
256/* Build argv, argc from string passed from Windows. */
257static void WIN32_build_argv(char *cmd)
258{
259 int argvlen = 0;
260 char *word;
261
262 WIN32_argc = 1;
263 WIN32_argv = (char **) xmalloc ((WIN32_argc+1) * sizeof (char *));
264 WIN32_argv[0]=xstrdup(WIN32_module_name);
265 /* Scan command line until there is nothing left. */
266
267 while (*cmd) {
268 /* Ignore spaces */
269
270 if (xisspace(*cmd)) {
271 cmd++;
272 continue;
273 }
274
275 /* Found the beginning of an argument. */
276 word = cmd;
277
278 while (*cmd) {
279 cmd++; /* Skip over this character */
280
281 if (xisspace(*cmd)) /* End of argument if space */
282 break;
283 }
284
285 if (*cmd)
286 *cmd++ = '\0'; /* Terminate `word' */
287
288 /* See if we need to allocate more space for argv */
289 if (WIN32_argc >= argvlen) {
290 argvlen = WIN32_argc + 1;
291 WIN32_argv = (char **) xrealloc (WIN32_argv, (1 + argvlen) * sizeof (char *));
292 }
293
294 /* Add word to argv file. */
295 WIN32_argv[WIN32_argc++] = word;
296 }
297
298 WIN32_argv[WIN32_argc] = NULL;
299}
300
301#endif /* USE_WIN32_SERVICE */
302
303static unsigned int
304GetOSVersion()
305{
cda5938d 306 OSVERSIONINFOEX osvi;
307 BOOL bOsVersionInfoEx;
9c8434f6 308
309 safe_free(WIN32_OS_string);
cda5938d 310 memset(&osvi, '\0', sizeof(OSVERSIONINFOEX));
311 /* Try calling GetVersionEx using the OSVERSIONINFOEX structure.
312 * If that fails, try using the OSVERSIONINFO structure.
313 */
9c8434f6 314
cda5938d 315 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
9c8434f6 316
cda5938d 317 if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
26ac0430
AJ
318 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
319 if (!GetVersionEx((OSVERSIONINFO *) & osvi))
320 goto GetVerError;
cda5938d 321 }
322 switch (osvi.dwPlatformId) {
9c8434f6 323 case VER_PLATFORM_WIN32_NT:
26ac0430
AJ
324 if (osvi.dwMajorVersion <= 4) {
325 WIN32_OS_string = xstrdup("Windows NT");
326 return _WIN_OS_WINNT;
327 }
328 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) {
329 WIN32_OS_string = xstrdup("Windows 2000");
330 return _WIN_OS_WIN2K;
331 }
332 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1)) {
333 WIN32_OS_string = xstrdup("Windows XP");
334 return _WIN_OS_WINXP;
335 }
336 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2)) {
337 WIN32_OS_string = xstrdup("Windows Server 2003");
338 return _WIN_OS_WINNET;
339 }
340 if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0)) {
341 if (osvi.wProductType == VER_NT_WORKSTATION)
342 WIN32_OS_string = xstrdup("Windows Vista");
343 else
344 WIN32_OS_string = xstrdup("Windows Server 2008");
345 return _WIN_OS_WINLON;
346 }
af6a12ee
AJ
347 if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1)) {
348 if (osvi.wProductType == VER_NT_WORKSTATION)
349 WIN32_OS_string = xstrdup("Windows 7");
350 else
351 WIN32_OS_string = xstrdup("Windows Server 2008 R2");
352 return _WIN_OS_WIN7;
353 }
354 if (((osvi.dwMajorVersion > 6)) || ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion > 1))) {
355 if (osvi.wProductType == VER_NT_WORKSTATION)
356 WIN32_OS_string = xstrdup("Unknown Windows version, assuming Windows 7 capabilities");
357 else
358 WIN32_OS_string = xstrdup("Unknown Windows version, assuming Windows Server 2008 R2 capabilities");
359 return _WIN_OS_WIN7;
360 }
26ac0430 361 break;
9c8434f6 362 case VER_PLATFORM_WIN32_WINDOWS:
26ac0430
AJ
363 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)) {
364 WIN32_OS_string = xstrdup("Windows 95");
365 return _WIN_OS_WIN95;
366 }
367 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 10)) {
368 WIN32_OS_string = xstrdup("Windows 98");
369 return _WIN_OS_WIN98;
370 }
371 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 90)) {
372 WIN32_OS_string = xstrdup("Windows Me");
373 return _WIN_OS_WINME;
374 }
375 break;
9c8434f6 376 case VER_PLATFORM_WIN32s:
26ac0430
AJ
377 WIN32_OS_string = xstrdup("Windows 3.1 with WIN32S");
378 return _WIN_OS_WIN32S;
379 break;
9c8434f6 380 default:
26ac0430 381 break;
9c8434f6 382 }
26ac0430 383GetVerError:
9c8434f6 384 WIN32_OS_string = xstrdup("Unknown Windows system");
385 return _WIN_OS_UNKNOWN;
386}
387
388/* ====================================================================== */
389/* PUBLIC FUNCTIONS */
390/* ====================================================================== */
391
392void
393WIN32_Abort(int sig)
394{
395#if USE_WIN32_SERVICE
396 svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
397 svcStatus.dwServiceSpecificExitCode = 1;
398#endif
399
400 Squid_Aborting = 1;
401 WIN32_Exit();
402}
403
b6696974 404#ifdef _SQUID_MSWIN_
babd1fd5 405void
406WIN32_IpAddrChangeMonitorExit()
407{
408 DWORD status = ERROR_SUCCESS;
409
b6696974 410 if (NotifyAddrChange_thread != INVALID_HANDLE_VALUE) {
26ac0430
AJ
411 TerminateThread(NotifyAddrChange_thread, status);
412 CloseHandle(NotifyAddrChange_thread);
babd1fd5 413 }
414}
b6696974 415#endif
babd1fd5 416
9c8434f6 417void
418WIN32_Exit()
419{
420#ifdef _SQUID_MSWIN_
421 Win32SockCleanup();
422#endif
423#if USE_WIN32_SERVICE
424
425 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
426 if (!Squid_Aborting) {
427 svcStatus.dwCurrentState = SERVICE_STOPPED;
428 SetServiceStatus(svcHandle, &svcStatus);
429 }
430 }
431
432#endif
433#ifdef _SQUID_MSWIN_
434 if (dbg_mutex)
435 DeleteCriticalSection(dbg_mutex);
436
437 WIN32_ExceptionHandlerCleanup();
babd1fd5 438 WIN32_IpAddrChangeMonitorExit();
9c8434f6 439
440#endif
441
442 _exit(0);
443}
444
babd1fd5 445#ifdef _SQUID_MSWIN_
446static DWORD WINAPI
447WIN32_IpAddrChangeMonitor(LPVOID lpParam)
448{
449 DWORD Result;
450 HMODULE IPHLPAPIHandle;
451 PFNotifyAddrChange NotifyAddrChange;
452
453 if ((IPHLPAPIHandle = GetModuleHandle("IPHLPAPI")) == NULL)
26ac0430 454 IPHLPAPIHandle = LoadLibrary("IPHLPAPI");
babd1fd5 455 NotifyAddrChange = (PFNotifyAddrChange) GetProcAddress(IPHLPAPIHandle, NOTIFYADDRCHANGE);
456
457 while (1) {
26ac0430
AJ
458 Result = NotifyAddrChange(NULL, NULL);
459 if (Result != NO_ERROR) {
460 debugs(1, 1, "NotifyAddrChange error " << Result);
461 return 1;
462 }
463 debugs(1, 1, "Notification of IP address change received, requesting Squid reconfiguration ...");
464 reconfigure(SIGHUP);
babd1fd5 465 }
466 return 0;
467}
468
469DWORD
470WIN32_IpAddrChangeMonitorInit()
471{
472 DWORD status = ERROR_SUCCESS;
473 DWORD threadID = 0, ThrdParam = 0;
474
b6696974 475 if ((WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) && (Config.onoff.WIN32_IpAddrChangeMonitor)) {
26ac0430
AJ
476 NotifyAddrChange_thread = CreateThread(NULL, 0, WIN32_IpAddrChangeMonitor,
477 &ThrdParam, 0, &threadID);
478 if (NotifyAddrChange_thread == NULL) {
479 status = GetLastError();
480 NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
481 debugs(1, 1, "Failed to start IP monitor thread.");
482 } else
483 debugs(1, 2, "Starting IP monitor thread [" << threadID << "] ...");
babd1fd5 484 }
485 return status;
486}
353942c5 487#endif /* _SQUID_MSWIN_ */
babd1fd5 488
9c8434f6 489int WIN32_Subsystem_Init(int * argc, char *** argv)
490{
491#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
492 _invalid_parameter_handler oldHandler, newHandler;
493#endif
494
495 WIN32_OS_version = GetOSVersion();
496
497 if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S))
498 return 1;
499
500 if (atexit(WIN32_Exit) != 0)
501 return 1;
502
503#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
504
505 newHandler = Squid_Win32InvalidParameterHandler;
506
507 oldHandler = _set_invalid_parameter_handler(newHandler);
508
509 _CrtSetReportMode(_CRT_ASSERT, 0);
510
511#endif
512#if USE_WIN32_SERVICE
513
514 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
515 char path[512];
516 HKEY hndKey;
517
518 if (signal(SIGABRT, WIN32_Abort) == SIG_ERR)
519 return 1;
520
521 /* Register the service Handler function */
522 svcHandle =
523 RegisterServiceCtrlHandler(WIN32_Service_name,
524 WIN32_svcHandler);
525
526 if (svcHandle == 0)
527 return 1;
528
529 /* Set Process work dir to directory cointaining squid.exe */
530 GetModuleFileName(NULL, path, 512);
531
532 WIN32_module_name=xstrdup(path);
533
534 path[strlen(path) - 10] = '\0';
535
536 if (SetCurrentDirectory(path) == 0)
537 return 1;
538
539 safe_free(ConfigFile);
540
541 /* get config file from Windows Registry */
542 if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY, &hndKey) == ERROR_SUCCESS) {
543 DWORD Type = 0;
544 DWORD Size = 0;
545 LONG Result;
546 Result =
547 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size);
548
549 if (Result == ERROR_SUCCESS && Size) {
550 ConfigFile = static_cast<char *>(xmalloc(Size));
551 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, (unsigned char *)ConfigFile,
552 &Size);
553 } else
554 ConfigFile = xstrdup(DefaultConfigFile);
555
556 Size = 0;
557
558 Type = 0;
559
560 Result =
561 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size);
562
563 if (Result == ERROR_SUCCESS && Size) {
564 WIN32_Service_Command_Line = static_cast<char *>(xmalloc(Size));
565 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, (unsigned char *)WIN32_Service_Command_Line,
566 &Size);
567 } else
568 WIN32_Service_Command_Line = xstrdup("");
569
570 RegCloseKey(hndKey);
571 } else {
572 ConfigFile = xstrdup(DefaultConfigFile);
573 WIN32_Service_Command_Line = xstrdup("");
574 }
575
576 WIN32_build_argv(WIN32_Service_Command_Line);
577 *argc = WIN32_argc;
578 *argv = WIN32_argv;
579 /* Set Service Status to SERVICE_START_PENDING */
580 svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
581 svcStatus.dwCurrentState = SERVICE_START_PENDING;
582 svcStatus.dwControlsAccepted =
583 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
584 svcStatus.dwWin32ExitCode = 0;
585 svcStatus.dwServiceSpecificExitCode = 0;
586 svcStatus.dwCheckPoint = 0;
587 svcStatus.dwWaitHint = 10000;
588 SetServiceStatus(svcHandle, &svcStatus);
589#ifdef _SQUID_MSWIN_
590
591 _setmaxstdio(Squid_MaxFD);
592#endif
593
594 }
595
596#endif /* USE_WIN32_SERVICE */
597#ifdef _SQUID_MSWIN_
598 if (Win32SockInit() < 0)
599 return 1;
600
601#endif
602
603 return 0;
604}
605
606#if USE_WIN32_SERVICE
607void
608WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
609{
610 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
611 svcStatus.dwCheckPoint++;
612 svcStatus.dwWaitHint = WaitHint;
613 svcStatus.dwCurrentState = svcstate;
614 SetServiceStatus(svcHandle, &svcStatus);
615 }
616}
617
618VOID WINAPI
619WIN32_svcHandler(DWORD Opcode)
620{
621 DWORD status;
622
623 switch (Opcode) {
624
625 case _WIN_SQUID_SERVICE_CONTROL_STOP:
626
627 case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN:
628 /* Do whatever it takes to stop here. */
629 svcStatus.dwWin32ExitCode = 0;
630 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
631 svcStatus.dwCheckPoint = 0;
632 svcStatus.dwWaitHint = 10000;
633 shut_down(SIGTERM);
634
635 if (!SetServiceStatus(svcHandle, &svcStatus)) {
636 status = GetLastError();
bf8fe701 637 debugs(1, 1, "SetServiceStatus error " << status);
9c8434f6 638 }
639
bf8fe701 640 debugs(1, 1, "Leaving Squid service");
9c8434f6 641 return;
642
643 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE:
644 /* Fall through to send current status. */
645
646 if (!SetServiceStatus(svcHandle, &svcStatus)) {
647 status = GetLastError();
bf8fe701 648 debugs(1, 1, "SetServiceStatus error " << status);
9c8434f6 649 }
650
651 break;
652
653 case _WIN_SQUID_SERVICE_CONTROL_ROTATE:
654 rotate_logs(SIGUSR1);
655 break;
656
657 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE:
658 reconfigure(SIGHUP);
659 break;
660
661 case _WIN_SQUID_SERVICE_CONTROL_DEBUG:
662 sigusr2_handle(SIGUSR2);
663 break;
664
665 case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT:
666 /* Do whatever it takes to stop here. */
667 svcStatus.dwWin32ExitCode = 0;
668 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
669 svcStatus.dwCheckPoint = 0;
670 svcStatus.dwWaitHint = 10000;
671 shut_down(SIGINT);
672
673 if (!SetServiceStatus(svcHandle, &svcStatus)) {
674 status = GetLastError();
bf8fe701 675 debugs(1, 1, "SetServiceStatus error " << status);
9c8434f6 676 }
677
bf8fe701 678 debugs(1, 1, "Leaving Squid service");
9c8434f6 679 break;
680
681 default:
bf8fe701 682 debugs(1, 1, "Unrecognized opcode " << Opcode);
9c8434f6 683 }
684
685 return;
686}
687
688void
689WIN32_RemoveService()
690{
691 SC_HANDLE schService;
692 SC_HANDLE schSCManager;
693
694 if (!WIN32_Service_name)
695 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
696
697 strcat(REGKEY, WIN32_Service_name);
698
699 keys[4] = WIN32_Service_name;
700
701 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
702 NULL, /* database (NULL == default) */
703 SC_MANAGER_ALL_ACCESS /* access required */
704 );
705
706 if (!schSCManager)
707 fprintf(stderr, "OpenSCManager failed\n");
708 else {
709 schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS);
710
711 if (schService == NULL)
712 fprintf(stderr, "OpenService failed\n");
713
714 /* Could not open the service */
715 else {
716 /* try to stop the service */
717
718 if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP,
719 &svcStatus)) {
720 sleep(1);
721
722 while (QueryServiceStatus(schService, &svcStatus)) {
723 if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
724 sleep(1);
725 else
726 break;
727 }
728 }
729
730 /* now remove the service */
731 if (DeleteService(schService) == 0)
732 fprintf(stderr, "DeleteService failed.\n");
733 else
734 printf("Service %s deleted successfully.\n",
735 WIN32_Service_name);
736
737 CloseServiceHandle(schService);
738 }
739
740 CloseServiceHandle(schSCManager);
741 }
742}
743
744void
745WIN32_SetServiceCommandLine()
746{
747 if (!WIN32_Service_name)
748 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
749
750 strcat(REGKEY, WIN32_Service_name);
751
752 keys[4] = WIN32_Service_name;
753
754 /* Now store the Service Command Line in the registry */
755 WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1);
756}
757
758void
759WIN32_InstallService()
760{
761 SC_HANDLE schService;
762 SC_HANDLE schSCManager;
763 char ServicePath[512];
764 char szPath[512];
765 int lenpath;
766
767 if (!WIN32_Service_name)
768 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
769
770 strcat(REGKEY, WIN32_Service_name);
771
772 keys[4] = WIN32_Service_name;
773
774 if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
775 fprintf(stderr, "Can't get executable path\n");
776 exit(1);
777 }
778
779 snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, WIN32_Service_name);
780 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
781 NULL, /* database (NULL == default) */
782 SC_MANAGER_ALL_ACCESS /* access required */
783 );
784
785 if (!schSCManager) {
786 fprintf(stderr, "OpenSCManager failed\n");
787 exit(1);
788 } else {
789 schService = CreateService(schSCManager, /* SCManager database */
790 WIN32_Service_name, /* name of service */
791 WIN32_Service_name, /* name to display */
792 SERVICE_ALL_ACCESS, /* desired access */
793 SERVICE_WIN32_OWN_PROCESS, /* service type */
794 SERVICE_AUTO_START, /* start type */
795 SERVICE_ERROR_NORMAL, /* error control type */
796 (const char *) szPath, /* service's binary */
797 NULL, /* no load ordering group */
798 NULL, /* no tag identifier */
799 "Tcpip\0AFD\0", /* dependencies */
800 NULL, /* LocalSystem account */
801 NULL); /* no password */
802
803 if (schService) {
804 if (WIN32_OS_version > _WIN_OS_WINNT) {
805 HMODULE ADVAPI32Handle;
806 PFChangeServiceConfig2 ChangeServiceConfig2;
807 DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION;
808
809 ADVAPI32Handle = GetModuleHandle("advapi32");
810 ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2);
811 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription);
812 dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS;
813 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions);
814 }
815
816 CloseServiceHandle(schService);
817 /* Now store the config file location in the registry */
818
819 if (!ConfigFile)
820 ConfigFile = xstrdup(DefaultConfigFile);
821
822 WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1);
823
824 printf("Squid Cache version %s for %s\n", version_string,
825 CONFIG_HOST_TYPE);
826
827 printf("installed successfully as %s Windows System Service.\n",
828 WIN32_Service_name);
829
830 printf
831 ("To run, start it from the Services Applet of Control Panel.\n");
832
833 printf("Don't forget to edit squid.conf before starting it.\n\n");
834 } else {
835 fprintf(stderr, "CreateService failed\n");
836 exit(1);
837 }
838
839 CloseServiceHandle(schSCManager);
840 }
841}
842
843void
844WIN32_sendSignal(int WIN32_signal)
845{
846 SERVICE_STATUS ssStatus;
847 DWORD fdwAccess, fdwControl;
848 SC_HANDLE schService;
849 SC_HANDLE schSCManager;
850
851 if (!WIN32_Service_name)
852 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
853
854 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
855 NULL, /* database (NULL == default) */
856 SC_MANAGER_ALL_ACCESS /* access required */
857 );
858
859 if (!schSCManager) {
860 fprintf(stderr, "OpenSCManager failed\n");
861 exit(1);
862 }
863
864 /* The required service object access depends on the control. */
865 switch (WIN32_signal) {
866
867 case 0: /* SIGNULL */
868 fdwAccess = SERVICE_INTERROGATE;
869 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE;
870 break;
871
872 case SIGUSR1:
873 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
874 fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE;
875 break;
876
877 case SIGUSR2:
878 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
879 fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG;
880 break;
881
882 case SIGHUP:
883 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
884 fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE;
885 break;
886
887 case SIGTERM:
888 fdwAccess = SERVICE_STOP;
889 fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP;
890 break;
891
892 case SIGINT:
893
894 case SIGKILL:
895 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
896 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT;
897 break;
898
899 default:
900 exit(1);
901 }
902
903 /* Open a handle to the service. */
904 schService = OpenService(schSCManager, /* SCManager database */
905 WIN32_Service_name, /* name of service */
906 fdwAccess); /* specify access */
907
908 if (schService == NULL) {
7dbca7a4 909 fprintf(stderr, "%s: ERROR: Could not open Service %s\n", APP_SHORTNAME,
9c8434f6 910 WIN32_Service_name);
911 exit(1);
912 } else {
913 /* Send a control value to the service. */
914
915 if (!ControlService(schService, /* handle of service */
916 fdwControl, /* control value to send */
917 &ssStatus)) { /* address of status info */
918 fprintf(stderr, "%s: ERROR: Could not Control Service %s\n",
7dbca7a4 919 APP_SHORTNAME, WIN32_Service_name);
9c8434f6 920 exit(1);
921 } else {
922 /* Print the service status. */
923 printf("\nStatus of %s Service:\n", WIN32_Service_name);
924 printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType);
925 printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState);
926 printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted);
927 printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode);
928 printf(" Service Specific Exit Code: %ld\n",
929 ssStatus.dwServiceSpecificExitCode);
930 printf(" Check Point: %ld\n", ssStatus.dwCheckPoint);
931 printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint);
932 }
933
934 CloseServiceHandle(schService);
935 }
936
937 CloseServiceHandle(schSCManager);
938}
939
940int main(int argc, char **argv)
941{
942 SERVICE_TABLE_ENTRY DispatchTable[] = {
26ac0430
AJ
943 {NULL, SquidWinSvcMain},
944 {NULL, NULL}
945 };
9c8434f6 946 char *c;
947 char stderr_path[256];
948
949 if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)) {
950 strcpy(stderr_path, argv[0]);
951 strcat(stderr_path,".log");
952 freopen(stderr_path, "w", stderr);
953 setmode(fileno(stderr), O_TEXT);
954 WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE;
9c8434f6 955
956 if (!(c=strchr(argv[1],':'))) {
957 fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
958 return 1;
959 }
960
961 WIN32_Service_name = xstrdup(c+1);
962 DispatchTable[0].lpServiceName=WIN32_Service_name;
963 strcat(REGKEY, WIN32_Service_name);
964 keys[4] = WIN32_Service_name;
965
966 if (!StartServiceCtrlDispatcher(DispatchTable)) {
967 fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n",
968 GetLastError());
969 return 1;
970 }
971 } else {
972 WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
973#ifdef _SQUID_MSWIN_
974
975 opt_no_daemon = 1;
976
977#endif
978
979 return SquidMain(argc, argv);
980 }
981
982 return 0;
983}
984
985#endif /* USE_WIN32_SERVICE */
986
987#if defined(_SQUID_MSWIN_)
988static int Win32SockInit(void)
989{
990 int iVersionRequested;
991 WSADATA wsaData;
992 int err, opt;
993 int optlen = sizeof(opt);
994
995 if (s_iInitCount > 0) {
996 s_iInitCount++;
997 return (0);
998 } else if (s_iInitCount < 0)
999 return (s_iInitCount);
1000
1001 /* s_iInitCount == 0. Do the initailization */
1002 iVersionRequested = MAKEWORD(2, 0);
1003
1004 err = WSAStartup((WORD) iVersionRequested, &wsaData);
1005
1006 if (err) {
1007 s_iInitCount = -1;
1008 return (s_iInitCount);
1009 }
1010
1011 if (LOBYTE(wsaData.wVersion) != 2 ||
1012 HIBYTE(wsaData.wVersion) != 0) {
1013 s_iInitCount = -2;
1014 WSACleanup();
1015 return (s_iInitCount);
1016 }
1017
1018 if (WIN32_OS_version !=_WIN_OS_WINNT) {
1019 if (::getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, &optlen)) {
1020 s_iInitCount = -3;
1021 WSACleanup();
1022 return (s_iInitCount);
1023 } else {
1024 opt = opt | SO_SYNCHRONOUS_NONALERT;
1025
1026 if (::setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen)) {
1027 s_iInitCount = -3;
1028 WSACleanup();
1029 return (s_iInitCount);
1030 }
1031 }
1032 }
1033
1034 WIN32_Socks_initialized = 1;
1035 s_iInitCount++;
1036 return (s_iInitCount);
1037}
1038
1039static void Win32SockCleanup(void)
1040{
1041 if (--s_iInitCount == 0)
1042 WSACleanup();
1043
1044 return;
1045}
1046
1047void Squid_Win32InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
1048{
1049 return;
1050}
1051
1052#endif /* SQUID_MSWIN_ */