]> git.ipfire.org Git - thirdparty/squid.git/blame - src/WinSvc.cc
Docs: Copyright updates for 2018 (#114)
[thirdparty/squid.git] / src / WinSvc.cc
CommitLineData
9c8434f6 1/*
5b74111a 2 * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
9c8434f6 3 *
bbc27441
AJ
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.
9c8434f6 7 */
8
bbc27441
AJ
9/* Inspired by previous work by Romeo Anghelache & Eric Stern. */
10
582c2af2 11#include "squid.h"
91d63ce7
AJ
12#include "Debug.h"
13#include "globals.h"
cf3edd6f 14#include "protos.h"
91d63ce7 15#include "SquidConfig.h"
2ed0191c
AJ
16#include "tools.h"
17#include "WinSvc.h"
9c8434f6 18
7aa9bb3e 19#if _SQUID_WINDOWS_
2ed0191c 20#if !defined(_MSWSOCK_)
9c8434f6 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
cf3edd6f
FC
29/* forward declarations */
30static void WIN32_Exit(void);
9c8434f6 31static unsigned int GetOSVersion();
32void WIN32_svcstatusupdate(DWORD, DWORD);
33void WINAPI WIN32_svcHandler(DWORD);
91d63ce7
AJ
34extern "C" void WINAPI SquidWinSvcMain(DWORD, char **);
35
9c8434f6 36#if USE_WIN32_SERVICE
91d63ce7 37static void WIN32_Abort(int);
9c8434f6 38static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int);
39static int WIN32_create_key(void);
40static void WIN32_build_argv (char *);
41#endif
9c8434f6 42
9c8434f6 43#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
44void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
45#endif
46static int Win32SockInit(void);
47static void Win32SockCleanup(void);
48SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex;
49void WIN32_ExceptionHandlerCleanup(void);
50static int s_iInitCount = 0;
353942c5 51static HANDLE NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
9c8434f6 52
babd1fd5 53#undef NotifyAddrChange
54typedef DWORD(WINAPI * PFNotifyAddrChange) (OUT PHANDLE, IN LPOVERLAPPED);
55#define NOTIFYADDRCHANGE "NotifyAddrChange"
9c8434f6 56
57#if USE_WIN32_SERVICE
58static SERVICE_STATUS svcStatus;
59static SERVICE_STATUS_HANDLE svcHandle;
60static int WIN32_argc;
61static char ** WIN32_argv;
62static char * WIN32_module_name;
63
d2b4d181 64#define VENDOR "squid-cache.org"
9c8434f6 65static char VENDORString[] = VENDOR;
d2b4d181 66#define SOFTWARENAME PACKAGE_NAME
9c8434f6 67static char SOFTWARENAMEString[] = SOFTWARENAME;
9c8434f6 68#define SOFTWARE "SOFTWARE"
69static char SOFTWAREString[] = SOFTWARE;
70#define COMMANDLINE "CommandLine"
71#define CONFIGFILE "ConfigFile"
72#undef ChangeServiceConfig2
73typedef BOOL (WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID);
74#ifdef UNICODE
75#define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
76#else
77#define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
78#endif
79static SC_ACTION Squid_SCAction[] = { { SC_ACTION_RESTART, 60000 } };
80static char Squid_ServiceDescriptionString[] = SOFTWARENAME " " VERSION " WWW Proxy Server";
81static SERVICE_DESCRIPTION Squid_ServiceDescription = { Squid_ServiceDescriptionString };
82static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = { INFINITE, NULL, NULL, 1, Squid_SCAction };
d54b5173 83static char REGKEY[256] = SOFTWARE "\\" VENDOR "\\" SOFTWARENAME "\\";
9c8434f6 84static char *keys[] = {
f53969cc
SM
85 SOFTWAREString, /* key[0] */
86 VENDORString, /* key[1] */
26ac0430 87 SOFTWARENAMEString, /* key[2] */
f53969cc
SM
88 NULL, /* key[3] */
89 NULL /* key[4] */
26ac0430 90};
91d63ce7
AJ
91
92static int Squid_Aborting = 0;
9c8434f6 93#endif
94
95/* ====================================================================== */
96/* LOCAL FUNCTIONS */
97/* ====================================================================== */
98
99#if USE_WIN32_SERVICE
100static int
101WIN32_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;
f53969cc
SM
117 rv = RegCreateKeyEx(hKey, keys[index], /* subkey */
118 0, /* reserved */
119 NULL, /* class */
9c8434f6 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;
14942edd 144 ++index;
9c8434f6 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
166static int
167WIN32_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 */
f53969cc
SM
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" */
9c8434f6 207
f53969cc 208 retval = 0; /* Return value */
9c8434f6 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. */
238static 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)) {
14942edd 252 ++cmd;
9c8434f6 253 continue;
254 }
255
256 /* Found the beginning of an argument. */
257 word = cmd;
258
259 while (*cmd) {
f53969cc 260 ++cmd; /* Skip over this character */
9c8434f6 261
f53969cc 262 if (xisspace(*cmd)) /* End of argument if space */
9c8434f6 263 break;
264 }
265
266 if (*cmd)
f53969cc 267 *cmd++ = '\0'; /* Terminate `word' */
9c8434f6 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
284static unsigned int
285GetOSVersion()
286{
cda5938d 287 OSVERSIONINFOEX osvi;
288 BOOL bOsVersionInfoEx;
9c8434f6 289
290 safe_free(WIN32_OS_string);
cda5938d 291 memset(&osvi, '\0', sizeof(OSVERSIONINFOEX));
292 /* Try calling GetVersionEx using the OSVERSIONINFOEX structure.
293 * If that fails, try using the OSVERSIONINFO structure.
294 */
9c8434f6 295
cda5938d 296 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
9c8434f6 297
cda5938d 298 if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
26ac0430
AJ
299 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
300 if (!GetVersionEx((OSVERSIONINFO *) & osvi))
301 goto GetVerError;
cda5938d 302 }
303 switch (osvi.dwPlatformId) {
9c8434f6 304 case VER_PLATFORM_WIN32_NT:
26ac0430
AJ
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 }
af6a12ee
AJ
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 }
26ac0430 342 break;
9c8434f6 343 case VER_PLATFORM_WIN32_WINDOWS:
26ac0430
AJ
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;
9c8434f6 357 case VER_PLATFORM_WIN32s:
26ac0430
AJ
358 WIN32_OS_string = xstrdup("Windows 3.1 with WIN32S");
359 return _WIN_OS_WIN32S;
360 break;
9c8434f6 361 default:
26ac0430 362 break;
9c8434f6 363 }
26ac0430 364GetVerError:
9c8434f6 365 WIN32_OS_string = xstrdup("Unknown Windows system");
366 return _WIN_OS_UNKNOWN;
367}
368
369/* ====================================================================== */
370/* PUBLIC FUNCTIONS */
371/* ====================================================================== */
372
91d63ce7 373#if USE_WIN32_SERVICE
9c8434f6 374void
375WIN32_Abort(int sig)
376{
9c8434f6 377 svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
378 svcStatus.dwServiceSpecificExitCode = 1;
9c8434f6 379 Squid_Aborting = 1;
380 WIN32_Exit();
381}
91d63ce7 382#endif
9c8434f6 383
babd1fd5 384void
385WIN32_IpAddrChangeMonitorExit()
386{
387 DWORD status = ERROR_SUCCESS;
388
b6696974 389 if (NotifyAddrChange_thread != INVALID_HANDLE_VALUE) {
26ac0430
AJ
390 TerminateThread(NotifyAddrChange_thread, status);
391 CloseHandle(NotifyAddrChange_thread);
babd1fd5 392 }
393}
394
9c8434f6 395void
396WIN32_Exit()
397{
9c8434f6 398 Win32SockCleanup();
9c8434f6 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
9c8434f6 409 if (dbg_mutex)
410 DeleteCriticalSection(dbg_mutex);
411
412 WIN32_ExceptionHandlerCleanup();
babd1fd5 413 WIN32_IpAddrChangeMonitorExit();
9c8434f6 414 _exit(0);
415}
416
babd1fd5 417static DWORD WINAPI
418WIN32_IpAddrChangeMonitor(LPVOID lpParam)
419{
420 DWORD Result;
421 HMODULE IPHLPAPIHandle;
422 PFNotifyAddrChange NotifyAddrChange;
423
424 if ((IPHLPAPIHandle = GetModuleHandle("IPHLPAPI")) == NULL)
26ac0430 425 IPHLPAPIHandle = LoadLibrary("IPHLPAPI");
babd1fd5 426 NotifyAddrChange = (PFNotifyAddrChange) GetProcAddress(IPHLPAPIHandle, NOTIFYADDRCHANGE);
427
428 while (1) {
26ac0430
AJ
429 Result = NotifyAddrChange(NULL, NULL);
430 if (Result != NO_ERROR) {
e0236918 431 debugs(1, DBG_IMPORTANT, "NotifyAddrChange error " << Result);
26ac0430
AJ
432 return 1;
433 }
e0236918 434 debugs(1, DBG_IMPORTANT, "Notification of IP address change received, requesting Squid reconfiguration ...");
26ac0430 435 reconfigure(SIGHUP);
babd1fd5 436 }
437 return 0;
438}
439
440DWORD
441WIN32_IpAddrChangeMonitorInit()
442{
443 DWORD status = ERROR_SUCCESS;
444 DWORD threadID = 0, ThrdParam = 0;
445
b6696974 446 if ((WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) && (Config.onoff.WIN32_IpAddrChangeMonitor)) {
26ac0430
AJ
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;
e0236918 452 debugs(1, DBG_IMPORTANT, "Failed to start IP monitor thread.");
26ac0430
AJ
453 } else
454 debugs(1, 2, "Starting IP monitor thread [" << threadID << "] ...");
babd1fd5 455 }
456 return status;
457}
babd1fd5 458
9c8434f6 459int 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 */
d5f21615 492 svcHandle = RegisterServiceCtrlHandler(service_name.c_str(), WIN32_svcHandler);
9c8434f6 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 */
04f7fd38 510 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
9c8434f6 511 DWORD Type = 0;
512 DWORD Size = 0;
513 LONG Result;
0dde2160 514 Result = RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size);
9c8434f6 515
516 if (Result == ERROR_SUCCESS && Size) {
517 ConfigFile = static_cast<char *>(xmalloc(Size));
0dde2160 518 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, (unsigned char *)ConfigFile, &Size);
9c8434f6 519 } else
520 ConfigFile = xstrdup(DefaultConfigFile);
521
522 Size = 0;
523
524 Type = 0;
525
0dde2160 526 Result = RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size);
9c8434f6 527
528 if (Result == ERROR_SUCCESS && Size) {
529 WIN32_Service_Command_Line = static_cast<char *>(xmalloc(Size));
0dde2160 530 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, (unsigned char *)WIN32_Service_Command_Line, &Size);
9c8434f6 531 } else
532 WIN32_Service_Command_Line = xstrdup("");
533
534 RegCloseKey(hndKey);
535 } else {
536 ConfigFile = xstrdup(DefaultConfigFile);
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);
9c8434f6 553
554 _setmaxstdio(Squid_MaxFD);
9c8434f6 555
556 }
557
558#endif /* USE_WIN32_SERVICE */
9c8434f6 559 if (Win32SockInit() < 0)
560 return 1;
561
9c8434f6 562 return 0;
563}
564
565#if USE_WIN32_SERVICE
566void
567WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
568{
569 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
14942edd 570 ++svcStatus.dwCheckPoint;
9c8434f6 571 svcStatus.dwWaitHint = WaitHint;
572 svcStatus.dwCurrentState = svcstate;
573 SetServiceStatus(svcHandle, &svcStatus);
574 }
575}
576
577VOID WINAPI
578WIN32_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();
e0236918 596 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
9c8434f6 597 }
598
e0236918 599 debugs(1, DBG_IMPORTANT, "Leaving Squid service");
9c8434f6 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();
e0236918 607 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
9c8434f6 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();
e0236918 634 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
9c8434f6 635 }
636
e0236918 637 debugs(1, DBG_IMPORTANT, "Leaving Squid service");
9c8434f6 638 break;
639
640 default:
e0236918 641 debugs(1, DBG_IMPORTANT, "Unrecognized opcode " << Opcode);
9c8434f6 642 }
643
644 return;
645}
646
647void
648WIN32_RemoveService()
649{
650 SC_HANDLE schService;
651 SC_HANDLE schSCManager;
652
d5f21615
AJ
653 if (service_name.isEmpty())
654 service_name = SBuf(APP_SHORTNAME);
9c8434f6 655
d5f21615
AJ
656 const char *service = service_name.c_str();
657 strcat(REGKEY, service);
9c8434f6 658
2ed0191c 659 keys[4] = const_cast<char*>(service);
9c8434f6 660
f53969cc
SM
661 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
662 NULL, /* database (NULL == default) */
663 SC_MANAGER_ALL_ACCESS /* access required */
9c8434f6 664 );
665
666 if (!schSCManager)
667 fprintf(stderr, "OpenSCManager failed\n");
668 else {
d5f21615 669 schService = OpenService(schSCManager, service, SERVICE_ALL_ACCESS);
9c8434f6 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
d5f21615 694 printf("Service " SQUIDSBUFPH " deleted successfully.\n", SQUIDSBUFPRINT(service_name));
9c8434f6 695
696 CloseServiceHandle(schService);
697 }
698
699 CloseServiceHandle(schSCManager);
700 }
701}
702
703void
704WIN32_SetServiceCommandLine()
705{
d5f21615
AJ
706 if (service_name.isEmpty())
707 service_name = SBuf(APP_SHORTNAME);
9c8434f6 708
2ed0191c 709 const char *service = service_name.c_str();
d5f21615 710 strcat(REGKEY, service);
9c8434f6 711
2ed0191c 712 keys[4] = const_cast<char*>(service);
9c8434f6 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
718void
719WIN32_InstallService()
720{
721 SC_HANDLE schService;
722 SC_HANDLE schSCManager;
723 char ServicePath[512];
724 char szPath[512];
725 int lenpath;
726
d5f21615
AJ
727 if (service_name.isEmpty())
728 service_name = SBuf(APP_SHORTNAME);
9c8434f6 729
d5f21615
AJ
730 const char *service = service_name.c_str();
731 strcat(REGKEY, service);
9c8434f6 732
2ed0191c 733 keys[4] = const_cast<char*>(service);
9c8434f6 734
735 if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
736 fprintf(stderr, "Can't get executable path\n");
24885773 737 exit(EXIT_FAILURE);
9c8434f6 738 }
739
d5f21615 740 snprintf(szPath, sizeof(szPath), "%s %s:" SQUIDSBUFPH, ServicePath, _WIN_SQUID_SERVICE_OPTION, SQUIDSBUFPRINT(service_name));
f53969cc
SM
741 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
742 NULL, /* database (NULL == default) */
743 SC_MANAGER_ALL_ACCESS /* access required */
9c8434f6 744 );
745
746 if (!schSCManager) {
747 fprintf(stderr, "OpenSCManager failed\n");
24885773 748 exit(EXIT_FAILURE);
9c8434f6 749 } else {
750 schService = CreateService(schSCManager, /* SCManager database */
f53969cc
SM
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 */
9c8434f6 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(DefaultConfigFile);
782
783 WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1);
784
cf2155f2 785 printf("Squid Cache version %s for %s\n", version_string, CONFIG_HOST_TYPE);
d5f21615 786 printf("installed successfully as " SQUIDSBUFPH " Windows System Service.\n", SQUIDSBUFPRINT(service_name));
cf2155f2 787 printf("To run, start it from the Services Applet of Control Panel.\n");
9c8434f6 788 printf("Don't forget to edit squid.conf before starting it.\n\n");
789 } else {
790 fprintf(stderr, "CreateService failed\n");
24885773 791 exit(EXIT_FAILURE);
9c8434f6 792 }
793
794 CloseServiceHandle(schSCManager);
795 }
796}
797
798void
799WIN32_sendSignal(int WIN32_signal)
800{
801 SERVICE_STATUS ssStatus;
802 DWORD fdwAccess, fdwControl;
803 SC_HANDLE schService;
804 SC_HANDLE schSCManager;
805
d5f21615
AJ
806 if (service_name.isEmpty())
807 service_name = SBuf(APP_SHORTNAME);
9c8434f6 808
f53969cc
SM
809 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
810 NULL, /* database (NULL == default) */
811 SC_MANAGER_ALL_ACCESS /* access required */
9c8434f6 812 );
813
814 if (!schSCManager) {
815 fprintf(stderr, "OpenSCManager failed\n");
24885773 816 exit(EXIT_FAILURE);
9c8434f6 817 }
818
819 /* The required service object access depends on the control. */
820 switch (WIN32_signal) {
821
f53969cc 822 case 0: /* SIGNULL */
9c8434f6 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:
24885773 855 exit(EXIT_FAILURE);
9c8434f6 856 }
857
858 /* Open a handle to the service. */
f53969cc
SM
859 schService = OpenService(schSCManager, /* SCManager database */
860 service_name.c_str(), /* name of service */
861 fdwAccess); /* specify access */
9c8434f6 862
863 if (schService == NULL) {
d5f21615 864 fprintf(stderr, "%s: ERROR: Could not open Service " SQUIDSBUFPH "\n", APP_SHORTNAME, SQUIDSBUFPRINT(service_name));
24885773 865 exit(EXIT_FAILURE);
9c8434f6 866 } else {
867 /* Send a control value to the service. */
868
f53969cc
SM
869 if (!ControlService(schService, /* handle of service */
870 fdwControl, /* control value to send */
871 &ssStatus)) { /* address of status info */
d5f21615
AJ
872 fprintf(stderr, "%s: ERROR: Could not Control Service " SQUIDSBUFPH "\n",
873 APP_SHORTNAME, SQUIDSBUFPRINT(service_name));
24885773 874 exit(EXIT_FAILURE);
9c8434f6 875 } else {
876 /* Print the service status. */
d5f21615 877 printf("\nStatus of " SQUIDSBUFPH " Service:\n", SQUIDSBUFPRINT(service_name));
9c8434f6 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
a74922b5 894int WIN32_StartService(int argc, char **argv)
9c8434f6 895{
896 SERVICE_TABLE_ENTRY DispatchTable[] = {
26ac0430
AJ
897 {NULL, SquidWinSvcMain},
898 {NULL, NULL}
899 };
9c8434f6 900 char *c;
901 char stderr_path[256];
902
a74922b5
AJ
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;
9c8434f6 908
a74922b5
AJ
909 if (!(c=strchr(argv[1],':'))) {
910 fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
911 return 1;
912 }
9c8434f6 913
a74922b5
AJ
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);
9c8434f6 919
a74922b5
AJ
920 if (!StartServiceCtrlDispatcher(DispatchTable)) {
921 fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n", GetLastError());
922 return 1;
9c8434f6 923 }
924
925 return 0;
926}
927
928#endif /* USE_WIN32_SERVICE */
929
9c8434f6 930static 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) {
14942edd 938 ++s_iInitCount;
9c8434f6 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;
14942edd 977 ++s_iInitCount;
9c8434f6 978 return (s_iInitCount);
979}
980
981static void Win32SockCleanup(void)
982{
983 if (--s_iInitCount == 0)
984 WSACleanup();
985
986 return;
987}
988
989void Squid_Win32InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
990{
991 return;
992}
f53969cc 993