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