VirtualBox

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

Last change on this file since 11938 was 11938, checked in by vboxsync, 16 years ago

Additions/Win/VBoxService to OSE

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