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