#include "services.h"
+#include <wincon.h>
+
#define NDEBUG
#include <debug.h>
/* GLOBALS ******************************************************************/
-#define PIPE_BUFSIZE 1024
-#define PIPE_TIMEOUT 1000
+/* Defined in include/reactos/services/services.h */
+// #define SCM_START_EVENT L"SvcctrlStartEvent_A3752DX"
+#define SCM_AUTOSTARTCOMPLETE_EVENT L"SC_AutoStartComplete"
+#define LSA_RPC_SERVER_ACTIVE L"LSA_RPC_SERVER_ACTIVE"
+BOOL ScmInitialize = FALSE;
BOOL ScmShutdown = FALSE;
static HANDLE hScmShutdownEvent = NULL;
VOID
-ScmLogError(DWORD dwEventId,
+ScmLogEvent(DWORD dwEventId,
+ WORD wType,
WORD wStrings,
LPCWSTR *lpStrings)
{
}
if (!ReportEventW(hLog,
- EVENTLOG_ERROR_TYPE,
+ wType,
0,
dwEventId,
- NULL, // Sid,
+ NULL,
wStrings,
0,
lpStrings,
}
-BOOL
-ScmCreateStartEvent(PHANDLE StartEvent)
+VOID
+ScmWaitForLsa(VOID)
{
- HANDLE hEvent;
-
- hEvent = CreateEventW(NULL,
- TRUE,
- FALSE,
- L"SvcctrlStartEvent_A3752DX");
+ HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, LSA_RPC_SERVER_ACTIVE);
if (hEvent == NULL)
{
- if (GetLastError() == ERROR_ALREADY_EXISTS)
- {
- hEvent = OpenEventW(EVENT_ALL_ACCESS,
- FALSE,
- L"SvcctrlStartEvent_A3752DX");
- if (hEvent == NULL)
- {
- return FALSE;
- }
- }
- else
- {
- return FALSE;
- }
+ DPRINT1("Failed to create the notification event (Error %lu)\n", GetLastError());
+ }
+ else
+ {
+ DPRINT("Wait for the LSA server!\n");
+ WaitForSingleObject(hEvent, INFINITE);
+ DPRINT("LSA server running!\n");
+ CloseHandle(hEvent);
}
- *StartEvent = hEvent;
-
- return TRUE;
+ DPRINT("ScmWaitForLsa() done\n");
}
-VOID
-ScmWaitForLsa(VOID)
+BOOL WINAPI
+ShutdownHandlerRoutine(DWORD dwCtrlType)
{
- HANDLE hEvent;
- DWORD dwError;
+ DPRINT1("ShutdownHandlerRoutine() called\n");
- hEvent = CreateEventW(NULL,
- TRUE,
- FALSE,
- L"LSA_RPC_SERVER_ACTIVE");
- if (hEvent == NULL)
+ if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT))
{
- dwError = GetLastError();
- DPRINT1("Failed to create the notication event (Error %lu)\n", dwError);
-
- if (dwError == ERROR_ALREADY_EXISTS)
- {
- hEvent = OpenEventW(SYNCHRONIZE,
- FALSE,
- L"LSA_RPC_SERVER_ACTIVE");
- if (hEvent == NULL)
- {
- DPRINT1("Could not open the notification event (Error %lu)\n", GetLastError());
- return;
- }
- }
- }
+ DPRINT1("Shutdown event received!\n");
+ ScmShutdown = TRUE;
- DPRINT("Wait for the LSA server!\n");
- WaitForSingleObject(hEvent, INFINITE);
- DPRINT("LSA server running!\n");
+ ScmAutoShutdownServices();
+ ScmShutdownServiceDatabase();
- CloseHandle(hEvent);
+ /* Set the shutdown event */
+ SetEvent(hScmShutdownEvent);
+ }
- DPRINT("ScmWaitForLsa() done\n");
+ return TRUE;
}
-BOOL
-ScmNamedPipeHandleRequest(PVOID Request,
- DWORD RequestSize,
- PVOID Reply,
- LPDWORD ReplySize)
-{
- DbgPrint("SCM READ: %p\n", Request);
+/*** HACK CORE-12541: Special service accounts initialization HACK ************/
- *ReplySize = 0;
- return FALSE;
-}
+#include <ndk/setypes.h>
+#include <sddl.h>
+#include <userenv.h>
+#include <strsafe.h>
-
-DWORD WINAPI
-ScmNamedPipeThread(LPVOID Context)
+/* Inspired from userenv.dll's CreateUserProfileExW and LoadUserProfileW APIs */
+static
+BOOL
+ScmLogAccountHack(IN LPCWSTR pszAccountName,
+ IN LPCWSTR pszSid,
+ OUT PHKEY phProfile)
{
- CHAR chRequest[PIPE_BUFSIZE];
- CHAR chReply[PIPE_BUFSIZE];
- DWORD cbReplyBytes;
- DWORD cbBytesRead;
- DWORD cbWritten;
- BOOL bSuccess;
- HANDLE hPipe;
+ BOOL Success = FALSE;
+ LONG Error;
+ NTSTATUS Status;
+ BOOLEAN WasPriv1Set = FALSE, WasPriv2Set = FALSE;
+ PSID pSid;
+ DWORD dwLength;
+ WCHAR szUserHivePath[MAX_PATH];
+
+ DPRINT1("ScmLogAccountsHack(%S, %S)\n", pszAccountName, pszSid);
+ if (!pszAccountName || !pszSid || !phProfile)
+ return ERROR_INVALID_PARAMETER;
+
+ /* Convert the SID string into a SID. NOTE: No RTL equivalent. */
+ if (!ConvertStringSidToSidW(pszSid, &pSid))
+ {
+ DPRINT1("ConvertStringSidToSidW() failed (error %lu)\n", GetLastError());
+ return FALSE;
+ }
- hPipe = (HANDLE)Context;
+ /* Determine a suitable profile path */
+ dwLength = ARRAYSIZE(szUserHivePath);
+ if (!GetProfilesDirectoryW(szUserHivePath, &dwLength))
+ {
+ DPRINT1("GetProfilesDirectoryW() failed (error %lu)\n", GetLastError());
+ goto Quit;
+ }
- DPRINT("ScmNamedPipeThread(%p) - Accepting SCM commands through named pipe\n", hPipe);
+ /* Create user hive name */
+ StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\");
+ StringCbCatW(szUserHivePath, sizeof(szUserHivePath), pszAccountName);
+ StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\ntuser.dat");
+ DPRINT("szUserHivePath: %S\n", szUserHivePath);
- for (;;)
+ /* Magic #1: Create the special user profile if needed */
+ if (GetFileAttributesW(szUserHivePath) == INVALID_FILE_ATTRIBUTES)
{
- bSuccess = ReadFile(hPipe,
- &chRequest,
- PIPE_BUFSIZE,
- &cbBytesRead,
- NULL);
- if (!bSuccess || cbBytesRead == 0)
+ if (!CreateUserProfileW(pSid, pszAccountName))
{
- break;
+ DPRINT1("CreateUserProfileW() failed (error %lu)\n", GetLastError());
+ goto Quit;
}
+ }
- if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes))
- {
- bSuccess = WriteFile(hPipe,
- &chReply,
- cbReplyBytes,
- &cbWritten,
- NULL);
- if (!bSuccess || cbReplyBytes != cbWritten)
- {
- break;
- }
- }
+ /*
+ * Now Da Magiks #2: Manually mount the user profile registry hive
+ * aka. manually do what LoadUserProfile does!! But we don't require
+ * a security token!
+ */
+
+ /* Acquire restore privilege */
+ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasPriv1Set);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Error 0x%08lx)\n", Status);
+ goto Quit;
}
- DPRINT("ScmNamedPipeThread(%p) - Disconnecting named pipe connection\n", hPipe);
+ /* Acquire backup privilege */
+ Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &WasPriv2Set);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Error 0x%08lx)\n", Status);
+ RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasPriv1Set, FALSE, &WasPriv1Set);
+ goto Quit;
+ }
- FlushFileBuffers(hPipe);
- DisconnectNamedPipe(hPipe);
- CloseHandle(hPipe);
+ /* Load user registry hive */
+ Error = RegLoadKeyW(HKEY_USERS, pszSid, szUserHivePath);
- DPRINT("ScmNamedPipeThread(%p) - Done.\n", hPipe);
+ /* Remove restore and backup privileges */
+ RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, WasPriv2Set, FALSE, &WasPriv2Set);
+ RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasPriv1Set, FALSE, &WasPriv1Set);
- return ERROR_SUCCESS;
-}
+ /* HACK: Do not fail if the profile has already been loaded! */
+ if (Error == ERROR_SHARING_VIOLATION)
+ Error = ERROR_SUCCESS;
+ if (Error != ERROR_SUCCESS)
+ {
+ DPRINT1("RegLoadKeyW() failed (Error %ld)\n", Error);
+ goto Quit;
+ }
-BOOL
-ScmCreateNamedPipe(VOID)
-{
- DWORD dwThreadId;
- BOOL bConnected;
- HANDLE hThread;
- HANDLE hPipe;
-
- DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
-
- hPipe = CreateNamedPipeW(L"\\\\.\\pipe\\Ntsvcs",
- PIPE_ACCESS_DUPLEX,
- PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES,
- PIPE_BUFSIZE,
- PIPE_BUFSIZE,
- PIPE_TIMEOUT,
- NULL);
- if (hPipe == INVALID_HANDLE_VALUE)
+ /* Open future HKEY_CURRENT_USER */
+ Error = RegOpenKeyExW(HKEY_USERS,
+ pszSid,
+ 0,
+ MAXIMUM_ALLOWED,
+ phProfile);
+ if (Error != ERROR_SUCCESS)
{
- DPRINT("CreateNamedPipe() failed (%lu)\n", GetLastError());
- return FALSE;
+ DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
+ goto Quit;
}
- DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%p)\n", hPipe);
- bConnected = ConnectNamedPipe(hPipe,
- NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
- DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", bConnected);
+ Success = TRUE;
- if (bConnected)
- {
- DPRINT("Pipe connected\n");
- hThread = CreateThread(NULL,
- 0,
- ScmNamedPipeThread,
- (LPVOID)hPipe,
- 0,
- &dwThreadId);
- if (!hThread)
- {
- DPRINT("Could not create thread (%lu)\n", GetLastError());
- DisconnectNamedPipe(hPipe);
- CloseHandle(hPipe);
- DPRINT("CreateNamedPipe() - returning FALSE\n");
- return FALSE;
- }
+Quit:
+ LocalFree(pSid);
- CloseHandle(hThread);
- }
- else
- {
- DPRINT("Pipe not connected\n");
- CloseHandle(hPipe);
- DPRINT("CreateNamedPipe() - returning FALSE\n");
- return FALSE;
- }
- DPRINT("CreateNamedPipe() - returning TRUE\n");
- return TRUE;
-}
+ DPRINT1("ScmLogAccountsHack(%S) returned %s\n",
+ pszAccountName, Success ? "success" : "failure");
+ return Success;
+}
-DWORD WINAPI
-ScmNamedPipeListenerThread(LPVOID Context)
+static struct
{
-// HANDLE hPipe;
- DPRINT("ScmNamedPipeListenerThread(%p) - aka SCM.\n", Context);
+ LPCWSTR pszAccountName;
+ LPCWSTR pszSid;
+ HKEY hProfile;
+} AccountHandles[] = {
+// {L"LocalSystem" , L"S-1-5-18", NULL},
+ {L"LocalService" , L"S-1-5-19", NULL}, // L"NT AUTHORITY\\LocalService"
+ {L"NetworkService", L"S-1-5-20", NULL}, // L"NT AUTHORITY\\NetworkService"
+};
+
+static VOID
+ScmCleanupServiceAccountsHack(VOID)
+{
+ UINT i;
+
+ DPRINT1("ScmCleanupServiceAccountsHack()\n");
-// hPipe = (HANDLE)Context;
- for (;;)
+ for (i = 0; i < ARRAYSIZE(AccountHandles); ++i)
{
- DPRINT("SCM: Waiting for new connection on named pipe...\n");
- /* Create named pipe */
- if (!ScmCreateNamedPipe())
+ if (AccountHandles[i].hProfile)
{
- DPRINT1("\nSCM: Failed to create named pipe\n");
- break;
- //ExitThread(0);
+ RegCloseKey(AccountHandles[i].hProfile);
+ AccountHandles[i].hProfile = NULL;
}
- DPRINT("\nSCM: named pipe session created.\n");
- Sleep(10);
}
- DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%p) - Aborted.\n\n", Context);
- return ERROR_SUCCESS;
}
-
-BOOL
-StartScmNamedPipeThreadListener(VOID)
+static BOOL
+ScmApplyServiceAccountsHack(VOID)
{
- DWORD dwThreadId;
- HANDLE hThread;
-
- hThread = CreateThread(NULL,
- 0,
- ScmNamedPipeListenerThread,
- NULL, /*(LPVOID)hPipe,*/
- 0,
- &dwThreadId);
- if (!hThread)
- {
- DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
- return FALSE;
- }
-
- CloseHandle(hThread);
-
- return TRUE;
-}
+ UINT i;
+ DPRINT1("ScmApplyServiceAccountsHack()\n");
-BOOL WINAPI
-ShutdownHandlerRoutine(DWORD dwCtrlType)
-{
- DPRINT1("ShutdownHandlerRoutine() called\n");
-
- if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT))
+ for (i = 0; i < ARRAYSIZE(AccountHandles); ++i)
{
- DPRINT1("Shutdown event received!\n");
- ScmShutdown = TRUE;
-
- ScmAutoShutdownServices();
- ScmShutdownServiceDatabase();
-
- /* Set the shutdwon event */
- SetEvent(hScmShutdownEvent);
+ if (!ScmLogAccountHack( AccountHandles[i].pszAccountName,
+ AccountHandles[i].pszSid,
+ &AccountHandles[i].hProfile))
+ {
+ ScmCleanupServiceAccountsHack();
+ return FALSE;
+ }
}
return TRUE;
}
+/*************************** END OF HACK CORE-12541 ***************************/
+
int WINAPI
wWinMain(HINSTANCE hInstance,
int nShowCmd)
{
HANDLE hScmStartEvent = NULL;
+ HANDLE hScmAutoStartCompleteEvent = NULL;
SC_RPC_LOCK Lock = NULL;
BOOL bCanDeleteNamedPipeCriticalSection = FALSE;
DWORD dwError;
DPRINT("SERVICES: Service Control Manager\n");
- /* Create start event */
- if (!ScmCreateStartEvent(&hScmStartEvent))
+ /* Make us critical */
+ RtlSetProcessIsCritical(TRUE, NULL, TRUE);
+
+ /* We are initializing ourselves */
+ ScmInitialize = TRUE;
+
+ /* Create the start event */
+ hScmStartEvent = CreateEventW(NULL, TRUE, FALSE, SCM_START_EVENT);
+ if (hScmStartEvent == NULL)
{
- DPRINT1("SERVICES: Failed to create start event\n");
+ DPRINT1("SERVICES: Failed to create the start event\n");
goto done;
}
+ DPRINT("SERVICES: Created start event with handle %p.\n", hScmStartEvent);
- DPRINT("SERVICES: created start event with handle %p.\n", hScmStartEvent);
+ /* Create the auto-start complete event */
+ hScmAutoStartCompleteEvent = CreateEventW(NULL, TRUE, FALSE, SCM_AUTOSTARTCOMPLETE_EVENT);
+ if (hScmAutoStartCompleteEvent == NULL)
+ {
+ DPRINT1("SERVICES: Failed to create the auto-start complete event\n");
+ goto done;
+ }
+ DPRINT("SERVICES: created auto-start complete event with handle %p.\n", hScmAutoStartCompleteEvent);
/* Create the shutdown event */
- hScmShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ hScmShutdownEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
if (hScmShutdownEvent == NULL)
{
- DPRINT1("SERVICES: Failed to create shutdown event\n");
+ DPRINT1("SERVICES: Failed to create the shutdown event\n");
goto done;
}
// ScmInitThreadManager();
+ ScmInitializeSecurity();
+
/* FIXME: more initialization */
/* Read the control set values */
if (!ScmGetControlSetValues())
{
- DPRINT1("SERVICES: failed to read the control set values\n");
+ DPRINT1("SERVICES: Failed to read the control set values\n");
goto done;
}
dwError = ScmCreateServiceDatabase();
if (dwError != ERROR_SUCCESS)
{
- DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError);
+ DPRINT1("SERVICES: Failed to create SCM database (Error %lu)\n", dwError);
goto done;
}
+ /* Wait for the LSA server */
+ ScmWaitForLsa();
+
/* Update the services database */
ScmGetBootAndSystemDriverState();
- /* Register the Service Control Manager process with CSRSS */
+ /* Register the Service Control Manager process with the ReactOS Subsystem */
if (!RegisterServicesProcess(GetCurrentProcessId()))
{
DPRINT1("SERVICES: Could not register SCM process\n");
goto done;
}
- /* Acquire the service start lock until autostart services have been started */
+ /*
+ * Acquire the user service start lock until
+ * auto-start services have been started.
+ */
dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
if (dwError != ERROR_SUCCESS)
{
- DPRINT1("SERVICES: failed to acquire the service start lock (Error %lu)\n", dwError);
+ DPRINT1("SERVICES: Failed to acquire the service start lock (Error %lu)\n", dwError);
goto done;
}
/* Start the RPC server */
ScmStartRpcServer();
- DPRINT("SERVICES: Initialized.\n");
-
/* Signal start event */
SetEvent(hScmStartEvent);
+ DPRINT("SERVICES: Initialized.\n");
+
/* Register event handler (used for system shutdown) */
SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
- /* Wait for the LSA server */
- ScmWaitForLsa();
+ /*
+ * Set our shutdown parameters: we want to shutdown after the maintained
+ * services (that inherit the default shutdown level of 640).
+ */
+ SetProcessShutdownParameters(480, SHUTDOWN_NORETRY);
+
+ /*** HACK CORE-12541: Apply service accounts HACK ***/
+ ScmApplyServiceAccountsHack();
/* Start auto-start services */
ScmAutoStartServices();
+ /* Signal auto-start complete event */
+ SetEvent(hScmAutoStartCompleteEvent);
+
/* FIXME: more to do ? */
/* Release the service start lock */
ScmReleaseServiceStartLock(&Lock);
+ /* Initialization finished */
+ ScmInitialize = FALSE;
+
DPRINT("SERVICES: Running.\n");
/* Wait until the shutdown event gets signaled */
WaitForSingleObject(hScmShutdownEvent, INFINITE);
+ /*** HACK CORE-12541: Cleanup service accounts HACK ***/
+ ScmCleanupServiceAccountsHack();
+
done:
+ ScmShutdownSecurity();
+
/* Delete our communication named pipe's critical section */
- if (bCanDeleteNamedPipeCriticalSection == TRUE)
+ if (bCanDeleteNamedPipeCriticalSection != FALSE)
ScmDeleteNamedPipeCriticalSection();
/* Close the shutdown event */
if (hScmShutdownEvent != NULL)
CloseHandle(hScmShutdownEvent);
+ /* Close the auto-start complete event */
+ if (hScmAutoStartCompleteEvent != NULL)
+ CloseHandle(hScmAutoStartCompleteEvent);
+
/* Close the start event */
if (hScmStartEvent != NULL)
CloseHandle(hScmStartEvent);
DPRINT("SERVICES: Finished.\n");
ExitThread(0);
-
return 0;
}