Cleanup shutdown code path. Now, the user can logoff and logon again.

svn path=/trunk/; revision=23501
This commit is contained in:
Hervé Poussineau 2006-08-06 15:47:04 +00:00
parent b229f6fcb2
commit 63e6cdc364
2 changed files with 188 additions and 113 deletions

View file

@ -149,7 +149,10 @@ DoGenericAction(
Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context); Session->Gina.Functions.WlxDisplaySASNotice(Session->Gina.Context);
} }
if (WLX_SHUTTINGDOWN(wlxAction)) if (WLX_SHUTTINGDOWN(wlxAction))
{
Session->Gina.Functions.WlxShutdown(Session->Gina.Context, wlxAction);
HandleShutdown(Session, wlxAction); HandleShutdown(Session, wlxAction);
}
break; break;
case WLX_SAS_ACTION_TASKLIST: /* 0x07 */ case WLX_SAS_ACTION_TASKLIST: /* 0x07 */
SwitchDesktop(WLSession->ApplicationDesktop); SwitchDesktop(WLSession->ApplicationDesktop);
@ -256,128 +259,164 @@ typedef struct tagLOGOFF_SHUTDOWN_DATA
static DWORD WINAPI static DWORD WINAPI
LogoffShutdownThread(LPVOID Parameter) LogoffShutdownThread(LPVOID Parameter)
{ {
PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA) Parameter; PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA) Parameter;
if (! ImpersonateLoggedOnUser(LSData->Session->UserToken)) if (!ImpersonateLoggedOnUser(LSData->Session->UserToken))
{ {
DPRINT1("ImpersonateLoggedOnUser failed with error %d\n", GetLastError()); ERR("ImpersonateLoggedOnUser failed with error %lu\n", GetLastError());
return 0; return 0;
} }
if (! ExitWindowsEx(EWX_INTERNAL_KILL_USER_APPS | (LSData->Flags & EWX_FLAGS_MASK)
| (EWX_LOGOFF == (LSData->Flags & EWX_ACTION_MASK) ? EWX_INTERNAL_FLAG_LOGOFF : 0),
0))
{
DPRINT1("Unable to kill user apps, error %d\n", GetLastError());
RevertToSelf();
return 0;
}
RevertToSelf();
/* This is not right (see top of reactos/dll/win32/user32/misc/exit.c), /* Close processes of the interactive user */
* but this should be enough atm */ if (!ExitWindowsEx(
switch (LSData->Flags & EWX_ACTION_MASK) EWX_INTERNAL_KILL_USER_APPS | (LSData->Flags & EWX_FLAGS_MASK) |
{ (EWX_LOGOFF == (LSData->Flags & EWX_ACTION_MASK) ? EWX_INTERNAL_FLAG_LOGOFF : 0),
case EWX_SHUTDOWN: 0))
NtShutdownSystem(ShutdownNoReboot); {
break; ERR("Unable to kill user apps, error %lu\n", GetLastError());
case EWX_REBOOT: RevertToSelf();
NtShutdownSystem(ShutdownReboot); return 0;
break; }
default:
UNIMPLEMENTED;
}
HeapFree(GetProcessHeap(), 0, LSData); /* FIXME: Call ExitWindowsEx() to terminate COM processes */
return 1; RevertToSelf();
return 1;
}
static NTSTATUS
CheckPrivilegeForRequestedAction(
IN UINT Action,
IN DWORD RequestingProcessId)
{
HANDLE Process;
HANDLE Token;
BOOL CheckResult;
PPRIVILEGE_SET PrivSet;
TRACE("CheckPrivilegeForRequestedAction(%u)\n", Action);
if (Action == EWX_LOGOFF)
/* No privilege needed to log off */
return STATUS_SUCCESS;
/* Check for invalid arguments */
if (Action != EWX_SHUTDOWN && Action != EWX_REBOOT && Action != EWX_POWEROFF)
{
ERR("Invalid exit action %u\n", Action);
return STATUS_INVALID_PARAMETER;
}
Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, RequestingProcessId);
if (!Process)
{
WARN("OpenProcess() failed with error %lu\n", GetLastError());
return STATUS_INVALID_HANDLE;
}
if (!OpenProcessToken(Process, TOKEN_QUERY, &Token))
{
WARN("OpenProcessToken() failed with error %lu\n", GetLastError());
CloseHandle(Process);
return STATUS_INVALID_HANDLE;
}
CloseHandle(Process);
PrivSet = HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET) + sizeof(LUID_AND_ATTRIBUTES));
if (!PrivSet)
{
ERR("Failed to allocate mem for privilege set\n");
CloseHandle(Token);
return STATUS_NO_MEMORY;
}
PrivSet->PrivilegeCount = 1;
PrivSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
if (!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &PrivSet->Privilege[0].Luid))
{
WARN("LookupPrivilegeValue() failed with error %lu\n", GetLastError());
HeapFree(GetProcessHeap(), 0, PrivSet);
CloseHandle(Token);
return STATUS_UNSUCCESSFUL;
}
if (!PrivilegeCheck(Token, PrivSet, &CheckResult))
{
WARN("PrivilegeCheck() failed with error %lu\n", GetLastError());
HeapFree(GetProcessHeap(), 0, PrivSet);
CloseHandle(Token);
return STATUS_ACCESS_DENIED;
}
HeapFree(GetProcessHeap(), 0, PrivSet);
CloseHandle(Token);
if (!CheckResult)
{
WARN("SE_SHUTDOWN privilege not enabled\n");
return STATUS_ACCESS_DENIED;
}
} }
static LRESULT static LRESULT
HandleExitWindows(PWLSESSION Session, DWORD RequestingProcessId, UINT Flags) HandleExitWindows(
IN OUT PWLSESSION Session,
IN DWORD RequestingProcessId,
IN UINT Flags)
{ {
UINT Action; UINT Action;
HANDLE Process; PLOGOFF_SHUTDOWN_DATA LSData;
HANDLE Token; HANDLE hThread;
HANDLE Thread; NTSTATUS Status;
BOOL CheckResult;
PPRIVILEGE_SET PrivSet;
PLOGOFF_SHUTDOWN_DATA LSData;
/* Check parameters */ /* Check parameters */
Action = Flags & EWX_ACTION_MASK; Action = Flags & EWX_ACTION_MASK;
if (EWX_LOGOFF != Action && EWX_SHUTDOWN != Action && EWX_REBOOT != Action if (Action != EWX_LOGOFF &&
&& EWX_POWEROFF != Action) Action != EWX_SHUTDOWN &&
{ Action != EWX_REBOOT &&
DPRINT1("Invalid ExitWindows action 0x%x\n", Action); Action != EWX_POWEROFF)
return STATUS_INVALID_PARAMETER; {
} ERR("Invalid ExitWindows action 0x%x\n", Action);
return STATUS_INVALID_PARAMETER;
}
/* Check privilege */ /* Check privilege */
if (EWX_LOGOFF != Action) Status = CheckPrivilegeForRequestedAction(Action, RequestingProcessId);
{ if (!NT_SUCCESS(Status))
Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, RequestingProcessId); return Status;
if (NULL == Process)
{
DPRINT1("OpenProcess failed with error %d\n", GetLastError());
return STATUS_INVALID_HANDLE;
}
if (! OpenProcessToken(Process, TOKEN_QUERY, &Token))
{
DPRINT1("OpenProcessToken failed with error %d\n", GetLastError());
CloseHandle(Process);
return STATUS_INVALID_HANDLE;
}
CloseHandle(Process);
PrivSet = HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET) + sizeof(LUID_AND_ATTRIBUTES));
if (NULL == PrivSet)
{
DPRINT1("Failed to allocate mem for privilege set\n");
CloseHandle(Token);
return STATUS_NO_MEMORY;
}
PrivSet->PrivilegeCount = 1;
PrivSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
if (! LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &PrivSet->Privilege[0].Luid))
{
DPRINT1("LookupPrivilegeValue failed with error %d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, PrivSet);
CloseHandle(Token);
return STATUS_UNSUCCESSFUL;
}
if (! PrivilegeCheck(Token, PrivSet, &CheckResult))
{
DPRINT1("PrivilegeCheck failed with error %d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, PrivSet);
CloseHandle(Token);
return STATUS_ACCESS_DENIED;
}
HeapFree(GetProcessHeap(), 0, PrivSet);
CloseHandle(Token);
if (! CheckResult)
{
DPRINT1("SE_SHUTDOWN privilege not enabled\n");
return STATUS_ACCESS_DENIED;
}
}
LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA)); /* Prepare data for logoff/shutdown thread */
if (NULL == LSData) LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA));
{ if (!LSData)
DPRINT1("Failed to allocate mem for thread data\n"); {
return STATUS_NO_MEMORY; ERR("Failed to allocate mem for thread data\n");
} return STATUS_NO_MEMORY;
LSData->Flags = Flags; }
LSData->Session = Session; LSData->Flags = Flags;
Thread = CreateThread(NULL, 0, LogoffShutdownThread, (LPVOID) LSData, 0, NULL); LSData->Session = Session;
if (NULL == Thread)
{
DPRINT1("Unable to create shutdown thread, error %d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, LSData);
return STATUS_UNSUCCESSFUL;
}
CloseHandle(Thread);
return 1; /* Run logoff/shutdown thread */
hThread = CreateThread(NULL, 0, LogoffShutdownThread, (LPVOID)LSData, 0, NULL);
if (!hThread)
{
ERR("Unable to create shutdown thread, error %lu\n", GetLastError());
HeapFree(GetProcessHeap(), 0, LSData);
return STATUS_UNSUCCESSFUL;
}
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
HeapFree(GetProcessHeap(), 0, LSData);
Session->LogonStatus = WKSTA_IS_LOGGED_OFF;
if (Action == EWX_LOGOFF)
{
DispatchSAS(Session, WLX_SAS_TYPE_TIMEOUT);
return 1;
}
/* Handle shutdown */
FIXME("FIXME: Call ExitWindowEx in SYSTEM process context\n");
FIXME("FIXME: Call SMSS API #1\n");
NtShutdownSystem(ShutdownNoReboot); /* FIXME: should go in smss */
return 1;
} }
static LRESULT CALLBACK static LRESULT CALLBACK

View file

@ -57,6 +57,9 @@ WlxUseCtrlAltDel(
HANDLE hWlx) HANDLE hWlx)
{ {
ULONG_PTR OldValue; ULONG_PTR OldValue;
TRACE("WlxUseCtrlAltDel()\n");
WlxSetOption(hWlx, WLX_OPTION_USE_CTRL_ALT_DEL, TRUE, &OldValue); WlxSetOption(hWlx, WLX_OPTION_USE_CTRL_ALT_DEL, TRUE, &OldValue);
} }
@ -69,6 +72,9 @@ WlxSetContextPointer(
PVOID pWlxContext) PVOID pWlxContext)
{ {
ULONG_PTR OldValue; ULONG_PTR OldValue;
TRACE("WlxSetContextPointer(%p)\n", pWlxContext);
WlxSetOption(hWlx, WLX_OPTION_CONTEXT_POINTER, (ULONG_PTR)pWlxContext, &OldValue); WlxSetOption(hWlx, WLX_OPTION_CONTEXT_POINTER, (ULONG_PTR)pWlxContext, &OldValue);
} }
@ -80,6 +86,7 @@ WlxSasNotify(
HANDLE hWlx, HANDLE hWlx,
DWORD dwSasType) DWORD dwSasType)
{ {
TRACE("WlxSasNotify(0x%lx)\n", dwSasType);
DispatchSAS((PWLSESSION)hWlx, dwSasType); DispatchSAS((PWLSESSION)hWlx, dwSasType);
} }
@ -92,6 +99,9 @@ WlxSetTimeout(
DWORD Timeout) DWORD Timeout)
{ {
PWLSESSION Session = (PWLSESSION)hWlx; PWLSESSION Session = (PWLSESSION)hWlx;
TRACE("WlxSetTimeout(%lu)\n", Timeout);
Session->DialogTimeout = Timeout; Session->DialogTimeout = Timeout;
return TRUE; return TRUE;
} }
@ -121,6 +131,7 @@ WlxMessageBox(
LPWSTR lpszTitle, LPWSTR lpszTitle,
UINT fuStyle) UINT fuStyle)
{ {
TRACE("WlxMessageBox()\n");
/* FIXME: Provide a custom window proc to be able to handle timeout */ /* FIXME: Provide a custom window proc to be able to handle timeout */
return MessageBoxW(hwndOwner, lpszText, lpszTitle, fuStyle); return MessageBoxW(hwndOwner, lpszText, lpszTitle, fuStyle);
} }
@ -136,6 +147,8 @@ WlxDialogBox(
HWND hwndOwner, HWND hwndOwner,
DLGPROC dlgprc) DLGPROC dlgprc)
{ {
TRACE("WlxDialogBox()\n");
if (PreviousWindowProc != NULL) if (PreviousWindowProc != NULL)
return -1; return -1;
PreviousWindowProc = dlgprc; PreviousWindowProc = dlgprc;
@ -154,6 +167,8 @@ WlxDialogBoxParam(
DLGPROC dlgprc, DLGPROC dlgprc,
LPARAM dwInitParam) LPARAM dwInitParam)
{ {
TRACE("WlxDialogBoxParam()\n");
if (PreviousWindowProc != NULL) if (PreviousWindowProc != NULL)
return -1; return -1;
PreviousWindowProc = dlgprc; PreviousWindowProc = dlgprc;
@ -171,6 +186,8 @@ WlxDialogBoxIndirect(
HWND hwndOwner, HWND hwndOwner,
DLGPROC dlgprc) DLGPROC dlgprc)
{ {
TRACE("WlxDialogBoxIndirect()\n");
if (PreviousWindowProc != NULL) if (PreviousWindowProc != NULL)
return -1; return -1;
PreviousWindowProc = dlgprc; PreviousWindowProc = dlgprc;
@ -189,6 +206,8 @@ WlxDialogBoxIndirectParam(
DLGPROC dlgprc, DLGPROC dlgprc,
LPARAM dwInitParam) LPARAM dwInitParam)
{ {
TRACE("WlxDialogBoxIndirectParam()\n");
if (PreviousWindowProc != NULL) if (PreviousWindowProc != NULL)
return -1; return -1;
PreviousWindowProc = dlgprc; PreviousWindowProc = dlgprc;
@ -203,6 +222,9 @@ WlxSwitchDesktopToUser(
HANDLE hWlx) HANDLE hWlx)
{ {
PWLSESSION Session = (PWLSESSION)hWlx; PWLSESSION Session = (PWLSESSION)hWlx;
TRACE("WlxSwitchDesktopToUser()\n");
return (int)SwitchDesktop(Session->ApplicationDesktop); return (int)SwitchDesktop(Session->ApplicationDesktop);
} }
@ -214,6 +236,9 @@ WlxSwitchDesktopToWinlogon(
HANDLE hWlx) HANDLE hWlx)
{ {
PWLSESSION Session = (PWLSESSION)hWlx; PWLSESSION Session = (PWLSESSION)hWlx;
TRACE("WlxSwitchDesktopToWinlogon()\n");
return (int)SwitchDesktop(Session->WinlogonDesktop); return (int)SwitchDesktop(Session->WinlogonDesktop);
} }
@ -309,6 +334,8 @@ WlxSetOption(
{ {
PWLSESSION Session = (PWLSESSION)hWlx; PWLSESSION Session = (PWLSESSION)hWlx;
TRACE("WlxSetOption(%lu)\n", Option);
switch (Option) switch (Option)
{ {
case WLX_OPTION_USE_CTRL_ALT_DEL: case WLX_OPTION_USE_CTRL_ALT_DEL:
@ -338,6 +365,8 @@ WlxGetOption(
{ {
PWLSESSION Session = (PWLSESSION)hWlx; PWLSESSION Session = (PWLSESSION)hWlx;
TRACE("WlxGetOption(%lu)\n", Option);
switch (Option) switch (Option)
{ {
case WLX_OPTION_USE_CTRL_ALT_DEL: case WLX_OPTION_USE_CTRL_ALT_DEL:
@ -460,7 +489,7 @@ WlxQueryTsLogonCredentials(
return FALSE; return FALSE;
} }
static const static
WLX_DISPATCH_VERSION_1_4 FunctionTable = { WLX_DISPATCH_VERSION_1_4 FunctionTable = {
WlxUseCtrlAltDel, WlxUseCtrlAltDel,
WlxSetContextPointer, WlxSetContextPointer,
@ -559,8 +588,15 @@ LoadGina(
/* Assume current version */ /* Assume current version */
*DllVersion = WLX_CURRENT_VERSION; *DllVersion = WLX_CURRENT_VERSION;
} }
else if (!Functions->WlxNegotiate(WLX_CURRENT_VERSION, DllVersion)) else
goto cleanup; {
TRACE("About to negociate with Gina %S. Winlogon uses version %lx\n",
GinaDll, WLX_CURRENT_VERSION);
if (!Functions->WlxNegotiate(WLX_CURRENT_VERSION, DllVersion))
goto cleanup;
}
TRACE("Gina uses WLX_VERSION %lx\n", *DllVersion);
if (*DllVersion >= WLX_VERSION_1_0) if (*DllVersion >= WLX_VERSION_1_0)
{ {