VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxService/VBoxService.cpp@ 11982

最後變更 在這個檔案從11982是 11982,由 vboxsync 提交於 17 年 前

All: license header changes for 2.0 (OSE headers, add Sun GPL/LGPL disclaimer)

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 15.5 KB
 
1/* $Id: VBoxService.cpp 11982 2008-09-02 13:09:44Z vboxsync $ */
2/** @file
3 * VBoxService - The Guest Additions Helper Service.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * Sun Microsystems, Inc. confidential
10 * All rights reserved
11 */
12
13#include "VBoxService.h"
14#ifdef VBOX_WITH_GUEST_PROPS
15 #include "VBoxVMInfo.h"
16#endif
17#include "resource.h"
18
19#define VBOXSERVICE_NAME _T("VBoxService")
20#define VBOXSERVICE_FRIENDLY_NAME _T("VBoxService")
21
22/* Global variables. */
23HANDLE gvboxDriver;
24HANDLE gStopSem;
25
26SERVICE_STATUS gvboxServiceStatus;
27DWORD gvboxServiceStatusCode;
28SERVICE_STATUS_HANDLE gvboxServiceStatusHandle;
29
30VBOXSERVICEENV gServiceEnv;
31
32/* Prototypes. */
33void writeLog (char* a_pszText, ...);
34
35/* The service table. */
36static VBOXSERVICEINFO vboxServiceTable[] =
37{
38#ifdef VBOX_WITH_GUEST_PROPS
39 {
40 "VMInfo",
41 vboxVMInfoInit,
42 vboxVMInfoThread,
43 vboxVMInfoDestroy,
44 },
45#endif
46 {
47 NULL
48 }
49};
50
51/**
52 * @todo Format code style.
53 * @todo Add full unicode support.
54 * @todo Add event log capabilities / check return values.
55 */
56
57DWORD AddAceToObjectsSecurityDescriptor (LPTSTR pszObjName,
58 SE_OBJECT_TYPE ObjectType,
59 LPTSTR pszTrustee,
60 TRUSTEE_FORM TrusteeForm,
61 DWORD dwAccessRights,
62 ACCESS_MODE AccessMode,
63 DWORD dwInheritance)
64{
65 DWORD dwRes = 0;
66 PACL pOldDACL = NULL, pNewDACL = NULL;
67 PSECURITY_DESCRIPTOR pSD = NULL;
68 EXPLICIT_ACCESS ea;
69
70 if (NULL == pszObjName)
71 return ERROR_INVALID_PARAMETER;
72
73 /* Get a pointer to the existing DACL. */
74 dwRes = GetNamedSecurityInfo(pszObjName, ObjectType,
75 DACL_SECURITY_INFORMATION,
76 NULL, NULL, &pOldDACL, NULL, &pSD);
77 if (ERROR_SUCCESS != dwRes) {
78 writeLog("VBoxService: GetNamedSecurityInfo: Error %u\n", dwRes);
79 goto Cleanup;
80 }
81
82 /* Initialize an EXPLICIT_ACCESS structure for the new ACE. */
83 ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
84 ea.grfAccessPermissions = dwAccessRights;
85 ea.grfAccessMode = AccessMode;
86 ea.grfInheritance= dwInheritance;
87 ea.Trustee.TrusteeForm = TrusteeForm;
88 ea.Trustee.ptstrName = pszTrustee;
89
90 /* Create a new ACL that merges the new ACE into the existing DACL. */
91 dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
92 if (ERROR_SUCCESS != dwRes) {
93 writeLog("VBoxService: 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 writeLog("VBoxService: SetNamedSecurityInfo: Error %u\n", dwRes);
103 goto Cleanup;
104 }
105
106Cleanup:
107
108 if(pSD != NULL)
109 LocalFree((HLOCAL) pSD);
110 if(pNewDACL != NULL)
111 LocalFree((HLOCAL) pNewDACL);
112
113 return dwRes;
114}
115
116static void SetStatus (DWORD a_dwStatus)
117{
118 if (NULL == gvboxServiceStatusHandle) /* Program could be in testing mode, so no service environment available. */
119 return;
120
121 gvboxServiceStatusCode = a_dwStatus;
122
123 SERVICE_STATUS ss;
124 ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
125 ss.dwCurrentState = gvboxServiceStatusCode;
126 ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
127 ss.dwWin32ExitCode = NOERROR;
128 ss.dwServiceSpecificExitCode = NOERROR;
129 ss.dwCheckPoint = 0;
130 ss.dwWaitHint = 3000;
131
132 SetServiceStatus (gvboxServiceStatusHandle, &ss);
133}
134
135static int vboxStartServices (VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
136{
137 Log(("VBoxService: Starting services ...\n"));
138
139 pEnv->hStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
140
141 if (!pEnv->hStopEvent)
142 {
143 /* Could not create event. */
144 return VERR_NOT_SUPPORTED;
145 }
146
147 while (pTable->pszName)
148 {
149 Log(("VBoxService: Starting %s ...\n", pTable->pszName));
150
151 int rc = VINF_SUCCESS;
152
153 bool fStartThread = false;
154
155 pTable->hThread = (HANDLE)0;
156 pTable->pInstance = NULL;
157 pTable->fStarted = false;
158
159 if (pTable->pfnInit)
160 {
161 rc = pTable->pfnInit (pEnv, &pTable->pInstance, &fStartThread);
162 }
163
164 if (VBOX_FAILURE (rc))
165 {
166 writeLog("VBoxService: Failed to initialize! Error = %Vrc.\n", rc);
167 }
168 else
169 {
170 if (pTable->pfnThread && fStartThread)
171 {
172 unsigned threadid;
173
174 pTable->hThread = (HANDLE)_beginthreadex (NULL, /* security */
175 0, /* stacksize */
176 pTable->pfnThread,
177 pTable->pInstance,
178 0, /* initflag */
179 &threadid);
180
181 if (pTable->hThread == (HANDLE)(0))
182 {
183 rc = VERR_NOT_SUPPORTED;
184 }
185 }
186
187 if (VBOX_FAILURE (rc))
188 {
189 Log(("VBoxService: Failed to start the thread: %s\n", pTable->pszName));
190
191 if (pTable->pfnDestroy)
192 {
193 pTable->pfnDestroy (pEnv, pTable->pInstance);
194 }
195 }
196 else
197 {
198 pTable->fStarted = true;
199 }
200 }
201
202 /* Advance to next table element. */
203 pTable++;
204 }
205
206 Log(("VBoxService: All threads started.\n"));
207 return VINF_SUCCESS;
208}
209
210static void vboxStopServices (BOOL bAlert, VBOXSERVICEENV *pEnv, VBOXSERVICEINFO *pTable)
211{
212 /* Signal to all threads. */
213 if (bAlert && (NULL != pEnv->hStopEvent))
214 {
215 Log(("VBoxService: Setting stop event ...\n"));
216 SetEvent(pEnv->hStopEvent);
217 }
218
219 while (pTable->pszName)
220 {
221 if (pTable->fStarted)
222 {
223 if (pTable->pfnThread)
224 {
225 Log(("VBoxService: Waiting for thread %s to close ...\n", pTable->pszName));
226
227 /* There is a thread, wait for termination. */
228 WaitForSingleObject(pTable->hThread, INFINITE);
229
230 CloseHandle (pTable->hThread);
231 pTable->hThread = 0;
232 }
233
234 if (pTable->pfnDestroy)
235 {
236 pTable->pfnDestroy (pEnv, pTable->pInstance);
237 }
238
239 pTable->fStarted = false;
240 }
241
242 /* Advance to next table element. */
243 pTable++;
244 }
245
246 CloseHandle (pEnv->hStopEvent);
247 SetStatus (SERVICE_STOPPED);
248}
249
250void vboxServiceStart()
251{
252 gStopSem = CreateEvent(NULL, TRUE, FALSE, NULL);
253 if (gStopSem == NULL)
254 {
255 writeLog("VBoxService: CreateEvent for stopping failed: rc = %d\n", GetLastError());
256 return;
257 }
258
259 /* Create a well-known SID for the "Builtin Users" group. */
260 PSID pBuiltinUsersSID = NULL;
261 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY;
262
263 if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
264 SECURITY_LOCAL_RID,
265 0, 0, 0, 0, 0, 0, 0,
266 &pBuiltinUsersSID))
267 {
268 writeLog("VBoxService: AllocateAndInitializeSid: Error %u\n", GetLastError());
269 }
270
271 AddAceToObjectsSecurityDescriptor (TEXT("\\\\.\\VBoxMiniRdrDN"),
272 SE_FILE_OBJECT,
273 (LPTSTR)pBuiltinUsersSID,
274 TRUSTEE_IS_SID,
275 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
276 SET_ACCESS,
277 NO_INHERITANCE);
278
279 /* Start service threads. */
280 /*gServiceEnv.hInstance = gInstance;
281 gServiceEnv.hDriver = gVBoxDriver;*/
282
283 int rc = vboxStartServices (&gServiceEnv, vboxServiceTable);
284
285 /** @todo Add error handling. */
286
287 SetStatus (SERVICE_RUNNING);
288}
289
290DWORD WINAPI ServiceCtrlHandler (DWORD dwControl,
291 DWORD dwEventType,
292 LPVOID lpEventData,
293 LPVOID lpContext)
294{
295 switch (dwControl)
296 {
297
298 case SERVICE_CONTROL_INTERROGATE:
299 SetStatus (gvboxServiceStatusCode);
300 break;
301
302 case SERVICE_CONTROL_STOP:
303 case SERVICE_CONTROL_SHUTDOWN:
304 {
305 SetStatus (SERVICE_STOP_PENDING);
306
307 vboxStopServices (TRUE, &gServiceEnv, vboxServiceTable);
308
309 /*CloseHandle(gvboxDriver);*/
310 CloseHandle(gStopSem);
311
312 SetStatus (SERVICE_STOPPED);
313 }
314 break;
315
316 case SERVICE_CONTROL_SESSIONCHANGE: /* Only Win XP and up. */
317
318 switch (dwEventType)
319 {
320 case WTS_SESSION_LOGON:
321 Log(("VBoxService: A user has logged on to the session.\n"));
322 break;
323 case WTS_SESSION_LOGOFF:
324 Log(("VBoxService: A user has logged off from the session.\n"));
325 break;
326 default:
327 break;
328 }
329 break;
330
331 default:
332 /** @todo r=bird: Andy, you should probably return ERROR_CALL_NOT_IMPLEMENTED here.
333 * Whoever omitted the DWORD return here and WINAPI bit here has been very sloppy :-| */
334 break;
335 }
336 return NO_ERROR;
337}
338
339void WINAPI ServiceMain (DWORD argc, LPTSTR *argv)
340{
341 Log(("VBoxService: Registering service control handler ...\n"));
342 gvboxServiceStatusHandle = RegisterServiceCtrlHandlerEx (VBOXSERVICE_NAME, ServiceCtrlHandler, NULL);
343
344 if (NULL == gvboxServiceStatusHandle)
345 {
346 DWORD dwErr = GetLastError();
347
348 switch (dwErr)
349 {
350 case ERROR_INVALID_NAME:
351 writeLog("VBoxService: Invalid service name!\n");
352 break;
353 case ERROR_SERVICE_DOES_NOT_EXIST:
354 writeLog("VBoxService: Service does not exist!\n");
355 break;
356 default:
357 writeLog("VBoxService: Could not register service control handle! Error: %d\n", dwErr);
358 break;
359 }
360 }
361 else
362 {
363 vboxServiceStart();
364
365 while( 1) {
366 Sleep( 100 ); /** @todo */
367 }
368 }
369}
370
371int Install ()
372{
373 SC_HANDLE hService, hSCManager;
374 TCHAR imagePath[MAX_PATH] = { 0 };
375
376 GetModuleFileName(NULL,imagePath,MAX_PATH);
377 writeLog("VBoxService: Installing service ...\n");
378
379 hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
380
381 if (NULL == hSCManager) {
382 writeLog("VBoxService: Could not open SCM! Error: %d\n", GetLastError());
383 return 1;
384 }
385
386 hService = ::CreateService (hSCManager,
387 VBOXSERVICE_NAME, VBOXSERVICE_FRIENDLY_NAME,
388 SERVICE_ALL_ACCESS,
389 SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,
390 SERVICE_DEMAND_START,SERVICE_ERROR_NORMAL,
391 imagePath, NULL, NULL, NULL, NULL, NULL);
392
393 if (NULL == hService) {
394 writeLog("VBoxService: Could not create service! Error: %d\n", GetLastError());
395 CloseServiceHandle (hSCManager);
396 return 1;
397 }
398 else
399 {
400 writeLog("VBoxService: Service successfully installed!\n");
401 }
402
403 CloseServiceHandle (hService);
404 CloseServiceHandle (hSCManager);
405
406 return 0;
407}
408
409int Uninstall ()
410{
411 SC_HANDLE hService, hSCManager;
412 hSCManager = OpenSCManager (NULL,NULL,SC_MANAGER_ALL_ACCESS);
413
414 writeLog("VBoxService: Uninstalling service ...\n");
415
416 if (NULL == hSCManager) {
417 writeLog("VBoxService: Could not open SCM! Error: %d\n", GetLastError());
418 return 1;
419 }
420
421 hService = OpenService (hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS );
422 if (NULL == hService) {
423 writeLog("VBoxService: Could not open service! Error: %d\n", GetLastError());
424 CloseServiceHandle (hSCManager);
425 return 1;
426 }
427
428 if (FALSE == DeleteService (hService))
429 {
430 writeLog("VBoxService: Could not remove service! Error: %d\n", GetLastError());
431 CloseServiceHandle (hService);
432 CloseServiceHandle (hSCManager);
433 return 1;
434 }
435 else
436 {
437 HKEY hKey;
438 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\System"), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) {
439 RegDeleteKey (hKey, VBOXSERVICE_NAME);
440 RegCloseKey (hKey);
441 }
442
443 writeLog("VBoxService: Service successfully uninstalled!\n");
444 }
445
446 CloseServiceHandle (hService);
447 CloseServiceHandle (hSCManager);
448
449 return 0;
450}
451
452void writeLog (char* a_pszText, ...)
453{
454 char szBuffer[1024] = { 0 };
455
456 va_list va;
457 va_start(va, a_pszText);
458
459 RTStrPrintfV(szBuffer, sizeof(szBuffer), a_pszText, va);
460 printf(szBuffer);
461 LogRel((szBuffer));
462
463 va_end(va);
464}
465
466void printHelp (_TCHAR* a_pszName)
467{
468 _tprintf(_T("VBoxService - Guest Additions Helper Service for Windows XP/2K/Vista\n"));
469 _tprintf(_T("Version: %d.%d.%d.%d\n\n"), VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD, VBOX_SVN_REV);
470 _tprintf(_T("Syntax:\n"));
471 _tprintf(_T("\tTo install: %ws /i\n"), a_pszName);
472 _tprintf(_T("\tTo uninstall: %ws /u\n"), a_pszName);
473 _tprintf(_T("\tTo execute from command line: %ws /t\n"), a_pszName);
474 _tprintf(_T("\tThis help text: %ws /h\n"), a_pszName);
475}
476
477int _tmain(int argc, _TCHAR* argv[])
478{
479 /* Do not use a global namespace ("Global\\") for mutex name here, will blow up NT4 compatibility! */
480 HANDLE hMutexAppRunning = CreateMutex (NULL, FALSE, VBOXSERVICE_NAME);
481 if ( (hMutexAppRunning != NULL)
482 && (GetLastError() == ERROR_ALREADY_EXISTS))
483 {
484 /* Close the mutex for this application instance. */
485 CloseHandle(hMutexAppRunning);
486 hMutexAppRunning = NULL;
487 }
488
489 int rc = RTR3Init();
490 if (RT_FAILURE(rc))
491 {
492 writeLog("VBoxService: Failed to initialise the VirtualBox runtime! Error: %d\n", rc);
493 return rc;
494 }
495
496 rc = VbglR3Init();
497 if (RT_FAILURE(rc))
498 {
499 writeLog("VBoxService: Failed to contact the VirtualBox host! Program maybe not running in a VM? Error: %d\n", rc);
500 return rc;
501 }
502
503 LogRel(("VBoxService: Started.\n"));
504
505 static SERVICE_TABLE_ENTRY const s_serviceTable[]=
506 {
507 { VBOXSERVICE_NAME, ServiceMain },
508 {NULL,NULL}
509 };
510
511 if (argc > 1)
512 {
513 if (0 == _tcsicmp(argv[1], _T("/i")))
514 Install();
515 else if (0 == _tcsicmp(argv[1], _T("/u")))
516 Uninstall();
517 else if (0 == _tcsicmp(argv[1], _T("/t")))
518 {
519 vboxServiceStart();
520
521 while (1) {
522 Sleep( 100 ); /** @todo */
523 }
524 }
525 else if (0 == _tcsicmp(argv[1], _T("/h")))
526 printHelp(argv[0]);
527
528 else {
529 _tprintf (_T("Invalid command line argument: %ws\n"), argv[1]);
530 _tprintf (_T("Type %s /h to display help.\n"), argv[0]);
531 }
532 }
533 else /* Normal service. */
534 {
535 if (FALSE == StartServiceCtrlDispatcher (s_serviceTable))
536 printHelp(argv[0]); /* Application called from command line, print some help. */
537 }
538
539 /* Release instance mutex. */
540 if (hMutexAppRunning != NULL) {
541 CloseHandle (hMutexAppRunning);
542 hMutexAppRunning = NULL;
543 }
544
545 writeLog("VBoxService: Ended.\n");
546
547 VbglR3Term();
548 return 0;
549}
550
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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