VirtualBox

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

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

Misc svn:eol-style correction and some manual cleanup.

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