VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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