1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 *
21 * Kern Sibbald, August 2007
22 *
23 * This is a generic service routine, which is used by all three
24 * of the daemons. Each one compiles it with slightly different
25 * #defines.
26 *
27 */
28
29 #include "bacula.h"
30 #include "win32.h"
31
32 /* Forward reference */
33 static void set_service_description(SC_HANDLE hSCManager,
34 SC_HANDLE hService, LPSTR lpDesc);
35
36 /* Other Window component dependencies */
37 #define BAC_DEPENDENCIES __TEXT("tcpip\0afd\0")
38
39 /* Service globals */
40 SERVICE_STATUS_HANDLE service_handle;
41 SERVICE_STATUS service_status;
42 DWORD service_error = 0;
43 static bool is_service = false;
44
45 /* Forward references */
46 void WINAPI serviceControlCallback(DWORD ctrlcode);
47 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
48 DWORD WINAPI baculaWorkerThread(LPVOID lpwThreadParam);
49
50
51 /*
52 * Post a message to a running instance of the app
53 */
postToBacula(UINT message,WPARAM wParam,LPARAM lParam)54 bool postToBacula(UINT message, WPARAM wParam, LPARAM lParam)
55 {
56 /* Locate the Bacula menu window */
57 HWND hservwnd = FindWindow(APP_NAME, NULL);
58 if (hservwnd == NULL) {
59 return false;
60 }
61
62 /* Post the message to Bacula */
63 PostMessage(hservwnd, message, wParam, lParam);
64 return true;
65 }
66
67
68 /*
69 * Running as a service?
70 */
isAService()71 bool isAService()
72 {
73 return is_service;
74 }
75
76 /*
77 * terminate any running Bacula
78 */
stopRunningBacula()79 int stopRunningBacula()
80 {
81 postToBacula(WM_CLOSE, 0, 0);
82 sleep(5);
83 return 0;
84 }
85
86 /*
87 * New style service start callback handler for the OS.
88 * the OS returns control here immediately after starting
89 * the service.
90 */
serviceStartCallback(DWORD argc,char ** argv)91 void WINAPI serviceStartCallback(DWORD argc, char **argv)
92 {
93 DWORD dwThreadID;
94
95 /* Register our service */
96 service_handle = RegisterServiceCtrlHandler(APP_NAME, serviceControlCallback);
97 if (!service_handle) {
98 log_error_message(_("RegisterServiceCtlHandler failed"));
99 MessageBox(NULL, _("Failure contacting the Service Handler"),
100 APP_DESC, MB_OK);
101 return;
102 }
103
104 service_status.dwServiceType = SERVICE_WIN32;
105 service_status.dwServiceSpecificExitCode = 0;
106
107 /* Report status */
108 if (!ReportStatus(SERVICE_START_PENDING, NO_ERROR, 45000)) {
109 ReportStatus(SERVICE_STOPPED, service_error, 0);
110 log_error_message(_("Service start report failed"));
111 return;
112 }
113
114 /* Now create the Bacula worker thread */
115 (void)CreateThread(NULL, 0, baculaWorkerThread, NULL, 0, &dwThreadID);
116 return;
117 }
118
119 /*
120 * Stop our service
121 */
serviceStop()122 static void serviceStop()
123 {
124 /* Post a quit message our service thread */
125 if (service_thread_id != 0) {
126 PostThreadMessage(service_thread_id, WM_QUIT, 0, 0);
127 }
128 }
129
130 /*
131 * Service Control callback handler. The OS can call us here
132 * at any time, most often to stop the service.
133 */
serviceControlCallback(DWORD ctrlcode)134 void WINAPI serviceControlCallback(DWORD ctrlcode)
135 {
136 switch(ctrlcode) {
137 case SERVICE_CONTROL_STOP:
138 service_status.dwCurrentState = SERVICE_STOP_PENDING;
139 serviceStop(); /* our stop service routine */
140 break;
141 }
142
143 /* Report our status */
144 ReportStatus(service_status.dwCurrentState, NO_ERROR, 0);
145 }
146
147
148 /*
149 * Run Bacula as a service
150 */
baculaServiceMain()151 int baculaServiceMain()
152 {
153 is_service = true; /* indicate we are running as a service */
154
155 if (have_service_api) { /* New style service API */
156 /* Tell OS where to dispatch service calls to us */
157 SERVICE_TABLE_ENTRY dispatchTable[] = {
158 {(char *)APP_NAME, (LPSERVICE_MAIN_FUNCTION)serviceStartCallback},
159 {NULL, NULL}};
160
161 /* Start the service control dispatcher */
162 if (!StartServiceCtrlDispatcher(dispatchTable)) {
163 log_error_message(_("StartServiceCtrlDispatcher failed."));
164 }
165 /* Note, this thread continues in the ServiceCallback routine */
166
167 } else { /* old style Win95/98/Me */
168 HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
169 if (kerneldll == NULL) {
170 MessageBox(NULL, _("KERNEL32.DLL not found: Bacula service not started"),
171 APP_DESC, MB_OK);
172 return 1;
173 }
174
175 /* Get entry point for RegisterServiceProcess function */
176 DWORD (WINAPI *RegisterService)(DWORD, DWORD);
177 RegisterService = (DWORD (WINAPI *)(DWORD, DWORD))
178 GetProcAddress(kerneldll, "RegisterServiceProcess");
179 if (RegisterService == NULL) {
180 MessageBox(NULL, _("Registry service not found: Bacula service not started"),
181 APP_DESC, MB_OK);
182 log_error_message(_("Registry service entry point not found"));
183 FreeLibrary(kerneldll); /* free up kernel dll */
184 return 1;
185 }
186
187 RegisterService(0, 1); /* register us as a service */
188 BaculaAppMain(); /* call the main Bacula code */
189 RegisterService(0, 0); /* terminate the service */
190 FreeLibrary(kerneldll); /* free up kernel dll */
191 }
192 return 0;
193 }
194
195
196 /*
197 * New style service bacula worker thread
198 */
baculaWorkerThread(LPVOID lpwThreadParam)199 DWORD WINAPI baculaWorkerThread(LPVOID lpwThreadParam)
200 {
201 service_thread_id = GetCurrentThreadId();
202
203 if (!ReportStatus(SERVICE_RUNNING, NO_ERROR, 0)) {
204 MessageBox(NULL, _("Report Service failure"), APP_DESC, MB_OK);
205 log_error_message("ReportStatus RUNNING failed");
206 return 0;
207 }
208
209 /* Call Bacula main code */
210 BaculaAppMain();
211
212 /* Mark that we're no longer running */
213 service_thread_id = 0;
214
215 /* Tell the service manager that we've stopped */
216 ReportStatus(SERVICE_STOPPED, service_error, 0);
217 return 0;
218 }
219
220
221
222 /*
223 * Install the Bacula service on the OS -- very complicated
224 */
installService(const char * cmdOpts)225 int installService(const char *cmdOpts)
226 {
227 const int maxlen = 2048;
228 char path[maxlen];
229 char svcmd[maxlen];
230
231 bsnprintf(svcmd, sizeof(svcmd), "service: install: %s", cmdOpts, APP_DESC, MB_OK);
232
233 /* Get our filename */
234 if (GetModuleFileName(NULL, path, maxlen-11) == 0) {
235 MessageBox(NULL, _("Unable to install the service"), APP_DESC, MB_ICONEXCLAMATION | MB_OK);
236 return 0;
237 }
238
239 /* Create a valid command for starting the service */
240 if ((int)strlen(path) + (int)strlen(cmdOpts) + 30 < maxlen) {
241 bsnprintf(svcmd, sizeof(svcmd), "\"%s\" /service %s", path, cmdOpts);
242 } else {
243 log_error_message(_("Service command length too long"));
244 MessageBox(NULL, _("Service command length too long. Service not registered."),
245 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
246 return 0;
247 }
248
249 if (have_service_api) {
250 SC_HANDLE baculaService, serviceManager;
251
252 /* Open the service control manager */
253 serviceManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
254 if (!serviceManager) {
255 log_error_message("Open Service Manager failed");
256 MessageBox(NULL,
257 _("The Service Control Manager could not be contacted - the service was not installed"),
258 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
259 return 0;
260 }
261
262 /* Now actually create the Bacula service entry */
263 baculaService = CreateService(
264 serviceManager,
265 APP_NAME, /* Our service name */
266 APP_DESC, /* Display name */
267 SERVICE_ALL_ACCESS,
268 SERVICE_WIN32_OWN_PROCESS, /* | SERVICE_INTERACTIVE_PROCESS, */
269 SERVICE_AUTO_START,
270 SERVICE_ERROR_NORMAL,
271 svcmd, /* Command string to start the service */
272 NULL,
273 NULL,
274 BAC_DEPENDENCIES, /* Services to start before us */
275 NULL, /* Use default SYSTEM account */
276 NULL);
277 if (!baculaService) {
278 CloseServiceHandle(serviceManager);
279 log_error_message("CreateService failed for " APP_DESC);
280 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be installed"),
281 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
282 return 0;
283 }
284
285 /* Set a text description in the service manager's control panel */
286 set_service_description(serviceManager, baculaService,
287 (char *)_("Provides file backup and restore services. Bacula -- the network backup solution."));
288
289 CloseServiceHandle(serviceManager);
290 CloseServiceHandle(baculaService);
291
292 } else {
293 /* Old style service -- create appropriate registry key path */
294 HKEY runservices;
295 if (RegCreateKey(HKEY_LOCAL_MACHINE,
296 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
297 &runservices) != ERROR_SUCCESS) {
298 log_error_message(_("Cannot write System Registry for " APP_DESC));
299 MessageBox(NULL, _("The System Registry could not be updated - the Bacula service was not installed"),
300 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
301 return 0;
302 }
303
304 /* Add the Bacula values */
305 if (RegSetValueEx(runservices, APP_NAME, 0, REG_SZ,
306 (unsigned char *)svcmd, strlen(svcmd)+1) != ERROR_SUCCESS) {
307 RegCloseKey(runservices);
308 log_error_message(_("Cannot add Bacula key to System Registry"));
309 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be installed"),
310 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
311 return 0;
312 }
313 RegCloseKey(runservices);
314 }
315
316 /* At this point the service is installed */
317 if (opt_debug) {
318 MessageBox(NULL,
319 _("The " APP_DESC "was successfully installed.\n"
320 "The service may be started by double clicking on the\n"
321 "Bacula \"Start\" icon and will be automatically\n"
322 "be run the next time this machine is rebooted. "),
323 APP_DESC, MB_ICONINFORMATION | MB_OK);
324 }
325 return 0;
326 }
327
328
329 /*
330 * Remove a service from the OS (normally done when we are installing
331 * a new version).
332 */
removeService()333 int removeService()
334 {
335 SC_HANDLE serviceManager, baculaService;
336 int stat = 0;
337
338 if (have_service_api) { /* Newer Windows platforms (NT, Win2K, ...) */
339 serviceManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
340 if (serviceManager) {
341 /* Now get the Bacula service entry */
342 baculaService = OpenService(serviceManager, APP_NAME, SERVICE_ALL_ACCESS);
343 if (baculaService) {
344 SERVICE_STATUS status;
345 /* If the service is running, stop it */
346 if (ControlService(baculaService, SERVICE_CONTROL_STOP, &status)) {
347 while(QueryServiceStatus(baculaService, &status)) {
348 if (status.dwCurrentState != SERVICE_STOP_PENDING) {
349 break;
350 }
351 sleep(1);
352 }
353 if (status.dwCurrentState != SERVICE_STOPPED) {
354 if (opt_debug) {
355 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be stopped"),
356 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
357 }
358 }
359 }
360 if (DeleteService(baculaService)) {
361 if (opt_debug) {
362 MessageBox(NULL, _("The Bacula service: " APP_NAME " has been removed"),
363 APP_DESC, MB_ICONINFORMATION | MB_OK);
364 }
365 } else {
366 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be removed"),
367 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
368 stat = 1; /* error */
369 }
370 CloseServiceHandle(baculaService);
371 } else {
372 if (opt_debug) {
373 MessageBox(NULL, _("An existing Bacula service: " APP_NAME " could not be found for "
374 "removal. This is not normally an error."),
375 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
376 }
377 }
378 CloseServiceHandle(serviceManager);
379 return stat;
380 } else {
381 MessageBox(NULL, _("The service Manager could not be contacted - the Bacula service was not removed"),
382 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
383 return 1; /* error */
384 }
385
386 } else { /* Old Win95/98/Me OS */
387 /* Open the registry path key */
388 HKEY runservices;
389 if (RegOpenKey(HKEY_LOCAL_MACHINE,
390 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
391 &runservices) != ERROR_SUCCESS) {
392 if (opt_debug) {
393 MessageBox(NULL,
394 _("Could not find registry entry.\nService probably not registerd - the Bacula service was not removed"),
395 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
396 }
397 } else {
398 /* Now delete the Bacula entry */
399 if (RegDeleteValue(runservices, APP_NAME) != ERROR_SUCCESS) {
400 RegCloseKey(runservices);
401 MessageBox(NULL, _("Could not delete Registry key for " APP_NAME ".\n"
402 "The Bacula service could not be removed"), APP_DESC, MB_ICONEXCLAMATION | MB_OK);
403 }
404 RegCloseKey(runservices);
405 return 1;
406 }
407 /* Stop any running Bacula */
408 if (!stopRunningBacula()) {
409 if (opt_debug) {
410 MessageBox(NULL,
411 _("Bacula could not be contacted, probably not running"),
412 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
413 }
414 return 0; /* not really an error */
415 }
416 /* At this point, the service has been removed */
417 if (opt_debug) {
418 MessageBox(NULL, _("The Bacula service has been removed"), APP_DESC, MB_ICONINFORMATION | MB_OK);
419 }
420 }
421 return 0;
422 }
423
424
425 /*
426 * This subroutine is called to report our current status to the
427 * new style service manager
428 */
ReportStatus(DWORD state,DWORD exitcode,DWORD waithint)429 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint)
430 {
431 static DWORD checkpoint = 1;
432 BOOL result = TRUE;
433
434 /* No callbacks until we are started */
435 if (state == SERVICE_START_PENDING) {
436 service_status.dwControlsAccepted = 0;
437 } else {
438 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
439 }
440
441 /* Save global service_status state */
442 service_status.dwCurrentState = state;
443 service_status.dwWin32ExitCode = exitcode;
444 service_status.dwWaitHint = waithint;
445
446 /*
447 * Update the checkpoint variable so the service manager knows
448 * we are alive.
449 */
450 if (state == SERVICE_RUNNING || state == SERVICE_STOPPED) {
451 service_status.dwCheckPoint = 0;
452 } else {
453 service_status.dwCheckPoint = checkpoint++;
454 }
455
456 /* Send our new status */
457 result = SetServiceStatus(service_handle, &service_status);
458 if (!result) {
459 log_error_message(_("SetServiceStatus failed"));
460 }
461 return result;
462 }
463
464 /* Log an error message for the last Windows error */
LogLastErrorMsg(const char * message,const char * fname,int lineno)465 void LogLastErrorMsg(const char *message, const char *fname, int lineno)
466 {
467 char msgbuf[500];
468 HANDLE eventHandler;
469 const char *strings[3];
470 LPTSTR msg;
471
472 service_error = GetLastError();
473 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
474 FORMAT_MESSAGE_FROM_SYSTEM,
475 NULL,
476 service_error,
477 0,
478 (LPTSTR)&msg,
479 0,
480 NULL);
481
482 /* Use the OS event logging to log the error */
483 eventHandler = RegisterEventSource(NULL, APP_NAME);
484
485 bsnprintf(msgbuf, sizeof(msgbuf), _("\n\n%s error: %ld at %s:%d"),
486 APP_NAME, service_error, fname, lineno);
487
488 strings[0] = msgbuf;
489 strings[1] = message;
490 strings[2] = msg;
491
492 if (eventHandler) {
493 ReportEvent(eventHandler, EVENTLOG_ERROR_TYPE,
494 0, /* category */
495 0, /* ID */
496 NULL, /* SID */
497 3, /* Number of strings */
498 0, /* raw data size */
499 (const char **)strings, /* error strings */
500 NULL); /* raw data */
501 DeregisterEventSource(eventHandler);
502 }
503 LocalFree(msg);
504 }
505
506 typedef BOOL (WINAPI * WinAPI)(SC_HANDLE, DWORD, LPVOID);
507
508 /*
509 * This is amazingly complicated just to get a bit of English explanation
510 * in the service manager's dialog box.
511 */
set_service_description(SC_HANDLE hSCManager,SC_HANDLE hService,LPSTR lpDesc)512 static void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService,
513 LPSTR lpDesc)
514 {
515 SC_LOCK sclLock;
516 LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
517 SERVICE_DESCRIPTION sdBuf;
518 DWORD dwBytesNeeded;
519 WinAPI ChangeServiceDescription;
520
521 HINSTANCE hLib = LoadLibrary("ADVAPI32.DLL");
522 if (!hLib) {
523 return;
524 }
525 ChangeServiceDescription = (WinAPI)GetProcAddress(hLib,
526 "ChangeServiceConfig2A");
527 FreeLibrary(hLib);
528 if (!ChangeServiceDescription) {
529 return;
530 }
531
532 // Need to acquire database lock before reconfiguring.
533 sclLock = LockServiceDatabase(hSCManager);
534
535 // If the database cannot be locked, report the details.
536 if (sclLock == NULL) {
537 // Exit if the database is not locked by another process.
538 if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) {
539 log_error_message("LockServiceDatabase");
540 return;
541 }
542
543 // Allocate a buffer to get details about the lock.
544 lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS)LocalAlloc(
545 LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
546 if (lpqslsBuf == NULL) {
547 log_error_message("LocalAlloc");
548 return;
549 }
550
551 // Get and print the lock status information.
552 if (!QueryServiceLockStatus(
553 hSCManager,
554 lpqslsBuf,
555 sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
556 &dwBytesNeeded)) {
557 log_error_message("QueryServiceLockStatus");
558 }
559
560 if (lpqslsBuf->fIsLocked) {
561 printf(_("Locked by: %s, duration: %ld seconds\n"),
562 lpqslsBuf->lpLockOwner,
563 lpqslsBuf->dwLockDuration);
564 } else {
565 printf(_("No longer locked\n"));
566 }
567
568 LocalFree(lpqslsBuf);
569 log_error_message(_("Could not lock database"));
570 return;
571 }
572
573 // The database is locked, so it is safe to make changes.
574
575 sdBuf.lpDescription = lpDesc;
576
577 if (!ChangeServiceDescription(
578 hService, // handle to service
579 SERVICE_CONFIG_DESCRIPTION, // change: description
580 &sdBuf) ) { // value: new description
581 log_error_message("ChangeServiceConfig2");
582 }
583
584 // Release the database lock.
585 UnlockServiceDatabase(sclLock);
586 }
587