VirtualBox

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

Last change on this file since 36249 was 35715, checked in by vboxsync, 14 years ago

Newline.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.1 KB
Line 
1/* $Id: VBoxService-win.cpp 35715 2011-01-25 14:34:26Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions Service Skeleton, Windows Specific Parts.
4 */
5
6/*
7 * Copyright (C) 2009-2010 Oracle Corporation
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
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <iprt/assert.h>
23#include <iprt/err.h>
24#include <VBox/VBoxGuestLib.h>
25#include "VBoxServiceInternal.h"
26
27#include <Windows.h>
28#include <process.h>
29#include <aclapi.h>
30
31
32/*******************************************************************************
33* Internal Functions *
34*******************************************************************************/
35static void WINAPI vboxServiceWinMain(DWORD argc, LPTSTR *argv);
36
37
38/*******************************************************************************
39* Global Variables *
40*******************************************************************************/
41static DWORD g_dwWinServiceLastStatus = 0;
42SERVICE_STATUS_HANDLE g_hWinServiceStatus = NULL;
43/** The semaphore for the dummy Windows service. */
44static RTSEMEVENT g_WindowsEvent = NIL_RTSEMEVENT;
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 */
58static DWORD 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 l_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 l_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 l_Cleanup;
111 }
112
113 /** @todo get rid of that spaghetti jump ... */
114l_Cleanup:
115
116 if(pSD != NULL)
117 LocalFree((HLOCAL) pSD);
118 if(pNewDACL != NULL)
119 LocalFree((HLOCAL) pNewDACL);
120
121 return dwRes;
122}
123
124
125/** Reports our current status to the SCM. */
126static BOOL vboxServiceWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint)
127{
128 if (g_hWinServiceStatus == NULL) /* Program could be in testing mode, so no service environment available. */
129 return FALSE;
130
131 VBoxServiceVerbose(2, "Setting service status to: %ld\n", dwStatus);
132 g_dwWinServiceLastStatus = dwStatus;
133
134 SERVICE_STATUS ss;
135 ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
136 ss.dwCurrentState = dwStatus;
137 ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
138 ss.dwWin32ExitCode = NO_ERROR;
139 ss.dwServiceSpecificExitCode = 0; /* Not used */
140 ss.dwCheckPoint = dwCheckPoint;
141 ss.dwWaitHint = 3000;
142
143 return SetServiceStatus(g_hWinServiceStatus, &ss);
144}
145
146
147/**
148 * Reports SERVICE_STOP_PENDING to SCM.
149 *
150 * @param uCheckPoint Some number.
151 */
152void VBoxServiceWinSetStopPendingStatus(uint32_t uCheckPoint)
153{
154 vboxServiceWinSetStatus(SERVICE_STOP_PENDING, uCheckPoint);
155}
156
157
158static RTEXITCODE vboxServiceWinSetDesc(SC_HANDLE hService)
159{
160#ifndef TARGET_NT4
161 /* On W2K+ there's ChangeServiceConfig2() which lets us set some fields
162 like a longer service description. */
163 /** @todo On Vista+ SERVICE_DESCRIPTION also supports localized strings! */
164 SERVICE_DESCRIPTION desc;
165 desc.lpDescription = VBOXSERVICE_DESCRIPTION;
166 if (!ChangeServiceConfig2(hService,
167 SERVICE_CONFIG_DESCRIPTION, /* Service info level */
168 &desc))
169 {
170 VBoxServiceError("Cannot set the service description! Error: %ld\n", GetLastError());
171 return RTEXITCODE_FAILURE;
172 }
173#endif
174 return RTEXITCODE_SUCCESS;
175}
176
177
178/**
179 * Installs the service.
180 */
181RTEXITCODE VBoxServiceWinInstall(void)
182{
183 VBoxServiceVerbose(1, "Installing service ...\n");
184
185 TCHAR imagePath[MAX_PATH] = { 0 };
186 GetModuleFileName(NULL, imagePath, sizeof(imagePath));
187
188 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
189 if (hSCManager == NULL)
190 {
191 VBoxServiceError("Could not open SCM! Error: %ld\n", GetLastError());
192 return RTEXITCODE_FAILURE;
193 }
194
195 RTEXITCODE rc = RTEXITCODE_SUCCESS;
196 SC_HANDLE hService = CreateService(hSCManager,
197 VBOXSERVICE_NAME, VBOXSERVICE_FRIENDLY_NAME,
198 SERVICE_ALL_ACCESS,
199 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
200 SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
201 imagePath, NULL, NULL, NULL, NULL, NULL);
202 if (hService != NULL)
203 VBoxServiceVerbose(0, "Service successfully installed!\n");
204 else
205 {
206 DWORD dwErr = GetLastError();
207 switch (dwErr)
208 {
209 case ERROR_SERVICE_EXISTS:
210 VBoxServiceVerbose(1, "Service already exists, just updating the service config.\n");
211 hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS);
212 if (hService)
213 {
214 if (ChangeServiceConfig (hService,
215 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
216 SERVICE_DEMAND_START,
217 SERVICE_ERROR_NORMAL,
218 imagePath,
219 NULL,
220 NULL,
221 NULL,
222 NULL,
223 NULL,
224 VBOXSERVICE_FRIENDLY_NAME))
225 VBoxServiceVerbose(1, "The service config has been successfully updated.\n");
226 else
227 rc = VBoxServiceError("Could not change service config! Error: %ld\n", GetLastError());
228 }
229 else
230 rc = VBoxServiceError("Could not open service! Error: %ld\n", GetLastError());
231 break;
232
233 default:
234 rc = VBoxServiceError("Could not create service! Error: %ld\n", dwErr);
235 break;
236 }
237 }
238
239 if (rc == RTEXITCODE_SUCCESS)
240 rc = vboxServiceWinSetDesc(hService);
241
242 CloseServiceHandle(hService);
243 CloseServiceHandle(hSCManager);
244 return rc;
245}
246
247/**
248 * Uninstalls the service.
249 */
250RTEXITCODE VBoxServiceWinUninstall(void)
251{
252 VBoxServiceVerbose(1, "Uninstalling service ...\n");
253
254 SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
255 if (hSCManager == NULL)
256 {
257 VBoxServiceError("Could not open SCM! Error: %d\n", GetLastError());
258 return RTEXITCODE_FAILURE;
259 }
260
261 RTEXITCODE rcExit;
262 SC_HANDLE hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS );
263 if (hService != NULL)
264 {
265 if (DeleteService(hService))
266 {
267 /*
268 * ???
269 */
270 HKEY hKey = NULL;
271 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
272 "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System",
273 0,
274 KEY_ALL_ACCESS,
275 &hKey)
276 == ERROR_SUCCESS)
277 {
278 RegDeleteKey(hKey, VBOXSERVICE_NAME);
279 RegCloseKey(hKey);
280 }
281
282 VBoxServiceVerbose(0, "Service successfully uninstalled!\n");
283 rcExit = RTEXITCODE_SUCCESS;
284 }
285 else
286 rcExit = VBoxServiceError("Could not remove service! Error: %d\n", GetLastError());
287 CloseServiceHandle(hService);
288 }
289 else
290 rcExit = VBoxServiceError("Could not open service! Error: %d\n", GetLastError());
291 CloseServiceHandle(hSCManager);
292
293 return rcExit;
294}
295
296
297static int vboxServiceWinStart(void)
298{
299 int rc = VINF_SUCCESS;
300
301#ifndef TARGET_NT4
302 /* Create a well-known SID for the "Builtin Users" group. */
303 PSID pBuiltinUsersSID = NULL;
304 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY;
305
306 if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
307 SECURITY_LOCAL_RID,
308 0, 0, 0, 0, 0, 0, 0,
309 &pBuiltinUsersSID))
310 {
311 /**@todo r=bird: rc = RTErrConvertFromWin32(GetLastError()); ?*/
312 VBoxServiceError("AllocateAndInitializeSid: Error %u\n", GetLastError());
313 }
314 else
315 {
316 DWORD dwRes = vboxServiceWinAddAceToObjectsSecurityDescriptor(TEXT("\\\\.\\VBoxMiniRdrDN"),
317 SE_FILE_OBJECT,
318 (LPTSTR)pBuiltinUsersSID,
319 TRUSTEE_IS_SID,
320 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
321 SET_ACCESS,
322 NO_INHERITANCE);
323 if (dwRes != ERROR_SUCCESS)
324 {
325 if (dwRes == ERROR_FILE_NOT_FOUND)
326 {
327 /* If we don't find our "VBoxMiniRdrDN" (for Shared Folders) object above,
328 don't report an error; it just might be not installed. Otherwise this
329 would cause the SCM to hang on starting up the service. */
330 rc = VINF_SUCCESS;
331 }
332 else
333 rc = RTErrConvertFromWin32(dwRes);
334 }
335 }
336#endif
337
338 if (RT_SUCCESS(rc))
339 {
340 rc = VBoxServiceStartServices();
341 if (RT_SUCCESS(rc))
342 {
343 vboxServiceWinSetStatus(SERVICE_RUNNING, 0);
344 VBoxServiceMainWait();
345 }
346 else
347 vboxServiceWinSetStatus(SERVICE_STOPPED, 0);
348 }
349 /**@todo r=bird: else vboxServiceWinSetStatus(SERVICE_STOPPED, 0); ? */
350
351 if (RT_FAILURE(rc))
352 VBoxServiceError("Service failed to start with rc=%Rrc!\n", rc);
353
354 return rc;
355}
356
357
358/**
359 * Call StartServiceCtrlDispatcher.
360 *
361 * The main() thread invokes this when not started in foreground mode. It
362 * won't return till the service is being shutdown (unless start up fails).
363 *
364 * @returns RTEXITCODE_SUCCESS on normal return after service shutdown.
365 * Something else on failure, error will have been reported.
366 */
367RTEXITCODE VBoxServiceWinEnterCtrlDispatcher(void)
368{
369 if (!StartServiceCtrlDispatcher(&g_aServiceTable[0]))
370 return VBoxServiceError("StartServiceCtrlDispatcher: %u. Please start %s with option -f (foreground)!\n",
371 GetLastError(), g_pszProgName);
372 return RTEXITCODE_SUCCESS;
373}
374
375
376#ifdef TARGET_NT4
377static VOID WINAPI vboxServiceWinCtrlHandler(DWORD dwControl)
378#else
379static DWORD WINAPI vboxServiceWinCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
380#endif
381{
382 DWORD rcRet = NO_ERROR;
383
384#ifdef TARGET_NT4
385 VBoxServiceVerbose(2, "Control handler: Control=%#x\n", dwControl);
386#else
387 VBoxServiceVerbose(2, "Control handler: Control=%#x EventType=%#x\n", dwControl, dwEventType);
388#endif
389
390 switch (dwControl)
391 {
392 case SERVICE_CONTROL_INTERROGATE:
393 vboxServiceWinSetStatus(g_dwWinServiceLastStatus, 0);
394 break;
395
396 case SERVICE_CONTROL_STOP:
397 case SERVICE_CONTROL_SHUTDOWN:
398 {
399 vboxServiceWinSetStatus(SERVICE_STOP_PENDING, 0);
400
401 int rc2 = VBoxServiceStopServices();
402 if (RT_FAILURE(rc2))
403 rcRet = ERROR_GEN_FAILURE;
404
405 vboxServiceWinSetStatus(SERVICE_STOPPED, 0);
406 break;
407 }
408
409 case SERVICE_CONTROL_SESSIONCHANGE: /* Only Win XP and up. */
410#ifndef TARGET_NT4
411# if 0
412 switch (dwEventType)
413 {
414 case WTS_SESSION_LOGON:
415 VBoxServiceVerbose(2, "A user has logged on to the session.\n");
416 break;
417
418 case WTS_SESSION_LOGOFF:
419 VBoxServiceVerbose(2, "A user has logged off from the session.\n");
420 break;
421 default:
422 break;
423 }
424# endif
425#endif /* !TARGET_NT4 */
426 break;
427
428 default:
429 VBoxServiceVerbose(1, "Service control function not implemented: %#x\n", dwControl);
430 rcRet = ERROR_CALL_NOT_IMPLEMENTED;
431 break;
432 }
433
434#ifndef TARGET_NT4
435 return rcRet;
436#endif
437}
438
439
440static void WINAPI vboxServiceWinMain(DWORD argc, LPTSTR *argv)
441{
442 VBoxServiceVerbose(2, "Registering service control handler ...\n");
443#ifdef TARGET_NT4
444 g_hWinServiceStatus = RegisterServiceCtrlHandler(VBOXSERVICE_NAME, vboxServiceWinCtrlHandler);
445#else
446 g_hWinServiceStatus = RegisterServiceCtrlHandlerEx(VBOXSERVICE_NAME, vboxServiceWinCtrlHandler, NULL);
447#endif
448 if (g_hWinServiceStatus != NULL)
449 {
450 VBoxServiceVerbose(2, "Service control handler registered.\n");
451 vboxServiceWinStart();
452 }
453 else
454 {
455 DWORD dwErr = GetLastError();
456 switch (dwErr)
457 {
458 case ERROR_INVALID_NAME:
459 VBoxServiceError("Invalid service name!\n");
460 break;
461 case ERROR_SERVICE_DOES_NOT_EXIST:
462 VBoxServiceError("Service does not exist!\n");
463 break;
464 default:
465 VBoxServiceError("Could not register service control handle! Error: %ld\n", dwErr);
466 break;
467 }
468 }
469}
470
Note: See TracBrowser for help on using the repository browser.

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