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);
}
if (WLX_SHUTTINGDOWN(wlxAction))
{
Session->Gina.Functions.WlxShutdown(Session->Gina.Context, wlxAction);
HandleShutdown(Session, wlxAction);
}
break;
case WLX_SAS_ACTION_TASKLIST: /* 0x07 */
SwitchDesktop(WLSession->ApplicationDesktop);
@ -256,128 +259,164 @@ typedef struct tagLOGOFF_SHUTDOWN_DATA
static DWORD WINAPI
LogoffShutdownThread(LPVOID Parameter)
{
PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA) Parameter;
PLOGOFF_SHUTDOWN_DATA LSData = (PLOGOFF_SHUTDOWN_DATA) Parameter;
if (! ImpersonateLoggedOnUser(LSData->Session->UserToken))
{
DPRINT1("ImpersonateLoggedOnUser failed with error %d\n", GetLastError());
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();
if (!ImpersonateLoggedOnUser(LSData->Session->UserToken))
{
ERR("ImpersonateLoggedOnUser failed with error %lu\n", GetLastError());
return 0;
}
/* This is not right (see top of reactos/dll/win32/user32/misc/exit.c),
* but this should be enough atm */
switch (LSData->Flags & EWX_ACTION_MASK)
{
case EWX_SHUTDOWN:
NtShutdownSystem(ShutdownNoReboot);
break;
case EWX_REBOOT:
NtShutdownSystem(ShutdownReboot);
break;
default:
UNIMPLEMENTED;
}
/* Close processes of the interactive user */
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))
{
ERR("Unable to kill user apps, error %lu\n", GetLastError());
RevertToSelf();
return 0;
}
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
HandleExitWindows(PWLSESSION Session, DWORD RequestingProcessId, UINT Flags)
HandleExitWindows(
IN OUT PWLSESSION Session,
IN DWORD RequestingProcessId,
IN UINT Flags)
{
UINT Action;
HANDLE Process;
HANDLE Token;
HANDLE Thread;
BOOL CheckResult;
PPRIVILEGE_SET PrivSet;
PLOGOFF_SHUTDOWN_DATA LSData;
UINT Action;
PLOGOFF_SHUTDOWN_DATA LSData;
HANDLE hThread;
NTSTATUS Status;
/* Check parameters */
Action = Flags & EWX_ACTION_MASK;
if (EWX_LOGOFF != Action && EWX_SHUTDOWN != Action && EWX_REBOOT != Action
&& EWX_POWEROFF != Action)
{
DPRINT1("Invalid ExitWindows action 0x%x\n", Action);
return STATUS_INVALID_PARAMETER;
}
/* Check parameters */
Action = Flags & EWX_ACTION_MASK;
if (Action != EWX_LOGOFF &&
Action != EWX_SHUTDOWN &&
Action != EWX_REBOOT &&
Action != EWX_POWEROFF)
{
ERR("Invalid ExitWindows action 0x%x\n", Action);
return STATUS_INVALID_PARAMETER;
}
/* Check privilege */
if (EWX_LOGOFF != Action)
{
Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, RequestingProcessId);
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;
}
}
/* Check privilege */
Status = CheckPrivilegeForRequestedAction(Action, RequestingProcessId);
if (!NT_SUCCESS(Status))
return Status;
LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA));
if (NULL == LSData)
{
DPRINT1("Failed to allocate mem for thread data\n");
return STATUS_NO_MEMORY;
}
LSData->Flags = Flags;
LSData->Session = Session;
Thread = CreateThread(NULL, 0, LogoffShutdownThread, (LPVOID) LSData, 0, NULL);
if (NULL == Thread)
{
DPRINT1("Unable to create shutdown thread, error %d\n", GetLastError());
HeapFree(GetProcessHeap(), 0, LSData);
return STATUS_UNSUCCESSFUL;
}
CloseHandle(Thread);
/* Prepare data for logoff/shutdown thread */
LSData = HeapAlloc(GetProcessHeap(), 0, sizeof(LOGOFF_SHUTDOWN_DATA));
if (!LSData)
{
ERR("Failed to allocate mem for thread data\n");
return STATUS_NO_MEMORY;
}
LSData->Flags = Flags;
LSData->Session = Session;
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

View file

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