VirtualBox

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

Last change on this file since 25795 was 25795, checked in by vboxsync, 15 years ago

VBoxService: Added service description for SCM running on W2K+.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: VBoxService-win.cpp 25795 2010-01-13 08:43:46Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions Service Skeleton, Windows Specific Parts.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <iprt/assert.h>
27#include <iprt/err.h>
28#include <iprt/ldr.h>
29#include <VBox/VBoxGuestLib.h>
30#include "VBoxServiceInternal.h"
31
32#include <Windows.h>
33#include <process.h>
34#include <aclapi.h>
35
36DWORD g_rcWinService = 0;
37SERVICE_STATUS_HANDLE g_hWinServiceStatus = NULL;
38
39/** Dynamically loaded function ChangeServiceConfig2() which is not available in NT4. */
40typedef BOOL (WINAPI FNCHANGESERVICECONFIG2) (SC_HANDLE hService, DWORD dwInfoLevel, LPVOID lpInfo);
41/** Pointer to FNCHANGESERVICECONFIG2. */
42typedef FNCHANGESERVICECONFIG2 *PFNCHANGESERVICECONFIG2;
43
44void WINAPI VBoxServiceWinMain (DWORD argc, LPTSTR *argv);
45
46static SERVICE_TABLE_ENTRY const g_aServiceTable[]=
47{
48 {VBOXSERVICE_NAME, VBoxServiceWinMain},
49 {NULL,NULL}
50};
51
52
53/**
54 * @todo Format code style.
55 * @todo Add full unicode support.
56 * @todo Add event log capabilities / check return values.
57 */
58DWORD VBoxServiceWinAddAceToObjectsSecurityDescriptor(LPTSTR pszObjName,
59 SE_OBJECT_TYPE ObjectType,
60 LPTSTR pszTrustee,
61 TRUSTEE_FORM TrusteeForm,
62 DWORD dwAccessRights,
63 ACCESS_MODE AccessMode,
64 DWORD dwInheritance)
65{
66 DWORD dwRes = 0;
67 PACL pOldDACL = NULL, pNewDACL = NULL;
68 PSECURITY_DESCRIPTOR pSD = NULL;
69 EXPLICIT_ACCESS ea;
70
71 if (NULL == pszObjName)
72 return ERROR_INVALID_PARAMETER;
73
74 /* Get a pointer to the existing DACL. */
75 dwRes = GetNamedSecurityInfo(pszObjName, ObjectType,
76 DACL_SECURITY_INFORMATION,
77 NULL, NULL, &pOldDACL, NULL, &pSD);
78 if (ERROR_SUCCESS != dwRes)
79 {
80 if (dwRes == ERROR_FILE_NOT_FOUND)
81 VBoxServiceError("AddAceToObjectsSecurityDescriptor: Object not found/installed: %s\n", pszObjName);
82 else
83 VBoxServiceError("AddAceToObjectsSecurityDescriptor: GetNamedSecurityInfo: Error %u\n", dwRes);
84 goto Cleanup;
85 }
86
87 /* Initialize an EXPLICIT_ACCESS structure for the new ACE. */
88 ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
89 ea.grfAccessPermissions = dwAccessRights;
90 ea.grfAccessMode = AccessMode;
91 ea.grfInheritance= dwInheritance;
92 ea.Trustee.TrusteeForm = TrusteeForm;
93 ea.Trustee.ptstrName = pszTrustee;
94
95 /* Create a new ACL that merges the new ACE into the existing DACL. */
96 dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
97 if (ERROR_SUCCESS != dwRes)
98 {
99 VBoxServiceError("AddAceToObjectsSecurityDescriptor: SetEntriesInAcl: Error %u\n", dwRes);
100 goto Cleanup;
101 }
102
103 /* Attach the new ACL as the object's DACL. */
104 dwRes = SetNamedSecurityInfo(pszObjName, ObjectType,
105 DACL_SECURITY_INFORMATION,
106 NULL, NULL, pNewDACL, NULL);
107 if (ERROR_SUCCESS != dwRes)
108 {
109 VBoxServiceError("AddAceToObjectsSecurityDescriptor: SetNamedSecurityInfo: Error %u\n", dwRes);
110 goto Cleanup;
111 }
112
113 /** @todo get rid of that spaghetti jump ... */
114Cleanup:
115
116 if(pSD != NULL)
117 LocalFree((HLOCAL) pSD);
118 if(pNewDACL != NULL)
119 LocalFree((HLOCAL) pNewDACL);
120
121 return dwRes;
122}
123
124
125BOOL VBoxServiceWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint)
126{
127 if (NULL == g_hWinServiceStatus) /* Program could be in testing mode, so no service environment available. */
128 return FALSE;
129
130 VBoxServiceVerbose(2, "Setting service status to: %ld\n", dwStatus);
131 g_rcWinService = dwStatus;
132
133 SERVICE_STATUS ss;
134 ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
135 ss.dwCurrentState = g_rcWinService;
136 ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
137 ss.dwWin32ExitCode = NO_ERROR;
138 ss.dwServiceSpecificExitCode = 0; /* Not used */
139 ss.dwCheckPoint = dwCheckPoint;
140 ss.dwWaitHint = 3000;
141
142 return SetServiceStatus(g_hWinServiceStatus, &ss);
143}
144
145
146int VBoxServiceWinInstall(void)
147{
148 SC_HANDLE hService, hSCManager;
149 TCHAR imagePath[MAX_PATH] = { 0 };
150
151 GetModuleFileName(NULL,imagePath,MAX_PATH);
152 VBoxServiceVerbose(1, "Installing service ...\n");
153
154 hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
155
156 if (NULL == hSCManager)
157 {
158 VBoxServiceError("Could not open SCM! Error: %ld\n", GetLastError());
159 return 1;
160 }
161
162 hService = ::CreateService (hSCManager,
163 VBOXSERVICE_NAME, VBOXSERVICE_FRIENDLY_NAME,
164 SERVICE_ALL_ACCESS,
165 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
166 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
167 imagePath, NULL, NULL, NULL, NULL, NULL);
168 int rc = VINF_SUCCESS;
169 if (NULL == hService)
170 {
171 DWORD dwErr = GetLastError();
172 switch (dwErr)
173 {
174
175 case ERROR_SERVICE_EXISTS:
176
177 VBoxServiceVerbose(1, "Service already exists, just updating the service config.\n");
178 hService = OpenService (hSCManager,
179 VBOXSERVICE_NAME,
180 SERVICE_ALL_ACCESS);
181 if (NULL == hService)
182 {
183 VBoxServiceError("Could not open service! Error: %ld\n", GetLastError());
184 rc = 1;
185 }
186 else
187 {
188 if (ChangeServiceConfig (hService,
189 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
190 SERVICE_DEMAND_START,
191 SERVICE_ERROR_NORMAL,
192 imagePath,
193 NULL,
194 NULL,
195 NULL,
196 NULL,
197 NULL,
198 VBOXSERVICE_FRIENDLY_NAME))
199 {
200 /* On W2K+ there's ChangeServiceConfig2() which lets us set some fields
201 like a longer service description. */
202 #ifndef TARGET_NT4
203 SERVICE_DESCRIPTION desc;
204 /** @todo On Vista+ SERVICE_DESCRIPTION also supports localized strings! */
205 desc. lpDescription = VBOXSERVICE_DESCRIPTION;
206 if (FALSE == ChangeServiceConfig2(hService,
207 SERVICE_CONFIG_DESCRIPTION, /* Service info level */
208 &desc))
209 {
210 VBoxServiceError("Cannot set the service description! Error: %ld\n", GetLastError());
211 }
212 #endif
213
214 VBoxServiceVerbose(1, "The service config has been successfully updated.\n");
215 }
216 else
217 {
218 VBoxServiceError("Could not change service config! Error: %ld\n", GetLastError());
219 rc = 1;
220 }
221 }
222 break;
223
224 default:
225
226 VBoxServiceError("Could not create service! Error: %ld\n", dwErr);
227 rc = 1;
228 break;
229 }
230 }
231 else
232 {
233 VBoxServiceVerbose(0, "Service successfully installed!\n");
234 }
235
236 CloseServiceHandle(hService);
237 CloseServiceHandle(hSCManager);
238 return rc;
239}
240
241int VBoxServiceWinUninstall(void)
242{
243 SC_HANDLE hService, hSCManager;
244 hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
245
246 VBoxServiceVerbose(1, "Uninstalling service ...\n");
247
248 if (NULL == hSCManager) {
249 VBoxServiceError("Could not open SCM! Error: %d\n", GetLastError());
250 return 1;
251 }
252
253 hService = OpenService (hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS );
254 if (NULL == hService) {
255 VBoxServiceError("Could not open service! Error: %d\n", GetLastError());
256 CloseServiceHandle (hSCManager);
257 return 1;
258 }
259
260 if (FALSE == DeleteService (hService))
261 {
262 VBoxServiceError("Could not remove service! Error: %d\n", GetLastError());
263 CloseServiceHandle (hService);
264 CloseServiceHandle (hSCManager);
265 return 1;
266 }
267 else
268 {
269 HKEY hKey = NULL;
270 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System", 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) {
271 RegDeleteKey(hKey, VBOXSERVICE_NAME);
272 RegCloseKey(hKey);
273 }
274
275 VBoxServiceVerbose(0, "Service successfully uninstalled!\n");
276 }
277
278 CloseServiceHandle(hService);
279 CloseServiceHandle(hSCManager);
280
281 return 0;
282}
283
284
285int VBoxServiceWinStart(void)
286{
287 int rc = VINF_SUCCESS;
288
289#ifndef TARGET_NT4
290 /* Create a well-known SID for the "Builtin Users" group. */
291 PSID pBuiltinUsersSID = NULL;
292 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY;
293
294 if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
295 SECURITY_LOCAL_RID,
296 0, 0, 0, 0, 0, 0, 0,
297 &pBuiltinUsersSID))
298 {
299 VBoxServiceError("AllocateAndInitializeSid: Error %u\n", GetLastError());
300 }
301 else
302 {
303 DWORD dwRes = VBoxServiceWinAddAceToObjectsSecurityDescriptor (TEXT("\\\\.\\VBoxMiniRdrDN"),
304 SE_FILE_OBJECT,
305 (LPTSTR)pBuiltinUsersSID,
306 TRUSTEE_IS_SID,
307 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
308 SET_ACCESS,
309 NO_INHERITANCE);
310 if (dwRes != ERROR_SUCCESS)
311 {
312 if (dwRes == ERROR_FILE_NOT_FOUND)
313 {
314 /* If we don't find our "VBoxMiniRdrDN" (for Shared Folders) object above,
315 don't report an error; it just might be not installed. Otherwise this
316 would cause the SCM to hang on starting up the service. */
317 rc = VINF_SUCCESS;
318 }
319 else rc = RTErrConvertFromWin32(dwRes);
320 }
321 }
322#endif
323
324 if (RT_SUCCESS(rc))
325 {
326 /* Notify SCM *before* we're starting the services, because the last services
327 always starts in main thread (which causes the SCM to wait because of the non-responding
328 service). */
329 VBoxServiceWinSetStatus (SERVICE_RUNNING, 0);
330
331 /*
332 * Check that at least one service is enabled.
333 */
334 unsigned iMain = VBoxServiceGetStartedServices();
335 rc = VBoxServiceStartServices(iMain); /* Start all the services. */
336
337 if (RT_FAILURE(rc))
338 VBoxServiceWinSetStatus (SERVICE_STOPPED, 0);
339 }
340
341 if (RT_FAILURE(rc))
342 VBoxServiceError("Service failed to start with rc=%Rrc!\n", rc);
343
344 return rc;
345}
346
347
348#ifdef TARGET_NT4
349VOID WINAPI VBoxServiceWinCtrlHandler(DWORD dwControl)
350#else
351DWORD WINAPI VBoxServiceWinCtrlHandler(DWORD dwControl,
352 DWORD dwEventType,
353 LPVOID lpEventData,
354 LPVOID lpContext)
355#endif
356{
357 DWORD rc = NO_ERROR;
358
359 VBoxServiceVerbose(2, "Control handler: Control=%ld\n", dwControl);
360#ifndef TARGET_NT4
361 VBoxServiceVerbose(2, "Control handler: EventType=%ld\n", dwEventType);
362#endif
363
364 switch (dwControl)
365 {
366
367 case SERVICE_CONTROL_INTERROGATE:
368 VBoxServiceWinSetStatus(g_rcWinService, 0);
369 break;
370
371 case SERVICE_CONTROL_STOP:
372 case SERVICE_CONTROL_SHUTDOWN:
373 {
374 VBoxServiceWinSetStatus(SERVICE_STOP_PENDING, 0);
375
376 rc = VBoxServiceStopServices();
377
378 VBoxServiceWinSetStatus(SERVICE_STOPPED, 0);
379 }
380 break;
381
382 case SERVICE_CONTROL_SESSIONCHANGE: /* Only Win XP and up. */
383
384#ifndef TARGET_NT4
385 switch (dwEventType)
386 {
387 /*case WTS_SESSION_LOGON:
388 VBoxServiceVerbose(2, "A user has logged on to the session.\n");
389 break;
390
391 case WTS_SESSION_LOGOFF:
392 VBoxServiceVerbose(2, "A user has logged off from the session.\n");
393 break;*/
394 default:
395 break;
396 }
397#endif /* TARGET_NT4 */
398 break;
399
400 default:
401
402 VBoxServiceVerbose(1, "Service control function not implemented: %ld\n", dwControl);
403 rc = ERROR_CALL_NOT_IMPLEMENTED;
404 break;
405 }
406
407#ifndef TARGET_NT4
408 return rc;
409#endif
410}
411
412
413void WINAPI VBoxServiceWinMain(DWORD argc, LPTSTR *argv)
414{
415 int rc = VINF_SUCCESS;
416
417 VBoxServiceVerbose(2, "Registering service control handler ...\n");
418#ifdef TARGET_NT4
419 g_hWinServiceStatus = RegisterServiceCtrlHandler (VBOXSERVICE_NAME, VBoxServiceWinCtrlHandler);
420#else
421 g_hWinServiceStatus = RegisterServiceCtrlHandlerEx (VBOXSERVICE_NAME, VBoxServiceWinCtrlHandler, NULL);
422#endif
423
424 if (NULL == g_hWinServiceStatus)
425 {
426 DWORD dwErr = GetLastError();
427
428 switch (dwErr)
429 {
430 case ERROR_INVALID_NAME:
431 VBoxServiceError("Invalid service name!\n");
432 break;
433 case ERROR_SERVICE_DOES_NOT_EXIST:
434 VBoxServiceError("Service does not exist!\n");
435 break;
436 default:
437 VBoxServiceError("Could not register service control handle! Error: %ld\n", dwErr);
438 break;
439 }
440 }
441 else
442 {
443 VBoxServiceVerbose(2, "Service control handler registered.\n");
444
445 rc = VBoxServiceWinStart();
446 }
447}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette