diff --git a/reactos/base/system/services/CMakeLists.txt b/reactos/base/system/services/CMakeLists.txt index ddb4994da7d..0005294b04b 100644 --- a/reactos/base/system/services/CMakeLists.txt +++ b/reactos/base/system/services/CMakeLists.txt @@ -26,6 +26,6 @@ if(NOT MSVC) endif() set_module_type(services win32gui UNICODE) -add_importlibs(services user32 advapi32 rpcrt4 msvcrt kernel32 ntdll) +add_importlibs(services userenv user32 advapi32 rpcrt4 msvcrt kernel32 ntdll) add_pch(services services.h SOURCE) add_cd_file(TARGET services DESTINATION reactos/system32 FOR all) diff --git a/reactos/base/system/services/database.c b/reactos/base/system/services/database.c index 167d6917349..fbe1f21b4e7 100644 --- a/reactos/base/system/services/database.c +++ b/reactos/base/system/services/database.c @@ -14,7 +14,7 @@ #include "services.h" -#include +#include #define NDEBUG #include @@ -1681,6 +1681,7 @@ ScmStartUserModeService(PSERVICE Service, { PROCESS_INFORMATION ProcessInformation; STARTUPINFOW StartupInfo; + LPVOID lpEnvironment; BOOL Result; DWORD dwError = ERROR_SUCCESS; @@ -1698,17 +1699,73 @@ ScmStartUserModeService(PSERVICE Service, StartupInfo.cb = sizeof(StartupInfo); ZeroMemory(&ProcessInformation, sizeof(ProcessInformation)); - Result = CreateProcessAsUserW(Service->lpImage->hToken, - NULL, - Service->lpImage->pszImagePath, - NULL, - NULL, - FALSE, - DETACHED_PROCESS | CREATE_SUSPENDED, - NULL, - NULL, - &StartupInfo, - &ProcessInformation); + /* Use the interactive desktop if the service is interactive */ + if (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS) + StartupInfo.lpDesktop = L"winsta0\\default"; + + if (Service->lpImage->hToken) + { + /* User token: Run the service under the user account */ + + if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE)) + { + /* We failed, run the service with the current environment */ + DPRINT1("CreateEnvironmentBlock() failed with error %d, service '%S' will run with the current environment.\n", + Service->lpServiceName, GetLastError()); + lpEnvironment = NULL; + } + + /* Impersonate the new user */ + if (!ImpersonateLoggedOnUser(Service->lpImage->hToken)) + { + dwError = GetLastError(); + DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", GetLastError()); + return dwError; + } + + /* Launch the process in the user's logon session */ + Result = CreateProcessAsUserW(Service->lpImage->hToken, + NULL, + Service->lpImage->pszImagePath, + NULL, + NULL, + FALSE, + CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, + lpEnvironment, + NULL, + &StartupInfo, + &ProcessInformation); + + /* Revert the impersonation */ + RevertToSelf(); + } + else + { + /* No user token: Run the service under the LocalSystem account */ + + if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE)) + { + /* We failed, run the service with the current environment */ + DPRINT1("CreateEnvironmentBlock() failed with error %d, service '%S' will run with the current environment.\n", + Service->lpServiceName, GetLastError()); + lpEnvironment = NULL; + } + + Result = CreateProcessW(NULL, + Service->lpImage->pszImagePath, + NULL, + NULL, + FALSE, + CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, + lpEnvironment, + NULL, + &StartupInfo, + &ProcessInformation); + } + + if (lpEnvironment) + DestroyEnvironmentBlock(lpEnvironment); + if (!Result) { dwError = GetLastError();