static void WINAPI vgsvcWinMain(DWORD argc, LPTSTR *argv) { RT_NOREF2(argc, argv); VGSvcVerbose(2, "Registering service control handler ...\n"); if (g_pfnRegisterServiceCtrlHandlerExA) g_hWinServiceStatus = g_pfnRegisterServiceCtrlHandlerExA(VBOXSERVICE_NAME, vgsvcWinCtrlHandlerNt5Plus, NULL); else g_hWinServiceStatus = RegisterServiceCtrlHandlerA(VBOXSERVICE_NAME, vgsvcWinCtrlHandlerNt4); if (g_hWinServiceStatus != NULL) { VGSvcVerbose(2, "Service control handler registered.\n"); vgsvcWinStart(); } else { DWORD dwErr = GetLastError(); switch (dwErr) { case ERROR_INVALID_NAME: VGSvcError("Invalid service name!\n"); break; case ERROR_SERVICE_DOES_NOT_EXIST: VGSvcError("Service does not exist!\n"); break; default: VGSvcError("Could not register service control handle! Error: %ld\n", dwErr); break; } } }
/** * Call StartServiceCtrlDispatcher. * * The main() thread invokes this when not started in foreground mode. It * won't return till the service is being shutdown (unless start up fails). * * @returns RTEXITCODE_SUCCESS on normal return after service shutdown. * Something else on failure, error will have been reported. */ RTEXITCODE VGSvcWinEnterCtrlDispatcher(void) { if (!StartServiceCtrlDispatcher(&g_aServiceTable[0])) return VGSvcError("StartServiceCtrlDispatcher: %u. Please start %s with option -f (foreground)!\n", GetLastError(), g_pszProgName); return RTEXITCODE_SUCCESS; }
/** * Try adjust the time using adjtime or similar. * * @returns true on success, false on failure. * * @param pDrift The time adjustment. */ static void vgsvcTimeSyncSet(PCRTTIMESPEC pDrift) { /* * Query the current time, adjust it by adding the drift and set it. */ RTTIMESPEC NewGuestTime; int rc = RTTimeSet(RTTimeSpecAdd(RTTimeNow(&NewGuestTime), pDrift)); if (RT_SUCCESS(rc)) { /* Succeeded - reset the error count and log the change. */ g_cTimeSyncErrors = 0; if (g_cVerbosity >= 1) { char sz[64]; RTTIME Time; VGSvcVerbose(1, "time set to %s\n", RTTimeToString(RTTimeExplode(&Time, &NewGuestTime), sz, sizeof(sz))); #ifdef DEBUG RTTIMESPEC Tmp; if (g_cVerbosity >= 3) VGSvcVerbose(3, " now %s\n", RTTimeToString(RTTimeExplode(&Time, RTTimeNow(&Tmp)), sz, sizeof(sz))); #endif } } else if (g_cTimeSyncErrors++ < 10) VGSvcError("vgsvcTimeSyncSet: RTTimeSet(%RDtimespec) failed: %Rrc\n", &NewGuestTime, rc); }
/** * Console control event callback. * * @returns TRUE if handled, FALSE if not. * @param dwCtrlType The control event type. * * @remarks This is generally called on a new thread, so we're racing every * other thread in the process. */ static BOOL WINAPI vgsvcWinConsoleControlHandler(DWORD dwCtrlType) { int rc = VINF_SUCCESS; bool fEventHandled = FALSE; switch (dwCtrlType) { /* User pressed CTRL+C or CTRL+BREAK or an external event was sent * via GenerateConsoleCtrlEvent(). */ case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: case CTRL_C_EVENT: VGSvcVerbose(2, "ControlHandler: Received break/close event\n"); rc = VGSvcStopServices(); fEventHandled = TRUE; break; default: break; /** @todo Add other events here. */ } if (RT_FAILURE(rc)) VGSvcError("ControlHandler: Event %ld handled with error rc=%Rrc\n", dwCtrlType, rc); return fEventHandled; }
/** * Uninstalls the service. */ RTEXITCODE VGSvcWinUninstall(void) { VGSvcVerbose(1, "Uninstalling service ...\n"); SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS); if (hSCManager == NULL) { VGSvcError("Could not open SCM! Error: %d\n", GetLastError()); return RTEXITCODE_FAILURE; } RTEXITCODE rcExit; SC_HANDLE hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS ); if (hService != NULL) { if (DeleteService(hService)) { /* * ??? */ HKEY hKey = NULL; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System", 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { RegDeleteKey(hKey, VBOXSERVICE_NAME); RegCloseKey(hKey); } VGSvcVerbose(0, "Service successfully uninstalled!\n"); rcExit = RTEXITCODE_SUCCESS; } else rcExit = VGSvcError("Could not remove service! Error: %d\n", GetLastError()); CloseServiceHandle(hService); } else rcExit = VGSvcError("Could not open service! Error: %d\n", GetLastError()); CloseServiceHandle(hSCManager); return rcExit; }
static int vgsvcWinStart(void) { int rc = VINF_SUCCESS; /* * Create a well-known SID for the "Builtin Users" group and modify the ACE * for the shared folders miniport redirector DN (whatever DN means). */ PSID pBuiltinUsersSID = NULL; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY; if (AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_LOCAL_RID, 0, 0, 0, 0, 0, 0, 0, &pBuiltinUsersSID)) { rc = vgsvcWinAddAceToObjectsSecurityDescriptor(TEXT("\\\\.\\VBoxMiniRdrDN"), SE_FILE_OBJECT, (LPTSTR)pBuiltinUsersSID, TRUSTEE_IS_SID, FILE_GENERIC_READ | FILE_GENERIC_WRITE, SET_ACCESS, NO_INHERITANCE); /* If we don't find our "VBoxMiniRdrDN" (for Shared Folders) object above, don't report an error; it just might be not installed. Otherwise this would cause the SCM to hang on starting up the service. */ if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND) rc = VINF_SUCCESS; FreeSid(pBuiltinUsersSID); } else rc = RTErrConvertFromWin32(GetLastError()); if (RT_SUCCESS(rc)) { /* * Start the service. */ vgsvcWinSetStatus(SERVICE_START_PENDING, 0); rc = VGSvcStartServices(); if (RT_SUCCESS(rc)) { vgsvcWinSetStatus(SERVICE_RUNNING, 0); VGSvcMainWait(); } else { vgsvcWinSetStatus(SERVICE_STOPPED, 0); #if 0 /** @todo r=bird: Enable this if SERVICE_CONTROL_STOP isn't triggered automatically */ VGSvcStopServices(); #endif } } else vgsvcWinSetStatus(SERVICE_STOPPED, 0); if (RT_FAILURE(rc)) VGSvcError("Service failed to start with rc=%Rrc!\n", rc); return rc; }
/** Reports our current status to the SCM. */ static BOOL vgsvcWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint) { if (g_hWinServiceStatus == NULL) /* Program could be in testing mode, so no service environment available. */ return FALSE; VGSvcVerbose(2, "Setting service status to: %ld\n", dwStatus); g_dwWinServiceLastStatus = dwStatus; SERVICE_STATUS ss; RT_ZERO(ss); ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ss.dwCurrentState = dwStatus; /* Don't accept controls when in start pending state. */ if (ss.dwCurrentState != SERVICE_START_PENDING) { ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; /* Don't use SERVICE_ACCEPT_SESSIONCHANGE on Windows 2000 or earlier. This makes SCM angry. */ char szOSVersion[32]; int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szOSVersion, sizeof(szOSVersion)); if (RT_SUCCESS(rc)) { if (RTStrVersionCompare(szOSVersion, "5.1") >= 0) ss.dwControlsAccepted |= SERVICE_ACCEPT_SESSIONCHANGE; } else VGSvcError("Error determining OS version, rc=%Rrc\n", rc); } ss.dwWin32ExitCode = NO_ERROR; ss.dwServiceSpecificExitCode = 0; /* Not used */ ss.dwCheckPoint = dwCheckPoint; ss.dwWaitHint = 3000; BOOL fStatusSet = SetServiceStatus(g_hWinServiceStatus, &ss); if (!fStatusSet) VGSvcError("Error reporting service status=%ld (controls=%x, checkpoint=%ld) to SCM: %ld\n", dwStatus, ss.dwControlsAccepted, dwCheckPoint, GetLastError()); return fStatusSet; }
/** * Lazily calls the pfnPreInit method on each service. * * @returns VBox status code, error message displayed. */ static RTEXITCODE vgsvcLazyPreInit(void) { for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) if (!g_aServices[j].fPreInited) { int rc = g_aServices[j].pDesc->pfnPreInit(); if (RT_FAILURE(rc)) return VGSvcError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName, rc); g_aServices[j].fPreInited = true; } return RTEXITCODE_SUCCESS; }
/** * Cancels any pending time adjustment. * * Called when we've caught up and before calls to vgsvcTimeSyncSet. */ static void vgsvcTimeSyncCancelAdjust(void) { #ifdef RT_OS_WINDOWS /** @todo r=bird: g_hTokenProcess cannot be NULL here. See argumentation in * vgsvcTimeSyncAdjust. */ if (g_hTokenProcess == NULL) /* No process token (anymore)? */ return; if (SetSystemTimeAdjustment(0, TRUE /* Periodic adjustments disabled. */)) VGSvcVerbose(3, "vgsvcTimeSyncCancelAdjust: Windows Time Adjustment is now disabled.\n"); else if (g_cTimeSyncErrors++ < 10) VGSvcError("vgsvcTimeSyncCancelAdjust: SetSystemTimeAdjustment(,disable) failed, error=%u\n", GetLastError()); #endif /* !RT_OS_WINDOWS */ }
static RTEXITCODE vgsvcWinSetDesc(SC_HANDLE hService) { /* On W2K+ there's ChangeServiceConfig2() which lets us set some fields like a longer service description. */ if (g_pfnChangeServiceConfig2A) { /** @todo On Vista+ SERVICE_DESCRIPTION also supports localized strings! */ SERVICE_DESCRIPTION desc; desc.lpDescription = VBOXSERVICE_DESCRIPTION; if (!g_pfnChangeServiceConfig2A(hService, SERVICE_CONFIG_DESCRIPTION, &desc)) { VGSvcError("Cannot set the service description! Error: %ld\n", GetLastError()); return RTEXITCODE_FAILURE; } } return RTEXITCODE_SUCCESS; }
/** * Reports the current VBoxService status to the host. * * This makes sure that the Failed state is sticky. * * @return IPRT status code. * @param enmStatus Status to report to the host. */ int VGSvcReportStatus(VBoxGuestFacilityStatus enmStatus) { /* * VBoxGuestFacilityStatus_Failed is sticky. */ static VBoxGuestFacilityStatus s_enmLastStatus = VBoxGuestFacilityStatus_Inactive; VGSvcVerbose(4, "Setting VBoxService status to %u\n", enmStatus); if (s_enmLastStatus != VBoxGuestFacilityStatus_Failed) { int rc = VbglR3ReportAdditionsStatus(VBoxGuestFacilityType_VBoxService, enmStatus, 0 /* Flags */); if (RT_FAILURE(rc)) { VGSvcError("Could not report VBoxService status (%u), rc=%Rrc\n", enmStatus, rc); return rc; } s_enmLastStatus = enmStatus; } return VINF_SUCCESS; }
/** * @interface_method_impl{VBOXSERVICE,pfnTerm} */ static DECLCALLBACK(void) vgsvcTimeSyncTerm(void) { #ifdef RT_OS_WINDOWS /* * Restore the SE_SYSTEMTIME_NAME token privileges (if init succeeded). */ if (g_hTokenProcess) { if (!AdjustTokenPrivileges(g_hTokenProcess, FALSE, &g_TkOldPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) { DWORD dwErr = GetLastError(); VGSvcError("vgsvcTimeSyncTerm: Restoring token privileges (SE_SYSTEMTIME_NAME) failed with code %u!\n", dwErr); } CloseHandle(g_hTokenProcess); g_hTokenProcess = NULL; } #endif /* !RT_OS_WINDOWS */ if (g_TimeSyncEvent != NIL_RTSEMEVENTMULTI) { RTSemEventMultiDestroy(g_TimeSyncEvent); g_TimeSyncEvent = NIL_RTSEMEVENTMULTI; } }
/** * @interface_method_impl{VBOXSERVICE,pfnWorker} */ DECLCALLBACK(int) vgsvcTimeSyncWorker(bool volatile *pfShutdown) { RTTIME Time; char sz[64]; int rc = VINF_SUCCESS; /* * Tell the control thread that it can continue spawning services. */ RTThreadUserSignal(RTThreadSelf()); /* * The Work Loop. */ for (;;) { /* * Try get a reliable time reading. */ int cTries = 3; do { /* query it. */ RTTIMESPEC GuestNow0, GuestNow, HostNow; RTTimeNow(&GuestNow0); int rc2 = VbglR3GetHostTime(&HostNow); if (RT_FAILURE(rc2)) { if (g_cTimeSyncErrors++ < 10) VGSvcError("vgsvcTimeSyncWorker: VbglR3GetHostTime failed; rc2=%Rrc\n", rc2); break; } RTTimeNow(&GuestNow); /* calc latency and check if it's ok. */ RTTIMESPEC GuestElapsed = GuestNow; RTTimeSpecSub(&GuestElapsed, &GuestNow0); if ((uint32_t)RTTimeSpecGetMilli(&GuestElapsed) < g_TimeSyncMaxLatency) { /* * Set the time once after we were restored. * (Of course only if the drift is bigger than MinAdjust) */ uint32_t TimeSyncSetThreshold = g_TimeSyncSetThreshold; if (g_fTimeSyncSetOnRestore) { uint64_t idNewSession = g_idTimeSyncSession; VbglR3GetSessionId(&idNewSession); if (idNewSession != g_idTimeSyncSession) { VGSvcVerbose(3, "vgsvcTimeSyncWorker: The VM session ID changed, forcing resync.\n"); TimeSyncSetThreshold = 0; g_idTimeSyncSession = idNewSession; } } /* * Calculate the adjustment threshold and the current drift. */ uint32_t MinAdjust = RTTimeSpecGetMilli(&GuestElapsed) * g_TimeSyncLatencyFactor; if (MinAdjust < g_TimeSyncMinAdjust) MinAdjust = g_TimeSyncMinAdjust; RTTIMESPEC Drift = HostNow; RTTimeSpecSub(&Drift, &GuestNow); if (RTTimeSpecGetMilli(&Drift) < 0) MinAdjust += g_TimeSyncMinAdjust; /* extra buffer against moving time backwards. */ RTTIMESPEC AbsDrift = Drift; RTTimeSpecAbsolute(&AbsDrift); if (g_cVerbosity >= 3) { VGSvcVerbose(3, "vgsvcTimeSyncWorker: Host: %s (MinAdjust: %RU32 ms)\n", RTTimeToString(RTTimeExplode(&Time, &HostNow), sz, sizeof(sz)), MinAdjust); VGSvcVerbose(3, "vgsvcTimeSyncWorker: Guest: - %s => %RDtimespec drift\n", RTTimeToString(RTTimeExplode(&Time, &GuestNow), sz, sizeof(sz)), &Drift); } uint32_t AbsDriftMilli = RTTimeSpecGetMilli(&AbsDrift); if (AbsDriftMilli > MinAdjust) { /* * Ok, the drift is above the threshold. * * Try a gradual adjustment first, if that fails or the drift is * too big, fall back on just setting the time. */ if ( AbsDriftMilli > TimeSyncSetThreshold || g_fTimeSyncSetNext || !vgsvcTimeSyncAdjust(&Drift)) { vgsvcTimeSyncCancelAdjust(); vgsvcTimeSyncSet(&Drift); } } else vgsvcTimeSyncCancelAdjust(); break; } VGSvcVerbose(3, "vgsvcTimeSyncWorker: %RDtimespec: latency too high (%RDtimespec) sleeping 1s\n", GuestElapsed); RTThreadSleep(1000); } while (--cTries > 0); /* Clear the set-next/set-start flag. */ g_fTimeSyncSetNext = false; /* * Block for a while. * * The event semaphore takes care of ignoring interruptions and it * allows us to implement service wakeup later. */ if (*pfShutdown) break; int rc2 = RTSemEventMultiWait(g_TimeSyncEvent, g_TimeSyncInterval); if (*pfShutdown) break; if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2)) { VGSvcError("vgsvcTimeSyncWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2); rc = rc2; break; } } vgsvcTimeSyncCancelAdjust(); RTSemEventMultiDestroy(g_TimeSyncEvent); g_TimeSyncEvent = NIL_RTSEMEVENTMULTI; return rc; }
/** * Stops and terminates the services. * * This should be called even when VBoxServiceStartServices fails so it can * clean up anything that we succeeded in starting. * * @remarks Also called from VBoxService-win.cpp, thus not static. */ int VGSvcStopServices(void) { VGSvcReportStatus(VBoxGuestFacilityStatus_Terminating); /* * Signal all the services. */ for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) ASMAtomicWriteBool(&g_aServices[j].fShutdown, true); /* * Do the pfnStop callback on all running services. */ for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) if (g_aServices[j].fStarted) { VGSvcVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName); g_aServices[j].pDesc->pfnStop(); } VGSvcVerbose(3, "All stop functions for services called\n"); /* * Wait for all the service threads to complete. */ int rc = VINF_SUCCESS; for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { if (!g_aServices[j].fEnabled) /* Only stop services which were started before. */ continue; if (g_aServices[j].Thread != NIL_RTTHREAD) { VGSvcVerbose(2, "Waiting for service '%s' to stop ...\n", g_aServices[j].pDesc->pszName); int rc2 = VINF_SUCCESS; for (int i = 0; i < 30; i++) /* Wait 30 seconds in total */ { rc2 = RTThreadWait(g_aServices[j].Thread, 1000 /* Wait 1 second */, NULL); if (RT_SUCCESS(rc2)) break; #ifdef RT_OS_WINDOWS /* Notify SCM that it takes a bit longer ... */ VGSvcWinSetStopPendingStatus(i + j*32); #endif } if (RT_FAILURE(rc2)) { VGSvcError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc2); rc = rc2; } } VGSvcVerbose(3, "Terminating service '%s' (%d) ...\n", g_aServices[j].pDesc->pszName, j); g_aServices[j].pDesc->pfnTerm(); } #ifdef RT_OS_WINDOWS /* * Wake up and tell the main() thread that we're shutting down (it's * sleeping in VBoxServiceMainWait). */ ASMAtomicWriteBool(&g_fWindowsServiceShutdown, true); if (g_hEvtWindowsService != NIL_RTSEMEVENT) { VGSvcVerbose(3, "Stopping the main thread...\n"); int rc2 = RTSemEventSignal(g_hEvtWindowsService); AssertRC(rc2); } #endif VGSvcVerbose(2, "Stopping services returning: %Rrc\n", rc); VGSvcReportStatus(RT_SUCCESS(rc) ? VBoxGuestFacilityStatus_Paused : VBoxGuestFacilityStatus_Failed); return rc; }
/** * Starts the service. * * @returns VBox status code, errors are fully bitched. * * @remarks Also called from VBoxService-win.cpp, thus not static. */ int VGSvcStartServices(void) { int rc; VGSvcReportStatus(VBoxGuestFacilityStatus_Init); /* * Initialize the services. */ VGSvcVerbose(2, "Initializing services ...\n"); for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) if (g_aServices[j].fEnabled) { rc = g_aServices[j].pDesc->pfnInit(); if (RT_FAILURE(rc)) { if (rc != VERR_SERVICE_DISABLED) { VGSvcError("Service '%s' failed to initialize: %Rrc\n", g_aServices[j].pDesc->pszName, rc); VGSvcReportStatus(VBoxGuestFacilityStatus_Failed); return rc; } g_aServices[j].fEnabled = false; VGSvcVerbose(0, "Service '%s' was disabled because of missing functionality\n", g_aServices[j].pDesc->pszName); } } /* * Start the service(s). */ VGSvcVerbose(2, "Starting services ...\n"); rc = VINF_SUCCESS; for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { if (!g_aServices[j].fEnabled) continue; VGSvcVerbose(2, "Starting service '%s' ...\n", g_aServices[j].pDesc->pszName); rc = RTThreadCreate(&g_aServices[j].Thread, vgsvcThread, (void *)(uintptr_t)j, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_aServices[j].pDesc->pszName); if (RT_FAILURE(rc)) { VGSvcError("RTThreadCreate failed, rc=%Rrc\n", rc); break; } g_aServices[j].fStarted = true; /* Wait for the thread to initialize. */ /** @todo There is a race between waiting and checking * the fShutdown flag of a thread here and processing * the thread's actual worker loop. If the thread decides * to exit the loop before we skipped the fShutdown check * below the service will fail to start! */ /** @todo This presumably means either a one-shot service or that * something has gone wrong. In the second case treating it as failure * to start is probably right, so we need a way to signal the first * rather than leaving the idle thread hanging around. A flag in the * service description? */ RTThreadUserWait(g_aServices[j].Thread, 60 * 1000); if (g_aServices[j].fShutdown) { VGSvcError("Service '%s' failed to start!\n", g_aServices[j].pDesc->pszName); rc = VERR_GENERAL_FAILURE; } } if (RT_SUCCESS(rc)) VGSvcVerbose(1, "All services started.\n"); else { VGSvcError("An error occcurred while the services!\n"); VGSvcReportStatus(VBoxGuestFacilityStatus_Failed); } return rc; }
/** * @interface_method_impl{VBOXSERVICE,pfnInit} */ static DECLCALLBACK(int) vgsvcTimeSyncInit(void) { /* * If not specified, find the right interval default. * Then create the event sem to block on. */ if (!g_TimeSyncInterval) g_TimeSyncInterval = g_DefaultInterval * 1000; if (!g_TimeSyncInterval) g_TimeSyncInterval = 10 * 1000; VbglR3GetSessionId(&g_idTimeSyncSession); /* The status code is ignored as this information is not available with VBox < 3.2.10. */ int rc = RTSemEventMultiCreate(&g_TimeSyncEvent); AssertRC(rc); #ifdef RT_OS_WINDOWS if (RT_SUCCESS(rc)) { /* * Adjust privileges of this process so we can make system time adjustments. */ if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &g_hTokenProcess)) { TOKEN_PRIVILEGES tkPriv; RT_ZERO(tkPriv); tkPriv.PrivilegeCount = 1; tkPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkPriv.Privileges[0].Luid)) { DWORD cbRet = sizeof(g_TkOldPrivileges); if (AdjustTokenPrivileges(g_hTokenProcess, FALSE, &tkPriv, sizeof(TOKEN_PRIVILEGES), &g_TkOldPrivileges, &cbRet)) rc = VINF_SUCCESS; else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VGSvcError("vgsvcTimeSyncInit: Adjusting token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); } } else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VGSvcError("vgsvcTimeSyncInit: Looking up token privileges (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); } if (RT_FAILURE(rc)) { CloseHandle(g_hTokenProcess); g_hTokenProcess = NULL; } } else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VGSvcError("vgsvcTimeSyncInit: Opening process token (SE_SYSTEMTIME_NAME) failed with status code %u/%Rrc!\n", dwErr, rc); g_hTokenProcess = NULL; } } if (GetSystemTimeAdjustment(&g_dwWinTimeAdjustment, &g_dwWinTimeIncrement, &g_bWinTimeAdjustmentDisabled)) VGSvcVerbose(3, "vgsvcTimeSyncInit: Initially %ld (100ns) units per %ld (100 ns) units interval, disabled=%d\n", g_dwWinTimeAdjustment, g_dwWinTimeIncrement, g_bWinTimeAdjustmentDisabled ? 1 : 0); else { DWORD dwErr = GetLastError(); rc = RTErrConvertFromWin32(dwErr); VGSvcError("vgsvcTimeSyncInit: Could not get time adjustment values! Last error: %ld!\n", dwErr); } #endif /* RT_OS_WINDOWS */ return rc; }
/** * Try adjust the time using adjtime or similar. * * @returns true on success, false on failure. * * @param pDrift The time adjustment. */ static bool vgsvcTimeSyncAdjust(PCRTTIMESPEC pDrift) { #ifdef RT_OS_WINDOWS /** @todo r=bird: g_hTokenProcess cannot be NULL here. * vgsvcTimeSyncInit will fail and the service will not be started with * it being NULL. vgsvcTimeSyncInit OTOH will *NOT* be called until the * service thread has terminated. If anything * else is the case, there is buggy code somewhere.*/ if (g_hTokenProcess == NULL) /* Is the token already closed when shutting down? */ return false; DWORD dwWinTimeAdjustment, dwWinNewTimeAdjustment, dwWinTimeIncrement; BOOL fWinTimeAdjustmentDisabled; if (GetSystemTimeAdjustment(&dwWinTimeAdjustment, &dwWinTimeIncrement, &fWinTimeAdjustmentDisabled)) { DWORD dwDiffMax = g_dwWinTimeAdjustment * 0.50; DWORD dwDiffNew = dwWinTimeAdjustment * 0.10; if (RTTimeSpecGetMilli(pDrift) > 0) { dwWinNewTimeAdjustment = dwWinTimeAdjustment + dwDiffNew; if (dwWinNewTimeAdjustment > (g_dwWinTimeAdjustment + dwDiffMax)) { dwWinNewTimeAdjustment = g_dwWinTimeAdjustment + dwDiffMax; dwDiffNew = dwDiffMax; } } else { dwWinNewTimeAdjustment = dwWinTimeAdjustment - dwDiffNew; if (dwWinNewTimeAdjustment < (g_dwWinTimeAdjustment - dwDiffMax)) { dwWinNewTimeAdjustment = g_dwWinTimeAdjustment - dwDiffMax; dwDiffNew = dwDiffMax; } } VGSvcVerbose(3, "vgsvcTimeSyncAdjust: Drift=%lldms\n", RTTimeSpecGetMilli(pDrift)); VGSvcVerbose(3, "vgsvcTimeSyncAdjust: OrgTA=%ld, CurTA=%ld, NewTA=%ld, DiffNew=%ld, DiffMax=%ld\n", g_dwWinTimeAdjustment, dwWinTimeAdjustment, dwWinNewTimeAdjustment, dwDiffNew, dwDiffMax); if (SetSystemTimeAdjustment(dwWinNewTimeAdjustment, FALSE /* Periodic adjustments enabled. */)) { g_cTimeSyncErrors = 0; return true; } if (g_cTimeSyncErrors++ < 10) VGSvcError("vgsvcTimeSyncAdjust: SetSystemTimeAdjustment failed, error=%u\n", GetLastError()); } else if (g_cTimeSyncErrors++ < 10) VGSvcError("vgsvcTimeSyncAdjust: GetSystemTimeAdjustment failed, error=%ld\n", GetLastError()); #elif defined(RT_OS_OS2) || defined(RT_OS_HAIKU) /* No API for doing gradual time adjustments. */ #else /* PORTME */ /* * Try use adjtime(), most unix-like systems have this. */ struct timeval tv; RTTimeSpecGetTimeval(pDrift, &tv); if (adjtime(&tv, NULL) == 0) { if (g_cVerbosity >= 1) VGSvcVerbose(1, "vgsvcTimeSyncAdjust: adjtime by %RDtimespec\n", pDrift); g_cTimeSyncErrors = 0; return true; } #endif /* failed */ return false; }
/** * @interface_method_impl{VBOXSERVICE,pfnPreInit} */ static DECLCALLBACK(int) vgsvcTimeSyncPreInit(void) { #ifdef VBOX_WITH_GUEST_PROPS /** @todo Merge this function with vgsvcTimeSyncOption() to generalize * the "command line args override guest property values" behavior. */ /* * Read the service options from the VM's guest properties. * Note that these options can be overridden by the command line options later. */ uint32_t uGuestPropSvcClientID; int rc = VbglR3GuestPropConnect(&uGuestPropSvcClientID); if (RT_FAILURE(rc)) { if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */ { VGSvcVerbose(0, "VMInfo: Guest property service is not available, skipping\n"); rc = VINF_SUCCESS; } else VGSvcError("Failed to connect to the guest property service! Error: %Rrc\n", rc); } else { rc = VGSvcReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-interval", &g_TimeSyncInterval, 50, UINT32_MAX - 1); if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) rc = VGSvcReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-min-adjust", &g_TimeSyncMinAdjust, 0, 3600000); if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) rc = VGSvcReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-latency-factor", &g_TimeSyncLatencyFactor, 1, 1024); if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) rc = VGSvcReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-max-latency", &g_TimeSyncMaxLatency, 1, 3600000); if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) rc = VGSvcReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-threshold", &g_TimeSyncSetThreshold, 0, 7*24*60*60*1000 /* a week */); if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) { char *pszValue; rc = VGSvcReadProp(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-start", &pszValue, NULL /* ppszFlags */, NULL /* puTimestamp */); if (RT_SUCCESS(rc)) { g_fTimeSyncSetNext = true; RTStrFree(pszValue); } } if ( RT_SUCCESS(rc) || rc == VERR_NOT_FOUND) { uint32_t value; rc = VGSvcReadPropUInt32(uGuestPropSvcClientID, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-on-restore", &value, 1, 1); if (RT_SUCCESS(rc)) g_fTimeSyncSetOnRestore = !!value; } VbglR3GuestPropDisconnect(uGuestPropSvcClientID); } if (rc == VERR_NOT_FOUND) /* If a value is not found, don't be sad! */ rc = VINF_SUCCESS; return rc; #else /* Nothing to do here yet. */ return VINF_SUCCESS; #endif }
/** * @interface_method_impl{VBOXSERVICE,pfnWorker} */ DECLCALLBACK(int) vgsvcVMStatsWorker(bool volatile *pfShutdown) { int rc = VINF_SUCCESS; /* Start monitoring of the stat event change event. */ rc = VbglR3CtlFilterMask(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0); if (RT_FAILURE(rc)) { VGSvcVerbose(3, "vgsvcVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc); return rc; } /* * Tell the control thread that it can continue * spawning services. */ RTThreadUserSignal(RTThreadSelf()); /* * Now enter the loop retrieving runtime data continuously. */ for (;;) { uint32_t fEvents = 0; RTMSINTERVAL cWaitMillies; /* Check if an update interval change is pending. */ rc = VbglR3WaitEvent(VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST, 0 /* no wait */, &fEvents); if ( RT_SUCCESS(rc) && (fEvents & VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)) VbglR3StatQueryInterval(&g_VMStat.cMsStatInterval); if (g_VMStat.cMsStatInterval) { vgsvcVMStatsReport(); cWaitMillies = g_VMStat.cMsStatInterval; } else cWaitMillies = 3000; /* * Block for a while. * * The event semaphore takes care of ignoring interruptions and it * allows us to implement service wakeup later. */ if (*pfShutdown) break; int rc2 = RTSemEventMultiWait(g_VMStatEvent, cWaitMillies); if (*pfShutdown) break; if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2)) { VGSvcError("vgsvcVMStatsWorker: RTSemEventMultiWait failed; rc2=%Rrc\n", rc2); rc = rc2; break; } } /* Cancel monitoring of the stat event change event. */ rc = VbglR3CtlFilterMask(0, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST); if (RT_FAILURE(rc)) VGSvcVerbose(3, "vgsvcVMStatsWorker: VbglR3CtlFilterMask failed with %d\n", rc); VGSvcVerbose(3, "VBoxStatsThread: finished statistics change request thread\n"); return 0; }
int main(int argc, char **argv) { RTEXITCODE rcExit; /* * Init globals and such. */ int rc = RTR3InitExe(argc, &argv, 0); if (RT_FAILURE(rc)) return RTMsgInitFailure(rc); g_pszProgName = RTPathFilename(argv[0]); #ifdef RT_OS_WINDOWS VGSvcWinResolveApis(); #endif #ifdef DEBUG rc = RTCritSectInit(&g_csLog); AssertRC(rc); #endif #ifdef VBOX_WITH_VBOXSERVICE_TOOLBOX /* * Run toolbox code before all other stuff since these things are simpler * shell/file/text utility like programs that just happens to be inside * VBoxService and shouldn't be subject to /dev/vboxguest, pid-files and * global mutex restrictions. */ if (VGSvcToolboxMain(argc, argv, &rcExit)) return rcExit; #endif bool fUserSession = false; #ifdef VBOX_WITH_VBOXSERVICE_CONTROL /* * Check if we're the specially spawned VBoxService.exe process that * handles a guest control session. */ if ( argc >= 2 && !RTStrICmp(argv[1], "guestsession")) fUserSession = true; #endif /* * Connect to the kernel part before daemonizing so we can fail and * complain if there is some kind of problem. We need to initialize the * guest lib *before* we do the pre-init just in case one of services needs * do to some initial stuff with it. */ if (fUserSession) rc = VbglR3InitUser(); else rc = VbglR3Init(); if (RT_FAILURE(rc)) { if (rc == VERR_ACCESS_DENIED) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n", g_pszProgName); return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc); } #ifdef RT_OS_WINDOWS /* * Check if we're the specially spawned VBoxService.exe process that * handles page fusion. This saves an extra statically linked executable. */ if ( argc == 2 && !RTStrICmp(argv[1], "pagefusion")) return VGSvcPageSharingWorkerChild(); #endif #ifdef VBOX_WITH_VBOXSERVICE_CONTROL /* * Check if we're the specially spawned VBoxService.exe process that * handles a guest control session. */ if (fUserSession) return VGSvcGstCtrlSessionSpawnInit(argc, argv); #endif /* * Parse the arguments. * * Note! This code predates RTGetOpt, thus the manual parsing. */ bool fDaemonize = true; bool fDaemonized = false; for (int i = 1; i < argc; i++) { const char *psz = argv[i]; if (*psz != '-') return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz); psz++; /* translate long argument to short */ if (*psz == '-') { psz++; size_t cch = strlen(psz); #define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \ && !memcmp(psz, strconst, sizeof(strconst) - 1) ) if (MATCHES("foreground")) psz = "f"; else if (MATCHES("verbose")) psz = "v"; else if (MATCHES("version")) psz = "V"; else if (MATCHES("help")) psz = "h"; else if (MATCHES("interval")) psz = "i"; #ifdef RT_OS_WINDOWS else if (MATCHES("register")) psz = "r"; else if (MATCHES("unregister")) psz = "u"; #endif else if (MATCHES("logfile")) psz = "l"; else if (MATCHES("pidfile")) psz = "p"; else if (MATCHES("daemonized")) { fDaemonized = true; continue; } else { bool fFound = false; if (cch > sizeof("enable-") && !memcmp(psz, RT_STR_TUPLE("enable-"))) for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName))) g_aServices[j].fEnabled = true; if (cch > sizeof("disable-") && !memcmp(psz, RT_STR_TUPLE("disable-"))) for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName))) g_aServices[j].fEnabled = false; if (cch > sizeof("only-") && !memcmp(psz, RT_STR_TUPLE("only-"))) for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName); if (g_aServices[j].fEnabled) fFound = true; } if (!fFound) { rcExit = vgsvcLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) { rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i); fFound = rc == VINF_SUCCESS; if (fFound) break; if (rc != -1) return rc; } } if (!fFound) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]); continue; } #undef MATCHES } /* handle the string of short options. */ do { switch (*psz) { case 'i': rc = VGSvcArgUInt32(argc, argv, psz + 1, &i, &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1); if (rc) return rc; psz = NULL; break; case 'f': fDaemonize = false; break; case 'v': g_cVerbosity++; break; case 'V': RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr()); return RTEXITCODE_SUCCESS; case 'h': case '?': return vgsvcUsage(); #ifdef RT_OS_WINDOWS case 'r': return VGSvcWinInstall(); case 'u': return VGSvcWinUninstall(); #endif case 'l': { rc = vgsvcArgString(argc, argv, psz + 1, &i, g_szLogFile, sizeof(g_szLogFile)); if (rc) return rc; psz = NULL; break; } case 'p': { rc = vgsvcArgString(argc, argv, psz + 1, &i, g_szPidFile, sizeof(g_szPidFile)); if (rc) return rc; psz = NULL; break; } default: { rcExit = vgsvcLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; bool fFound = false; for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) { rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i); fFound = rc == VINF_SUCCESS; if (fFound) break; if (rc != -1) return rc; } if (!fFound) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%c' (%s)\n", *psz, argv[i]); break; } } } while (psz && *++psz); } /* Check that at least one service is enabled. */ if (vgsvcCountEnabledServices() == 0) return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n"); rc = VGSvcLogCreate(g_szLogFile[0] ? g_szLogFile : NULL); if (RT_FAILURE(rc)) return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log '%s', rc=%Rrc\n", g_szLogFile[0] ? g_szLogFile : "<None>", rc); /* Call pre-init if we didn't do it already. */ rcExit = vgsvcLazyPreInit(); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; #ifdef RT_OS_WINDOWS /* * Make sure only one instance of VBoxService runs at a time. Create a * global mutex for that. * * Note! The \\Global\ namespace was introduced with Win2K, thus the * version check. * Note! If the mutex exists CreateMutex will open it and set last error to * ERROR_ALREADY_EXISTS. */ OSVERSIONINFOEX OSInfoEx; RT_ZERO(OSInfoEx); OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); SetLastError(NO_ERROR); HANDLE hMutexAppRunning; if ( GetVersionEx((LPOSVERSIONINFO)&OSInfoEx) && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT && OSInfoEx.dwMajorVersion >= 5 /* NT 5.0 a.k.a W2K */) hMutexAppRunning = CreateMutex(NULL, FALSE, "Global\\" VBOXSERVICE_NAME); else hMutexAppRunning = CreateMutex(NULL, FALSE, VBOXSERVICE_NAME); if (hMutexAppRunning == NULL) { DWORD dwErr = GetLastError(); if ( dwErr == ERROR_ALREADY_EXISTS || dwErr == ERROR_ACCESS_DENIED) { VGSvcError("%s is already running! Terminating.\n", g_pszProgName); return RTEXITCODE_FAILURE; } VGSvcError("CreateMutex failed with last error %u! Terminating.\n", GetLastError()); return RTEXITCODE_FAILURE; } #else /* !RT_OS_WINDOWS */ /** @todo Add PID file creation here? */ #endif /* !RT_OS_WINDOWS */ VGSvcVerbose(0, "%s r%s started. Verbose level = %d\n", RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity); /* * Daemonize if requested. */ if (fDaemonize && !fDaemonized) { #ifdef RT_OS_WINDOWS VGSvcVerbose(2, "Starting service dispatcher ...\n"); rcExit = VGSvcWinEnterCtrlDispatcher(); #else VGSvcVerbose(1, "Daemonizing...\n"); rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */, false /* fRespawn */, NULL /* pcRespawn */); if (RT_FAILURE(rc)) return VGSvcError("Daemon failed: %Rrc\n", rc); /* in-child */ #endif } #ifdef RT_OS_WINDOWS else #endif { /* * Windows: We're running the service as a console application now. Start the * services, enter the main thread's run loop and stop them again * when it returns. * * POSIX: This is used for both daemons and console runs. Start all services * and return immediately. */ #ifdef RT_OS_WINDOWS # ifndef RT_OS_NT4 /** @todo r=bird: What's RT_OS_NT4??? */ /* Install console control handler. */ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)vgsvcWinConsoleControlHandler, TRUE /* Add handler */)) { VGSvcError("Unable to add console control handler, error=%ld\n", GetLastError()); /* Just skip this error, not critical. */ } # endif /* !RT_OS_NT4 */ #endif /* RT_OS_WINDOWS */ rc = VGSvcStartServices(); RTFILE hPidFile = NIL_RTFILE; if (RT_SUCCESS(rc)) if (g_szPidFile[0]) rc = VbglR3PidFile(g_szPidFile, &hPidFile); rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; if (RT_SUCCESS(rc)) VGSvcMainWait(); if (g_szPidFile[0] && hPidFile != NIL_RTFILE) VbglR3ClosePidFile(g_szPidFile, hPidFile); #ifdef RT_OS_WINDOWS # ifndef RT_OS_NT4 /* Uninstall console control handler. */ if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)NULL, FALSE /* Remove handler */)) { VGSvcError("Unable to remove console control handler, error=%ld\n", GetLastError()); /* Just skip this error, not critical. */ } # endif /* !RT_OS_NT4 */ #else /* !RT_OS_WINDOWS */ /* On Windows - since we're running as a console application - we already stopped all services * through the console control handler. So only do the stopping of services here on other platforms * where the break/shutdown/whatever signal was just received. */ VGSvcStopServices(); #endif /* RT_OS_WINDOWS */ } VGSvcReportStatus(VBoxGuestFacilityStatus_Terminated); #ifdef RT_OS_WINDOWS /* * Cleanup mutex. */ CloseHandle(hMutexAppRunning); #endif VGSvcVerbose(0, "Ended.\n"); #ifdef DEBUG RTCritSectDelete(&g_csLog); //RTMemTrackerDumpAllToStdOut(); #endif VGSvcLogDestroy(); return rcExit; }
/** * @todo Add full unicode support. * @todo Add event log capabilities / check return values. */ static int vgsvcWinAddAceToObjectsSecurityDescriptor(LPTSTR pszObjName, SE_OBJECT_TYPE enmObjectType, const char *pszTrustee, TRUSTEE_FORM enmTrusteeForm, DWORD dwAccessRights, ACCESS_MODE fAccessMode, DWORD dwInheritance) { int rc; if ( g_pfnGetNamedSecurityInfoA && g_pfnSetEntriesInAclA && g_pfnSetNamedSecurityInfoA) { /* Get a pointer to the existing DACL. */ PSECURITY_DESCRIPTOR pSD = NULL; PACL pOldDACL = NULL; DWORD rcWin = g_pfnGetNamedSecurityInfoA(pszObjName, enmObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDACL, NULL, &pSD); if (rcWin == ERROR_SUCCESS) { /* Initialize an EXPLICIT_ACCESS structure for the new ACE. */ EXPLICIT_ACCESSA ExplicitAccess; RT_ZERO(ExplicitAccess); ExplicitAccess.grfAccessPermissions = dwAccessRights; ExplicitAccess.grfAccessMode = fAccessMode; ExplicitAccess.grfInheritance = dwInheritance; ExplicitAccess.Trustee.TrusteeForm = enmTrusteeForm; ExplicitAccess.Trustee.ptstrName = (char *)pszTrustee; /* Create a new ACL that merges the new ACE into the existing DACL. */ PACL pNewDACL = NULL; rcWin = g_pfnSetEntriesInAclA(1, &ExplicitAccess, pOldDACL, &pNewDACL); if (rcWin == ERROR_SUCCESS) { /* Attach the new ACL as the object's DACL. */ rcWin = g_pfnSetNamedSecurityInfoA(pszObjName, enmObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDACL, NULL); if (rcWin == ERROR_SUCCESS) rc = VINF_SUCCESS; else { VGSvcError("AddAceToObjectsSecurityDescriptor: SetNamedSecurityInfo: Error %u\n", rcWin); rc = RTErrConvertFromWin32(rcWin); } if (pNewDACL) LocalFree(pNewDACL); } else { VGSvcError("AddAceToObjectsSecurityDescriptor: SetEntriesInAcl: Error %u\n", rcWin); rc = RTErrConvertFromWin32(rcWin); } if (pSD) LocalFree(pSD); } else { if (rcWin == ERROR_FILE_NOT_FOUND) VGSvcError("AddAceToObjectsSecurityDescriptor: Object not found/installed: %s\n", pszObjName); else VGSvcError("AddAceToObjectsSecurityDescriptor: GetNamedSecurityInfo: Error %u\n", rcWin); rc = RTErrConvertFromWin32(rcWin); } } else rc = VINF_SUCCESS; /* fake it */ return rc; }
/** * Installs the service. */ RTEXITCODE VGSvcWinInstall(void) { VGSvcVerbose(1, "Installing service ...\n"); TCHAR imagePath[MAX_PATH] = { 0 }; GetModuleFileName(NULL, imagePath, sizeof(imagePath)); SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCManager == NULL) { VGSvcError("Could not open SCM! Error: %ld\n", GetLastError()); return RTEXITCODE_FAILURE; } RTEXITCODE rc = RTEXITCODE_SUCCESS; SC_HANDLE hService = CreateService(hSCManager, VBOXSERVICE_NAME, VBOXSERVICE_FRIENDLY_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, imagePath, NULL, NULL, NULL, NULL, NULL); if (hService != NULL) VGSvcVerbose(0, "Service successfully installed!\n"); else { DWORD dwErr = GetLastError(); switch (dwErr) { case ERROR_SERVICE_EXISTS: VGSvcVerbose(1, "Service already exists, just updating the service config.\n"); hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS); if (hService) { if (ChangeServiceConfig (hService, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, imagePath, NULL, NULL, NULL, NULL, NULL, VBOXSERVICE_FRIENDLY_NAME)) VGSvcVerbose(1, "The service config has been successfully updated.\n"); else rc = VGSvcError("Could not change service config! Error: %ld\n", GetLastError()); } else rc = VGSvcError("Could not open service! Error: %ld\n", GetLastError()); break; default: rc = VGSvcError("Could not create service! Error: %ld\n", dwErr); break; } } if (rc == RTEXITCODE_SUCCESS) rc = vgsvcWinSetDesc(hService); CloseServiceHandle(hService); CloseServiceHandle(hSCManager); return rc; }