VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp

Last change on this file was 99828, checked in by vboxsync, 12 months ago

*: A bunch of adjustments that allows using /permissive- with Visual C++ (qt 6.x necessity).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.0 KB
RevLine 
[19374]1/* $Id: VBoxService-win.cpp 99828 2023-05-17 13:48:57Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions Service Skeleton, Windows Specific Parts.
4 */
5
6/*
[98103]7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
[19374]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[19374]26 */
27
28
[57358]29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[19374]32#include <iprt/assert.h>
[21230]33#include <iprt/err.h>
[70171]34#include <iprt/ldr.h>
[44114]35#include <iprt/system.h> /* For querying OS version. */
[19374]36
[70196]37#define WIN32_NO_STATUS
38#include <iprt/win/ws2tcpip.h>
39#include <iprt/win/winsock2.h>
40#undef WIN32_NO_STATUS
[70171]41#include <iprt/nt/nt-and-windows.h>
[70196]42#include <iprt/win/iphlpapi.h>
[19374]43#include <aclapi.h>
[70171]44#include <tlhelp32.h>
[70214]45#define _NTDEF_
46#include <Ntsecapi.h>
[19374]47
[70171]48#include "VBoxServiceInternal.h"
[29817]49
[70171]50
[57358]51/*********************************************************************************************************************************
52* Internal Functions *
53*********************************************************************************************************************************/
[58029]54static void WINAPI vgsvcWinMain(DWORD argc, LPTSTR *argv);
[29817]55
56
[57358]57/*********************************************************************************************************************************
58* Global Variables *
59*********************************************************************************************************************************/
[29817]60static DWORD g_dwWinServiceLastStatus = 0;
[19374]61SERVICE_STATUS_HANDLE g_hWinServiceStatus = NULL;
[29762]62/** The semaphore for the dummy Windows service. */
63static RTSEMEVENT g_WindowsEvent = NIL_RTSEMEVENT;
[19374]64
[99828]65static SERVICE_TABLE_ENTRYA const g_aServiceTable[] =
[19374]66{
[99828]67 { (PSTR)VBOXSERVICE_NAME, vgsvcWinMain },
68 { NULL, NULL}
[19374]69};
70
[70171]71/** @name APIs from ADVAPI32.DLL.
72 * @{ */
73decltype(RegisterServiceCtrlHandlerExA) *g_pfnRegisterServiceCtrlHandlerExA; /**< W2K+ */
74decltype(ChangeServiceConfig2A) *g_pfnChangeServiceConfig2A; /**< W2K+ */
[70196]75decltype(GetNamedSecurityInfoA) *g_pfnGetNamedSecurityInfoA; /**< NT4+ */
76decltype(SetEntriesInAclA) *g_pfnSetEntriesInAclA; /**< NT4+ */
77decltype(SetNamedSecurityInfoA) *g_pfnSetNamedSecurityInfoA; /**< NT4+ */
[70214]78decltype(LsaNtStatusToWinError) *g_pfnLsaNtStatusToWinError; /**< NT3.51+ */
[70171]79/** @} */
[25166]80
[70171]81/** @name API from KERNEL32.DLL
82 * @{ */
83decltype(CreateToolhelp32Snapshot) *g_pfnCreateToolhelp32Snapshot; /**< W2K+, but Geoff says NT4. Hmm. */
84decltype(Process32First) *g_pfnProcess32First; /**< W2K+, but Geoff says NT4. Hmm. */
85decltype(Process32Next) *g_pfnProcess32Next; /**< W2K+, but Geoff says NT4. Hmm. */
86decltype(Module32First) *g_pfnModule32First; /**< W2K+, but Geoff says NT4. Hmm. */
87decltype(Module32Next) *g_pfnModule32Next; /**< W2K+, but Geoff says NT4. Hmm. */
[70346]88decltype(GetSystemTimeAdjustment) *g_pfnGetSystemTimeAdjustment; /**< NT 3.50+ */
89decltype(SetSystemTimeAdjustment) *g_pfnSetSystemTimeAdjustment; /**< NT 3.50+ */
[70171]90/** @} */
91
92/** @name API from NTDLL.DLL
93 * @{ */
94decltype(ZwQuerySystemInformation) *g_pfnZwQuerySystemInformation; /**< NT4 (where as NtQuerySystemInformation is W2K). */
95/** @} */
96
[70196]97/** @name API from IPHLPAPI.DLL
98 * @{ */
99decltype(GetAdaptersInfo) *g_pfnGetAdaptersInfo;
100/** @} */
[70171]101
[70196]102/** @name APIs from WS2_32.DLL
103 * @note WSAIoctl is not present in wsock32.dll, so no point in trying the
104 * fallback here.
105 * @{ */
106decltype(WSAStartup) *g_pfnWSAStartup;
107decltype(WSACleanup) *g_pfnWSACleanup;
108decltype(WSASocketA) *g_pfnWSASocketA;
109decltype(WSAIoctl) *g_pfnWSAIoctl;
110decltype(WSAGetLastError) *g_pfnWSAGetLastError;
111decltype(closesocket) *g_pfnclosesocket;
112decltype(inet_ntoa) *g_pfninet_ntoa;
113
114/** @} */
115
[19374]116/**
[70171]117 * Resolve APIs not present on older windows versions.
118 */
119void VGSvcWinResolveApis(void)
120{
121 RTLDRMOD hLdrMod;
122#define RESOLVE_SYMBOL(a_fn) do { RT_CONCAT(g_pfn, a_fn) = (decltype(a_fn) *)RTLdrGetFunction(hLdrMod, #a_fn); } while (0)
123
124 /* From ADVAPI32.DLL: */
[70267]125 int rc = RTLdrLoadSystem("advapi32.dll", true /*fNoUnload*/, &hLdrMod);
[70171]126 AssertRC(rc);
127 if (RT_SUCCESS(rc))
128 {
129 RESOLVE_SYMBOL(RegisterServiceCtrlHandlerExA);
130 RESOLVE_SYMBOL(ChangeServiceConfig2A);
[70196]131 RESOLVE_SYMBOL(GetNamedSecurityInfoA);
132 RESOLVE_SYMBOL(SetEntriesInAclA);
133 RESOLVE_SYMBOL(SetNamedSecurityInfoA);
[70214]134 RESOLVE_SYMBOL(LsaNtStatusToWinError);
[70171]135 RTLdrClose(hLdrMod);
136 }
137
138 /* From KERNEL32.DLL: */
[70267]139 rc = RTLdrLoadSystem("kernel32.dll", true /*fNoUnload*/, &hLdrMod);
[70171]140 AssertRC(rc);
141 if (RT_SUCCESS(rc))
142 {
143 RESOLVE_SYMBOL(CreateToolhelp32Snapshot);
144 RESOLVE_SYMBOL(Process32First);
145 RESOLVE_SYMBOL(Process32Next);
146 RESOLVE_SYMBOL(Module32First);
147 RESOLVE_SYMBOL(Module32Next);
[70346]148 RESOLVE_SYMBOL(GetSystemTimeAdjustment);
149 RESOLVE_SYMBOL(SetSystemTimeAdjustment);
[70171]150 RTLdrClose(hLdrMod);
151 }
152
153 /* From NTDLL.DLL: */
[70267]154 rc = RTLdrLoadSystem("ntdll.dll", true /*fNoUnload*/, &hLdrMod);
[70171]155 AssertRC(rc);
156 if (RT_SUCCESS(rc))
157 {
158 RESOLVE_SYMBOL(ZwQuerySystemInformation);
159 RTLdrClose(hLdrMod);
160 }
[70196]161
162 /* From IPHLPAPI.DLL: */
[70267]163 rc = RTLdrLoadSystem("iphlpapi.dll", true /*fNoUnload*/, &hLdrMod);
[70196]164 if (RT_SUCCESS(rc))
165 {
166 RESOLVE_SYMBOL(GetAdaptersInfo);
167 RTLdrClose(hLdrMod);
168 }
169
170 /* From WS2_32.DLL: */
[70267]171 rc = RTLdrLoadSystem("ws2_32.dll", true /*fNoUnload*/, &hLdrMod);
[70196]172 if (RT_SUCCESS(rc))
173 {
174 RESOLVE_SYMBOL(WSAStartup);
175 RESOLVE_SYMBOL(WSACleanup);
176 RESOLVE_SYMBOL(WSASocketA);
177 RESOLVE_SYMBOL(WSAIoctl);
178 RESOLVE_SYMBOL(WSAGetLastError);
179 RESOLVE_SYMBOL(closesocket);
180 RESOLVE_SYMBOL(inet_ntoa);
181 RTLdrClose(hLdrMod);
182 }
[70171]183}
184
185
186/**
[19374]187 * @todo Add full unicode support.
188 * @todo Add event log capabilities / check return values.
189 */
[99828]190static int vgsvcWinAddAceToObjectsSecurityDescriptor(LPCSTR pszObjName, SE_OBJECT_TYPE enmObjectType, const char *pszTrustee,
[70196]191 TRUSTEE_FORM enmTrusteeForm, DWORD dwAccessRights, ACCESS_MODE fAccessMode,
192 DWORD dwInheritance)
[19374]193{
[70196]194 int rc;
195 if ( g_pfnGetNamedSecurityInfoA
196 && g_pfnSetEntriesInAclA
197 && g_pfnSetNamedSecurityInfoA)
198 {
199 /* Get a pointer to the existing DACL. */
200 PSECURITY_DESCRIPTOR pSD = NULL;
201 PACL pOldDACL = NULL;
202 DWORD rcWin = g_pfnGetNamedSecurityInfoA(pszObjName, enmObjectType, DACL_SECURITY_INFORMATION,
203 NULL, NULL, &pOldDACL, NULL, &pSD);
204 if (rcWin == ERROR_SUCCESS)
205 {
206 /* Initialize an EXPLICIT_ACCESS structure for the new ACE. */
207 EXPLICIT_ACCESSA ExplicitAccess;
208 RT_ZERO(ExplicitAccess);
209 ExplicitAccess.grfAccessPermissions = dwAccessRights;
210 ExplicitAccess.grfAccessMode = fAccessMode;
211 ExplicitAccess.grfInheritance = dwInheritance;
212 ExplicitAccess.Trustee.TrusteeForm = enmTrusteeForm;
213 ExplicitAccess.Trustee.ptstrName = (char *)pszTrustee;
[19374]214
[70196]215 /* Create a new ACL that merges the new ACE into the existing DACL. */
216 PACL pNewDACL = NULL;
217 rcWin = g_pfnSetEntriesInAclA(1, &ExplicitAccess, pOldDACL, &pNewDACL);
218 if (rcWin == ERROR_SUCCESS)
219 {
220 /* Attach the new ACL as the object's DACL. */
[99828]221 rcWin = g_pfnSetNamedSecurityInfoA((PSTR)pszObjName, enmObjectType, DACL_SECURITY_INFORMATION,
[70196]222 NULL, NULL, pNewDACL, NULL);
223 if (rcWin == ERROR_SUCCESS)
224 rc = VINF_SUCCESS;
225 else
226 {
227 VGSvcError("AddAceToObjectsSecurityDescriptor: SetNamedSecurityInfo: Error %u\n", rcWin);
228 rc = RTErrConvertFromWin32(rcWin);
229 }
230 if (pNewDACL)
231 LocalFree(pNewDACL);
232 }
233 else
234 {
235 VGSvcError("AddAceToObjectsSecurityDescriptor: SetEntriesInAcl: Error %u\n", rcWin);
236 rc = RTErrConvertFromWin32(rcWin);
237 }
238 if (pSD)
239 LocalFree(pSD);
240 }
[23139]241 else
[70196]242 {
243 if (rcWin == ERROR_FILE_NOT_FOUND)
244 VGSvcError("AddAceToObjectsSecurityDescriptor: Object not found/installed: %s\n", pszObjName);
245 else
246 VGSvcError("AddAceToObjectsSecurityDescriptor: GetNamedSecurityInfo: Error %u\n", rcWin);
247 rc = RTErrConvertFromWin32(rcWin);
248 }
[19374]249 }
[70196]250 else
251 rc = VINF_SUCCESS; /* fake it */
252 return rc;
[19374]253}
254
[25166]255
[26136]256/** Reports our current status to the SCM. */
[58029]257static BOOL vgsvcWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint)
[19374]258{
[29817]259 if (g_hWinServiceStatus == NULL) /* Program could be in testing mode, so no service environment available. */
[19374]260 return FALSE;
261
[58029]262 VGSvcVerbose(2, "Setting service status to: %ld\n", dwStatus);
[29817]263 g_dwWinServiceLastStatus = dwStatus;
[19374]264
265 SERVICE_STATUS ss;
[44114]266 RT_ZERO(ss);
267
[19374]268 ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
[29817]269 ss.dwCurrentState = dwStatus;
[44114]270 /* Don't accept controls when in start pending state. */
271 if (ss.dwCurrentState != SERVICE_START_PENDING)
272 {
273 ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
[70171]274
275 /* Don't use SERVICE_ACCEPT_SESSIONCHANGE on Windows 2000 or earlier. This makes SCM angry. */
[44114]276 char szOSVersion[32];
[70171]277 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSVersion, sizeof(szOSVersion));
[44114]278 if (RT_SUCCESS(rc))
279 {
280 if (RTStrVersionCompare(szOSVersion, "5.1") >= 0)
281 ss.dwControlsAccepted |= SERVICE_ACCEPT_SESSIONCHANGE;
282 }
283 else
[58029]284 VGSvcError("Error determining OS version, rc=%Rrc\n", rc);
[44114]285 }
286
[25159]287 ss.dwWin32ExitCode = NO_ERROR;
288 ss.dwServiceSpecificExitCode = 0; /* Not used */
289 ss.dwCheckPoint = dwCheckPoint;
[19374]290 ss.dwWaitHint = 3000;
291
[44114]292 BOOL fStatusSet = SetServiceStatus(g_hWinServiceStatus, &ss);
293 if (!fStatusSet)
[58029]294 VGSvcError("Error reporting service status=%ld (controls=%x, checkpoint=%ld) to SCM: %ld\n",
[70171]295 dwStatus, ss.dwControlsAccepted, dwCheckPoint, GetLastError());
[44114]296 return fStatusSet;
[19374]297}
298
[25166]299
[29817]300/**
301 * Reports SERVICE_STOP_PENDING to SCM.
302 *
303 * @param uCheckPoint Some number.
304 */
[58029]305void VGSvcWinSetStopPendingStatus(uint32_t uCheckPoint)
[25959]306{
[58029]307 vgsvcWinSetStatus(SERVICE_STOP_PENDING, uCheckPoint);
[29817]308}
309
310
[58029]311static RTEXITCODE vgsvcWinSetDesc(SC_HANDLE hService)
[29817]312{
[26136]313 /* On W2K+ there's ChangeServiceConfig2() which lets us set some fields
[25959]314 like a longer service description. */
[70171]315 if (g_pfnChangeServiceConfig2A)
[25959]316 {
[70171]317 /** @todo On Vista+ SERVICE_DESCRIPTION also supports localized strings! */
318 SERVICE_DESCRIPTION desc;
[99828]319 desc.lpDescription = (LPSTR)VBOXSERVICE_DESCRIPTION;
[70171]320 if (!g_pfnChangeServiceConfig2A(hService, SERVICE_CONFIG_DESCRIPTION, &desc))
321 {
322 VGSvcError("Cannot set the service description! Error: %ld\n", GetLastError());
323 return RTEXITCODE_FAILURE;
324 }
[25959]325 }
[29817]326 return RTEXITCODE_SUCCESS;
[25959]327}
328
329
[29817]330/**
331 * Installs the service.
332 */
[58029]333RTEXITCODE VGSvcWinInstall(void)
[19374]334{
[58029]335 VGSvcVerbose(1, "Installing service ...\n");
[19374]336
[29817]337 TCHAR imagePath[MAX_PATH] = { 0 };
338 GetModuleFileName(NULL, imagePath, sizeof(imagePath));
[19374]339
[29817]340 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
341 if (hSCManager == NULL)
[25795]342 {
[58029]343 VGSvcError("Could not open SCM! Error: %ld\n", GetLastError());
[29817]344 return RTEXITCODE_FAILURE;
[19374]345 }
346
[29817]347 RTEXITCODE rc = RTEXITCODE_SUCCESS;
348 SC_HANDLE hService = CreateService(hSCManager,
349 VBOXSERVICE_NAME, VBOXSERVICE_FRIENDLY_NAME,
350 SERVICE_ALL_ACCESS,
351 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
352 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
353 imagePath, NULL, NULL, NULL, NULL, NULL);
354 if (hService != NULL)
[58029]355 VGSvcVerbose(0, "Service successfully installed!\n");
[29817]356 else
[25795]357 {
358 DWORD dwErr = GetLastError();
359 switch (dwErr)
360 {
[29817]361 case ERROR_SERVICE_EXISTS:
[58029]362 VGSvcVerbose(1, "Service already exists, just updating the service config.\n");
[29817]363 hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS);
364 if (hService)
[25795]365 {
[83974]366 if (ChangeServiceConfig(hService,
367 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
368 SERVICE_DEMAND_START,
369 SERVICE_ERROR_NORMAL,
370 imagePath,
371 NULL,
372 NULL,
373 NULL,
374 NULL,
375 NULL,
376 VBOXSERVICE_FRIENDLY_NAME))
[58029]377 VGSvcVerbose(1, "The service config has been successfully updated.\n");
[29817]378 else
[58029]379 rc = VGSvcError("Could not change service config! Error: %ld\n", GetLastError());
[25795]380 }
381 else
[58029]382 rc = VGSvcError("Could not open service! Error: %ld\n", GetLastError());
[29817]383 break;
[25795]384
[29817]385 default:
[58029]386 rc = VGSvcError("Could not create service! Error: %ld\n", dwErr);
[29817]387 break;
[25795]388 }
[19374]389 }
390
[29817]391 if (rc == RTEXITCODE_SUCCESS)
[58029]392 rc = vgsvcWinSetDesc(hService);
[25959]393
[19374]394 CloseServiceHandle(hService);
395 CloseServiceHandle(hSCManager);
[25795]396 return rc;
[19374]397}
398
[29817]399/**
400 * Uninstalls the service.
401 */
[58029]402RTEXITCODE VGSvcWinUninstall(void)
[19374]403{
[58029]404 VGSvcVerbose(1, "Uninstalling service ...\n");
[19374]405
[29817]406 SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
407 if (hSCManager == NULL)
408 {
[58029]409 VGSvcError("Could not open SCM! Error: %d\n", GetLastError());
[29817]410 return RTEXITCODE_FAILURE;
[19374]411 }
412
[29817]413 RTEXITCODE rcExit;
414 SC_HANDLE hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS );
415 if (hService != NULL)
416 {
417 if (DeleteService(hService))
418 {
419 /*
420 * ???
421 */
422 HKEY hKey = NULL;
423 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
424 "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System",
425 0,
426 KEY_ALL_ACCESS,
427 &hKey)
428 == ERROR_SUCCESS)
429 {
430 RegDeleteKey(hKey, VBOXSERVICE_NAME);
431 RegCloseKey(hKey);
432 }
[19374]433
[58029]434 VGSvcVerbose(0, "Service successfully uninstalled!\n");
[29817]435 rcExit = RTEXITCODE_SUCCESS;
436 }
437 else
[58029]438 rcExit = VGSvcError("Could not remove service! Error: %d\n", GetLastError());
[29817]439 CloseServiceHandle(hService);
[19374]440 }
441 else
[58029]442 rcExit = VGSvcError("Could not open service! Error: %d\n", GetLastError());
[19374]443 CloseServiceHandle(hSCManager);
444
[29817]445 return rcExit;
[19374]446}
447
[25166]448
[58029]449static int vgsvcWinStart(void)
[19374]450{
451 int rc = VINF_SUCCESS;
452
[70196]453 /*
454 * Create a well-known SID for the "Builtin Users" group and modify the ACE
455 * for the shared folders miniport redirector DN (whatever DN means).
456 */
[70171]457 PSID pBuiltinUsersSID = NULL;
458 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY;
459 if (AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_LOCAL_RID, 0, 0, 0, 0, 0, 0, 0, &pBuiltinUsersSID))
[19374]460 {
[99828]461 rc = vgsvcWinAddAceToObjectsSecurityDescriptor("\\\\.\\VBoxMiniRdrDN", SE_FILE_OBJECT,
[70196]462 (LPTSTR)pBuiltinUsersSID, TRUSTEE_IS_SID,
463 FILE_GENERIC_READ | FILE_GENERIC_WRITE, SET_ACCESS, NO_INHERITANCE);
464 /* If we don't find our "VBoxMiniRdrDN" (for Shared Folders) object above,
465 don't report an error; it just might be not installed. Otherwise this
466 would cause the SCM to hang on starting up the service. */
467 if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND)
468 rc = VINF_SUCCESS;
469
470 FreeSid(pBuiltinUsersSID);
[19374]471 }
[70171]472 else
473 rc = RTErrConvertFromWin32(GetLastError());
[19374]474 if (RT_SUCCESS(rc))
475 {
[70196]476 /*
477 * Start the service.
478 */
[58029]479 vgsvcWinSetStatus(SERVICE_START_PENDING, 0);
[44114]480
[58029]481 rc = VGSvcStartServices();
[29817]482 if (RT_SUCCESS(rc))
483 {
[58029]484 vgsvcWinSetStatus(SERVICE_RUNNING, 0);
485 VGSvcMainWait();
[29817]486 }
487 else
[36331]488 {
[58029]489 vgsvcWinSetStatus(SERVICE_STOPPED, 0);
[36331]490#if 0 /** @todo r=bird: Enable this if SERVICE_CONTROL_STOP isn't triggered automatically */
[58029]491 VGSvcStopServices();
[36331]492#endif
493 }
[19374]494 }
[36338]495 else
[58029]496 vgsvcWinSetStatus(SERVICE_STOPPED, 0);
[19374]497
498 if (RT_FAILURE(rc))
[58029]499 VGSvcError("Service failed to start with rc=%Rrc!\n", rc);
[19374]500
501 return rc;
502}
503
[25166]504
[29817]505/**
506 * Call StartServiceCtrlDispatcher.
507 *
508 * The main() thread invokes this when not started in foreground mode. It
509 * won't return till the service is being shutdown (unless start up fails).
510 *
511 * @returns RTEXITCODE_SUCCESS on normal return after service shutdown.
512 * Something else on failure, error will have been reported.
513 */
[58029]514RTEXITCODE VGSvcWinEnterCtrlDispatcher(void)
[29817]515{
516 if (!StartServiceCtrlDispatcher(&g_aServiceTable[0]))
[58029]517 return VGSvcError("StartServiceCtrlDispatcher: %u. Please start %s with option -f (foreground)!\n",
[70171]518 GetLastError(), g_pszProgName);
[29817]519 return RTEXITCODE_SUCCESS;
520}
521
522
[70171]523/**
524 * Event code to description.
525 *
526 * @returns String.
527 * @param dwEvent The event code.
528 */
529static const char *vgsvcWTSStateToString(DWORD dwEvent)
[40158]530{
531 switch (dwEvent)
532 {
[70171]533 case WTS_CONSOLE_CONNECT: return "A session was connected to the console terminal";
534 case WTS_CONSOLE_DISCONNECT: return "A session was disconnected from the console terminal";
535 case WTS_REMOTE_CONNECT: return "A session connected to the remote terminal";
536 case WTS_REMOTE_DISCONNECT: return "A session was disconnected from the remote terminal";
537 case WTS_SESSION_LOGON: return "A user has logged on to a session";
538 case WTS_SESSION_LOGOFF: return "A user has logged off the session";
539 case WTS_SESSION_LOCK: return "A session has been locked";
540 case WTS_SESSION_UNLOCK: return "A session has been unlocked";
541 case WTS_SESSION_REMOTE_CONTROL: return "A session has changed its remote controlled status";
542#ifdef WTS_SESSION_CREATE
543 case WTS_SESSION_CREATE: return "A session has been created";
[40158]544#endif
[70171]545#ifdef WTS_SESSION_TERMINATE
546 case WTS_SESSION_TERMINATE: return "The session has been terminated";
547#endif
548 default: return "Uknonwn state";
[40158]549 }
550}
551
552
[70171]553/**
554 * Common control handler.
555 *
556 * @returns Return code for NT5+.
557 * @param dwControl The control code.
558 */
559static DWORD vgsvcWinCtrlHandlerCommon(DWORD dwControl)
[19374]560{
[62851]561 DWORD rcRet = NO_ERROR;
[19374]562 switch (dwControl)
563 {
[29817]564 case SERVICE_CONTROL_INTERROGATE:
[58029]565 vgsvcWinSetStatus(g_dwWinServiceLastStatus, 0);
[29817]566 break;
[19374]567
[29817]568 case SERVICE_CONTROL_STOP:
569 case SERVICE_CONTROL_SHUTDOWN:
[19374]570 {
[58029]571 vgsvcWinSetStatus(SERVICE_STOP_PENDING, 0);
[19374]572
[58029]573 int rc2 = VGSvcStopServices();
[29817]574 if (RT_FAILURE(rc2))
575 rcRet = ERROR_GEN_FAILURE;
[36338]576 else
577 {
[58029]578 rc2 = VGSvcReportStatus(VBoxGuestFacilityStatus_Terminated);
[36338]579 AssertRC(rc2);
580 }
[19374]581
[58029]582 vgsvcWinSetStatus(SERVICE_STOPPED, 0);
[29817]583 break;
[19374]584 }
585
[70171]586 default:
587 VGSvcVerbose(1, "Control handler: Function not implemented: %#x\n", dwControl);
588 rcRet = ERROR_CALL_NOT_IMPLEMENTED;
589 break;
590 }
591
592 return rcRet;
593}
594
595
596/**
597 * Callback registered by RegisterServiceCtrlHandler on NT4 and earlier.
598 */
[85121]599static VOID WINAPI vgsvcWinCtrlHandlerNt4(DWORD dwControl) RT_NOTHROW_DEF
[70171]600{
601 VGSvcVerbose(2, "Control handler (NT4): dwControl=%#x\n", dwControl);
602 vgsvcWinCtrlHandlerCommon(dwControl);
603}
604
605
606/**
607 * Callback registered by RegisterServiceCtrlHandler on NT5 and later.
608 */
[85121]609static DWORD WINAPI
610vgsvcWinCtrlHandlerNt5Plus(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) RT_NOTHROW_DEF
[70171]611{
612 VGSvcVerbose(2, "Control handler: dwControl=%#x, dwEventType=%#x\n", dwControl, dwEventType);
613 RT_NOREF1(lpContext);
614
615 switch (dwControl)
616 {
617 default:
618 return vgsvcWinCtrlHandlerCommon(dwControl);
619
620 case SERVICE_CONTROL_SESSIONCHANGE: /* Only Windows 2000 and up. */
[40158]621 {
622 AssertPtr(lpEventData);
623 PWTSSESSION_NOTIFICATION pNotify = (PWTSSESSION_NOTIFICATION)lpEventData;
624 Assert(pNotify->cbSize == sizeof(WTSSESSION_NOTIFICATION));
[19374]625
[58029]626 VGSvcVerbose(1, "Control handler: %s (Session=%ld, Event=%#x)\n",
[70171]627 vgsvcWTSStateToString(dwEventType), pNotify->dwSessionId, dwEventType);
[40158]628
629 /* Handle all events, regardless of dwEventType. */
[58029]630 int rc2 = VGSvcVMInfoSignal();
[40158]631 AssertRC(rc2);
[70171]632
633 return NO_ERROR;
[40158]634 }
[19374]635 }
636}
637
[25166]638
[58029]639static void WINAPI vgsvcWinMain(DWORD argc, LPTSTR *argv)
[19374]640{
[62851]641 RT_NOREF2(argc, argv);
[58029]642 VGSvcVerbose(2, "Registering service control handler ...\n");
[70171]643 if (g_pfnRegisterServiceCtrlHandlerExA)
644 g_hWinServiceStatus = g_pfnRegisterServiceCtrlHandlerExA(VBOXSERVICE_NAME, vgsvcWinCtrlHandlerNt5Plus, NULL);
645 else
646 g_hWinServiceStatus = RegisterServiceCtrlHandlerA(VBOXSERVICE_NAME, vgsvcWinCtrlHandlerNt4);
[29817]647 if (g_hWinServiceStatus != NULL)
[19374]648 {
[58029]649 VGSvcVerbose(2, "Service control handler registered.\n");
650 vgsvcWinStart();
[29817]651 }
652 else
653 {
[19374]654 DWORD dwErr = GetLastError();
655 switch (dwErr)
656 {
[29817]657 case ERROR_INVALID_NAME:
[58029]658 VGSvcError("Invalid service name!\n");
[29817]659 break;
660 case ERROR_SERVICE_DOES_NOT_EXIST:
[58029]661 VGSvcError("Service does not exist!\n");
[29817]662 break;
663 default:
[58029]664 VGSvcError("Could not register service control handle! Error: %ld\n", dwErr);
[29817]665 break;
[19374]666 }
667 }
[29817]668}
[19374]669
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use