summaryrefslogtreecommitdiffstats
path: root/private/windows/gina/winlogon/sysshut.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/windows/gina/winlogon/sysshut.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/windows/gina/winlogon/sysshut.c')
-rw-r--r--private/windows/gina/winlogon/sysshut.c1395
1 files changed, 1395 insertions, 0 deletions
diff --git a/private/windows/gina/winlogon/sysshut.c b/private/windows/gina/winlogon/sysshut.c
new file mode 100644
index 000000000..65ff4c55f
--- /dev/null
+++ b/private/windows/gina/winlogon/sysshut.c
@@ -0,0 +1,1395 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ Shutdown.c
+
+Abstract:
+
+ This module contains the server side implementation for the Win32 remote
+ shutdown APIs, that is:
+
+ - BaseInitiateSystemShutdown
+ - BaseAbortSystemShutdown
+
+Author:
+
+ Dave Chalmers (davidc) 29-Apr-1992
+
+Notes:
+
+
+Revision History:
+
+ 19-Oct-1993 Danl
+ Removed HackExtraThread which was only here to work around a bug in
+ the UserSrv. The text describing the reason for this workaround is
+ as follows:
+ HACKHACK - Work around bug in UserSrv that causes ExitWindowsEx to
+ fail (error 5) when called by a process which doesn't
+ have any threads which have called User APIs. Remove
+ after UserSrv is fixed. See NTBUG 11601.
+ Workaround is to create a thread which will make one
+ API call then sleep forever.
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define RPC_NO_WINDOWS_H
+#include "regrpc.h"
+#include "ntrpcp.h"
+#include <rpc.h>
+
+// // // // // //
+
+//
+// Shutdown Dialog Return Codes:
+//
+
+#define SHUTDOWN_SUCCESS 0
+#define SHUTDOWN_USER_LOGOFF 1
+#define SHUTDOWN_DESKTOP_SWITCH 2
+#define SHUTDOWN_CANCELLED 3
+
+//
+// System Shutdown globals
+//
+
+RTL_CRITICAL_SECTION ShutdownCriticalSection; // Protect global shutdown data
+
+//
+// Set when a thread has a shutdown 'in progress'
+// (Protected by critical section)
+//
+
+BOOL ShutdownInProgress;
+
+//
+// Set when a thread wants to interrupt the shutdown
+// (Protected by critical section)
+//
+
+BOOL AbortShutdown;
+
+
+//
+// Data for shutdown UI - this is protected by the ShutdownInProgress flag.
+// i.e. only the current shutdown thread manipulates this data.
+//
+
+LARGE_INTEGER ShutdownTime;
+DWORD ShutdownDelayInSeconds;
+PTCH ShutdownMessage;
+DWORD ExitWindowsFlags;
+DWORD GinaCode;
+PTSTR UserName;
+PTSTR UserDomain;
+BOOL AllowLogonDuringShutdown = TRUE ;
+ActiveDesktops ShutdownDesktop;
+WINDOWPLACEMENT ShutdownWindowPlacement;
+BOOL ShutdownGetPlacement = FALSE;
+BOOL ShutdownHasBegun = FALSE;
+
+//
+// Data captured during initialization
+//
+
+PGLOBALS GlobalWinMainData;
+
+
+
+
+
+//
+// Private prototypes
+//
+
+
+DWORD
+InitializeShutdownData(
+ PUNICODE_STRING lpMessage,
+ DWORD dwTimeout,
+ BOOL bForceAppsClosed,
+ BOOL bRebootAfterShutdown
+ );
+
+VOID
+FreeShutdownData(
+ VOID
+ );
+
+BOOL WINAPI
+ShutdownApiDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL
+UpdateTimeToShutdown(
+ HWND hDlg
+ );
+
+VOID
+CentreWindow(
+ HWND hwnd
+ );
+
+DWORD
+TestClientPrivilege(
+ VOID
+ );
+
+DWORD
+GetClientId(
+ PTSTR *UserName,
+ PTSTR *UserDomain
+ );
+
+VOID
+DeleteClientId(
+ PTSTR UserName,
+ PTSTR UserDomain
+ );
+
+BOOL
+InsertClientId(
+ HWND hDlg,
+ int ControlId,
+ PTSTR UserName,
+ PTSTR UserDomain
+ );
+
+
+
+
+
+BOOL
+InitializeShutdownModule(
+ PGLOBALS pGlobals
+ )
+/*++
+
+Routine Description:
+
+ Does any initializtion required for this module.
+
+Arguments:
+
+ pGlobals - Pointer to global data defined in WinMain
+
+Return Value:
+
+ Returns TRUE on success, FALSE on failure.
+
+--*/
+{
+ NTSTATUS Status;
+
+ //
+ // Initialize global variables
+ //
+
+ ShutdownInProgress = FALSE;
+
+ //
+ // Initialize critical section to protect globals
+ //
+
+ Status = RtlInitializeCriticalSection(&ShutdownCriticalSection);
+
+#if DBG
+ if (!NT_SUCCESS(Status)) {
+ DbgPrint("Registry Server : Shutdown : Failed to initialize critical section\n");
+ }
+#endif
+
+ GlobalWinMainData = pGlobals;
+ return(NT_SUCCESS(Status));
+}
+
+ULONG
+BaseInitiateSystemShutdown(
+ IN PREGISTRY_SERVER_NAME ServerName,
+ IN PUNICODE_STRING lpMessage OPTIONAL,
+ IN DWORD dwTimeout,
+ IN BOOLEAN bForceAppsClosed,
+ IN BOOLEAN bRebootAfterShutdown
+ )
+/*++
+
+Routine Description:
+
+ Initiates the shutdown of this machine.
+
+Arguments:
+
+ ServerName - Name of machine this server code is running on. (Ignored)
+
+ lpMessage - message to display during shutdown timeout period.
+
+ dwTimeout - number of seconds to delay before shutting down
+
+ bForceAppsClosed - Normally applications may prevent system shutdown.
+ - If this true, all applications are terminated unconditionally.
+
+ bRebootAfterShutdown - TRUE if the system should reboot. FALSE if it should
+ - be left in a shutdown state.
+
+Return Value:
+
+ Returns ERROR_SUCCESS (0) for success; error-code for failure.
+
+--*/
+
+{
+ NTSTATUS Status;
+ DWORD Error;
+
+ //
+ // Check the caller has the appropriate privilege
+ //
+
+ Error = TestClientPrivilege();
+ if (Error != ERROR_SUCCESS) {
+ return(Error);
+ }
+
+ //
+ // Enter the critical section so we can look at our globals
+ //
+
+ Status = RtlEnterCriticalSection(&ShutdownCriticalSection);
+ if (!NT_SUCCESS(Status)) {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+ //
+ // Set up our global shutdown data.
+ // Fail if a shutdown is already in progress
+ //
+
+ if (ShutdownInProgress) {
+ Error = ERROR_SHUTDOWN_IN_PROGRESS;
+ } else {
+
+ //
+ // Set up our globals for the shutdown thread to use.
+ //
+
+ Error = InitializeShutdownData(lpMessage,
+ dwTimeout,
+ bForceAppsClosed,
+ bRebootAfterShutdown
+ );
+ if (Error == ERROR_SUCCESS) {
+ ShutdownInProgress = TRUE;
+ AbortShutdown = FALSE;
+ }
+ }
+
+ //
+ // Leave the critical section
+ //
+
+ Status = RtlLeaveCriticalSection(&ShutdownCriticalSection);
+ if (Error == ERROR_SUCCESS) {
+ if (!NT_SUCCESS(Status)) {
+ Error = RtlNtStatusToDosError(Status);
+ }
+ } else {
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+
+
+ //
+ // Create a thread to handle the shutdown (UI and calling ExitWindows)
+ // The thread will handle resetting our shutdown data and globals.
+ //
+
+ if (Error == ERROR_SUCCESS) {
+ int Result;
+
+ //
+ // Have winlogon create us a thread running on the user's desktop.
+ //
+ // The thread will do a call back to ShutdownThread()
+ //
+
+ GlobalWinMainData->LogoffFlags = EWX_WINLOGON_API_SHUTDOWN | ExitWindowsFlags;
+ Result = InitiateLogoff( GlobalWinMainData,
+ EWX_WINLOGON_API_SHUTDOWN | ExitWindowsFlags );
+
+
+ if (Result != DLG_SUCCESS ) {
+ Error = GetLastError();
+ KdPrint(("InitiateSystemShutdown : Failed to create shutdown thread. Error = %d\n", Error));
+ FreeShutdownData();
+ ShutdownInProgress = FALSE; // Atomic operation
+ }
+ }
+
+ return(Error);
+
+ UNREFERENCED_PARAMETER(ServerName);
+}
+
+
+
+DWORD
+InitializeShutdownData(
+ PUNICODE_STRING lpMessage,
+ DWORD dwTimeout,
+ BOOL bForceAppsClosed,
+ BOOL bRebootAfterShutdown
+ )
+/*++
+
+Routine Description:
+
+ Stores the passed shutdown parameters in our global data.
+
+Return Value:
+
+ Returns ERROR_SUCCESS (0) for success; error-code for failure.
+
+--*/
+
+{
+ NTSTATUS Status;
+ LARGE_INTEGER TimeNow;
+ LARGE_INTEGER Delay;
+ DWORD Error;
+
+ //
+ // Set the shutdown time
+ //
+
+ ShutdownDelayInSeconds = dwTimeout;
+
+ Status = NtQuerySystemTime(&TimeNow);
+ if (!NT_SUCCESS(Status)) {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+ Delay = RtlEnlargedUnsignedMultiply(dwTimeout, 10000000); // Delay in 100ns
+
+ ShutdownTime.QuadPart = TimeNow.QuadPart + Delay.QuadPart;
+
+
+ //
+ // Set the shutdown flags
+ //
+ // We set the EWX_WINLOGON_OLD_xxx and EWX_xxx both since this message
+ // originates from the winlogon process. When these flags actually bubble
+ // back to the active dialog box, winlogon expects the EWX_WINLOGON_OLD_xxx
+ // to indicate the 'real' request.
+ //
+
+ ExitWindowsFlags = EWX_LOGOFF | EWX_SHUTDOWN | EWX_WINLOGON_OLD_SHUTDOWN;
+ ExitWindowsFlags |= bForceAppsClosed ? EWX_FORCE : 0;
+ ExitWindowsFlags |= bRebootAfterShutdown ?
+ (EWX_REBOOT | EWX_WINLOGON_OLD_REBOOT) : 0;
+
+ if (bRebootAfterShutdown)
+ {
+ GinaCode = WLX_SAS_ACTION_SHUTDOWN_REBOOT;
+ }
+ else
+ {
+ GinaCode = WLX_SAS_ACTION_SHUTDOWN;
+ }
+
+
+ //
+ // Store the caller's username and domain.
+ //
+
+ Error = GetClientId(&UserName, &UserDomain);
+ if (Error != ERROR_SUCCESS) {
+ return(Error);
+ }
+
+
+ //
+ // Set the shutdown message
+ //
+
+ if (lpMessage != NULL) {
+
+ //
+ // Copy the message into a global buffer
+ //
+
+ USHORT Bytes = lpMessage->Length + (USHORT)sizeof(UNICODE_NULL);
+
+ ShutdownMessage = (PTCH)LocalAlloc(LPTR, Bytes);
+ if (ShutdownMessage == NULL) {
+ DeleteClientId(UserName, UserDomain);
+ return(ERROR_NOT_ENOUGH_MEMORY);
+ }
+
+ RtlMoveMemory(ShutdownMessage, lpMessage->Buffer, lpMessage->Length);
+ ShutdownMessage[lpMessage->Length / sizeof(WCHAR)] = 0; // Null terminate
+
+ } else {
+ ShutdownMessage = NULL;
+ }
+
+
+ return(ERROR_SUCCESS);
+}
+
+
+
+VOID
+FreeShutdownData(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Frees up any memory allocated to store the shutdown data
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (ShutdownMessage != NULL) {
+ LocalFree(ShutdownMessage);
+ ShutdownMessage = NULL;
+ }
+
+ DeleteClientId(UserName, UserDomain);
+ UserName = NULL;
+ UserDomain = NULL;
+}
+
+
+
+BOOLEAN
+ShutdownThread(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Handles the display of a shutdown dialog and coordinating with the
+ AbortShutdown API.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE - system should be shut down
+ FALSE - shutdown was aborted
+
+--*/
+{
+ NTSTATUS Status;
+ DWORD Error;
+ BOOL DoShutdown = TRUE;
+ HDESK hdesk;
+ BOOL CloseDesktopHandle;
+ DWORD Result;
+ BOOL Locked;
+ BOOL Success;
+
+ //
+ // Quick check so we don't get into thorny race conditions.
+ //
+
+ if ( ShutdownDelayInSeconds == 0 )
+ {
+
+ FreeShutdownData();
+
+ RtlEnterCriticalSection( &ShutdownCriticalSection );
+
+ ShutdownInProgress = FALSE ;
+
+ RtlLeaveCriticalSection( &ShutdownCriticalSection );
+
+ GlobalWinMainData->LastGinaRet = GinaCode;
+
+ ShutdownHasBegun = TRUE;
+
+ return( TRUE );
+
+ }
+
+
+ hdesk = GetActiveDesktop(&GlobalWinMainData->WindowStation,
+ &CloseDesktopHandle,
+ &Locked);
+
+ while (hdesk != NULL)
+ {
+ DebugLog((DEB_TRACE, "Starting shutdown dialog on desktop %x\n", hdesk));
+
+ if (Locked)
+ {
+ UnlockWindowStation(GlobalWinMainData->WindowStation.hwinsta);
+ }
+
+ Success = SetThreadDesktop(hdesk);
+ if (!Success)
+ {
+ DebugLog((DEB_TRACE, "Unable to set desktop, %d\n", GetLastError()));
+ }
+
+ if (Locked)
+ {
+ LockWindowStation(GlobalWinMainData->WindowStation.hwinsta);
+ }
+
+ ShutdownDesktop = GlobalWinMainData->WindowStation.ActiveDesktop;
+
+
+ //
+ // Push the timeout past the shutdown delay, so that we can
+ // catch the messages we want, without stomping on the timeout
+ // structures.
+ //
+ Result = DialogBoxParam( GetModuleHandle(NULL),
+ MAKEINTRESOURCE( IDD_SYSTEM_SHUTDOWN ),
+ NULL,
+ ShutdownApiDlgProc,
+ (LPARAM) 0 );
+
+ DebugLog((DEB_TRACE, "Shutdown Dialog Returned %d\n", Result ));
+
+
+
+ if (CloseDesktopHandle)
+ {
+ CloseDesktop( hdesk );
+ }
+
+ if ((Result == SHUTDOWN_SUCCESS) ||
+ (Result == SHUTDOWN_CANCELLED) )
+ {
+ break;
+ }
+
+ //
+ // Trickier ones:
+ //
+
+ if (Result == SHUTDOWN_USER_LOGOFF)
+ {
+ if (!AllowLogonDuringShutdown)
+ {
+ break;
+ }
+
+ }
+
+ ShutdownGetPlacement = TRUE;
+
+ hdesk = GetActiveDesktop(&GlobalWinMainData->WindowStation,
+ &CloseDesktopHandle,
+ &Locked);
+
+ DebugLog((DEB_TRACE, "Switching to current desktop and restarting dialog\n"));
+
+ }
+
+ //
+ // The shutdown has either completed or been cancelled
+ // Reset our globals.
+ //
+ // Note we need to reset the shutdown-in-progress flag before
+ // entering the non-abortable part of shutdown so that anyone
+ // trying to abort from here on in will get a failure return code.
+ //
+
+ FreeShutdownData();
+
+
+ Status = RtlEnterCriticalSection(&ShutdownCriticalSection);
+ Error = RtlNtStatusToDosError(Status);
+
+ if (Error == ERROR_SUCCESS) {
+
+ //
+ // Reset the global shutdown-in-progress flag
+ // and check for an abort request.
+ //
+
+ if (AbortShutdown) {
+ DoShutdown = FALSE;
+ }
+
+ ShutdownInProgress = FALSE;
+
+ //
+ // Leave the critical section
+ //
+
+ Status = RtlLeaveCriticalSection(&ShutdownCriticalSection);
+ if (!NT_SUCCESS(Status)) {
+ Error = RtlNtStatusToDosError(Status);
+ }
+ }
+
+ //
+ // If DoShutdown, update the last gina ret so that
+ // the shutdown code will know what to do:
+ //
+
+ if ( DoShutdown )
+ {
+ GlobalWinMainData->LastGinaRet = GinaCode;
+
+ ShutdownHasBegun = TRUE;
+ }
+
+
+
+ //
+ // Tell the caller if he should shut down.
+ //
+
+ return DoShutdown;
+
+}
+
+
+
+BOOL WINAPI
+ShutdownApiDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+/*++
+
+Routine Description:
+
+ Processes messages for the shutdown dialog
+
+ Dialog returns ERROR_SUCCESS if shutdown should proceed,
+ ERROR_OPERATION_ABORTED if shutdown should be cancelled.
+
+--*/
+{
+ HMENU hMenu;
+
+ switch (message) {
+
+ case WM_INITDIALOG:
+
+ //
+ // Add the caller's id to the main message text
+ //
+
+ InsertClientId(hDlg, IDD_SYSTEM_MESSAGE, UserName, UserDomain);
+
+ //
+ // Setup the client's message
+ //
+
+ SetDlgItemText(hDlg, IDD_MESSAGE, ShutdownMessage);
+
+ //
+ // Remove the close item from the system menu
+ //
+
+ hMenu = GetSystemMenu(hDlg, FALSE);
+ DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
+
+ //
+ // Position ourselves
+ //
+
+ if ( ShutdownGetPlacement )
+ {
+ SetWindowPlacement( hDlg, &ShutdownWindowPlacement );
+ }
+ else
+ {
+ CentreWindow(hDlg);
+ }
+
+ SetWindowPos( hDlg, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
+
+
+ //
+ // Start the timer
+ //
+
+ SetTimer(hDlg, 0, 1000, NULL); // 1 second timer
+
+ //
+ // Check if it's over before we've even started
+ //
+
+ if (UpdateTimeToShutdown(hDlg)) {
+
+ // It's already time to shutdown
+ EndDialog(hDlg, SHUTDOWN_SUCCESS);
+ }
+
+ //
+ // Let everyone know what state we're in
+ //
+
+ GlobalWinMainData->PreviousWinlogonState = GlobalWinMainData->WinlogonState;
+ GlobalWinMainData->WinlogonState = Winsta_InShutdownDlg;
+
+// GlobalWinMainData->ShutdownStarted = TRUE;
+
+ return(TRUE);
+
+
+ case WM_TIMER:
+
+ //
+ // Check for abort flag
+ //
+
+ if (AbortShutdown) {
+ if (GlobalWinMainData->WinlogonState == Winsta_InShutdownDlg) {
+ GlobalWinMainData->WinlogonState = GlobalWinMainData->PreviousWinlogonState;
+ }
+// GlobalWinMainData->ShutdownStarted = FALSE;
+ EndDialog(hDlg, SHUTDOWN_CANCELLED);
+ return(TRUE);
+ }
+
+ if ( GlobalWinMainData->WindowStation.ActiveDesktop != ShutdownDesktop )
+ {
+ GetWindowPlacement( hDlg, &ShutdownWindowPlacement );
+ EndDialog( hDlg, SHUTDOWN_DESKTOP_SWITCH );
+ return( TRUE );
+ }
+
+ //
+ // Update the time delay and check if our time's up
+ //
+
+ if (!UpdateTimeToShutdown(hDlg)) {
+
+ //
+ // Keep waiting
+ //
+
+ return(TRUE);
+ }
+
+ //
+ // Shutdown time has arrived. Drop through...
+ //
+
+ case WLX_WM_SAS:
+
+
+ DebugLog((DEB_TRACE, "Sas message received? wParam = %d\n", wParam ));
+ if ((wParam == WLX_SAS_TYPE_SCRNSVR_TIMEOUT) &&
+ (message == WLX_WM_SAS)) {
+
+ //
+ // Don't end the dialog if it's just a screen saver timeout
+ //
+
+ return(TRUE);
+
+ } else if ((wParam == WLX_SAS_TYPE_CTRL_ALT_DEL) &&
+ (message == WLX_WM_SAS)) {
+
+ //
+ // Also don't end the dialog if it's a Ctrl-Alt-Del
+ //
+
+ Sleep (1000);
+ return(TRUE);
+
+ } else {
+
+ //
+ // If the user logs off, preempt the timeout, restore the state
+ //
+
+ if (GlobalWinMainData->WinlogonState == Winsta_InShutdownDlg) {
+ GlobalWinMainData->WinlogonState = GlobalWinMainData->PreviousWinlogonState;
+ }
+
+ EndDialog(hDlg, SHUTDOWN_SUCCESS);
+
+ return(TRUE);
+
+ }
+
+ }
+
+ // We didn't process this message
+ return FALSE;
+
+ UNREFERENCED_PARAMETER(lParam);
+}
+
+
+
+
+BOOL
+UpdateTimeToShutdown(
+ HWND hDlg
+ )
+/*++
+
+Routine Description:
+
+ Updates the display of the time to system shutdown.
+
+Returns:
+
+ TRUE if shutdown time has arrived, otherwise FALSE
+
+--*/
+{
+ NTSTATUS Status;
+ BOOLEAN Success;
+ LARGE_INTEGER TimeNow;
+ ULONG ElapsedSecondsNow;
+ ULONG ElapsedSecondsAtShutdown;
+ ULONG SecondsRemaining;
+ ULONG DaysRemaining;
+ ULONG HoursRemaining;
+ ULONG MinutesRemaining;
+ TCHAR Message[40];
+
+ //
+ // Set the shutdown time
+ //
+
+ Status = NtQuerySystemTime(&TimeNow);
+ ASSERT(NT_SUCCESS(Status));
+
+ if (TimeNow.QuadPart >= ShutdownTime.QuadPart)
+ {
+ return(TRUE);
+ }
+
+ Success = RtlTimeToSecondsSince1980(&TimeNow, &ElapsedSecondsNow);
+ ASSERT(Success);
+
+ Success = RtlTimeToSecondsSince1980(&ShutdownTime, &ElapsedSecondsAtShutdown);
+ ASSERT(Success);
+
+ SecondsRemaining = ElapsedSecondsAtShutdown - ElapsedSecondsNow;
+
+ //
+ // Convert the seconds remaining to a string
+ //
+
+ MinutesRemaining = SecondsRemaining / 60;
+ HoursRemaining = MinutesRemaining / 60;
+ DaysRemaining = HoursRemaining / 24;
+
+ SecondsRemaining = SecondsRemaining % 60;
+ MinutesRemaining = MinutesRemaining % 60;
+ HoursRemaining = HoursRemaining % 24;
+
+ if (DaysRemaining > 0) {
+ wsprintf(Message, TEXT("%d days"), DaysRemaining);
+ } else {
+ wsprintf(Message, TEXT("%02d:%02d:%02d"), HoursRemaining, MinutesRemaining, SecondsRemaining);
+ }
+
+ SetDlgItemText(hDlg, IDD_TIMER, Message);
+
+ return(FALSE);
+}
+
+
+
+ULONG
+BaseAbortSystemShutdown(
+ IN PREGISTRY_SERVER_NAME ServerName
+ )
+/*++
+
+Routine Description:
+
+ Aborts a pending shutdown of this machine.
+
+Arguments:
+
+ ServerName - Name of machine this server code is running on. (Ignored)
+
+Return Value:
+
+ Returns ERROR_SUCCESS (0) for success; error-code for failure.
+
+--*/
+
+{
+ NTSTATUS Status;
+ DWORD Error;
+
+ //
+ // Check the caller has the appropriate privilege
+ //
+
+ Error = TestClientPrivilege();
+ if (Error != ERROR_SUCCESS) {
+ return(Error);
+ }
+
+ //
+ // Enter the critical section so we can look at our globals
+ //
+
+ Status = RtlEnterCriticalSection(&ShutdownCriticalSection);
+ if (!NT_SUCCESS(Status)) {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+
+ //
+ // If a shutdown is in progress, set the abort flag
+ //
+
+ if (ShutdownInProgress) {
+ AbortShutdown = TRUE;
+ Error = ERROR_SUCCESS;
+ } else
+ {
+ if ( ShutdownHasBegun )
+ {
+ Error = ERROR_SHUTDOWN_IN_PROGRESS;
+ }
+ else
+ {
+ Error = ERROR_NO_SHUTDOWN_IN_PROGRESS;
+ }
+ }
+
+ //
+ // Leave the critical section
+ //
+
+ Status = RtlLeaveCriticalSection(&ShutdownCriticalSection);
+ if (Error == ERROR_SUCCESS) {
+ if (!NT_SUCCESS(Status)) {
+ Error = RtlNtStatusToDosError(Status);
+ }
+ } else {
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ return(Error);
+
+ UNREFERENCED_PARAMETER(ServerName);
+}
+
+
+
+DWORD
+TestClientPrivilege(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Checks if the client has the privilege to perform the requested shutdown.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ ERROR_SUCCESS if the client has the appropriate privilege.
+
+ ERROR_ACCESS_DENIED - client does not have the required privilege
+
+--*/
+{
+ NTSTATUS Status, IgnoreStatus;
+ BOOL LocalConnection;
+ LUID PrivilegeRequired;
+ PRIVILEGE_SET PrivilegeSet;
+ BOOLEAN Privileged;
+ USER_SESSION_KEY SessionKey;
+ HANDLE Token;
+
+ UNICODE_STRING SubSystemName; // LATER this should be global
+ RtlInitUnicodeString(&SubSystemName, L"Win32 Registry/SystemShutdown module");
+
+ //
+ // Find out if this is a local connection
+ //
+
+ Status = RtlGetUserSessionKeyServer(NULL, &SessionKey);
+ if (NT_SUCCESS(Status)) {
+
+ LocalConnection = (Status == STATUS_LOCAL_USER_SESSION_KEY);
+
+ if (LocalConnection) {
+ PrivilegeRequired = RtlConvertLongToLuid(SE_SHUTDOWN_PRIVILEGE);
+ } else {
+ PrivilegeRequired = RtlConvertLongToLuid(SE_REMOTE_SHUTDOWN_PRIVILEGE);
+ }
+
+
+ //
+ // See if the client has the required privilege
+ //
+
+ Status = I_RpcMapWin32Status(RpcImpersonateClient( NULL ));
+ if (NT_SUCCESS(Status)) {
+
+ PrivilegeSet.PrivilegeCount = 1;
+ PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
+ PrivilegeSet.Privilege[0].Luid = PrivilegeRequired;
+ PrivilegeSet.Privilege[0].Attributes = 0;
+
+ Status = NtOpenThreadToken( NtCurrentThread(),
+ TOKEN_QUERY,
+ TRUE,
+ &Token);
+ if (NT_SUCCESS(Status)) {
+
+ Status = NtPrivilegeCheck(Token,
+ &PrivilegeSet,
+ &Privileged);
+
+ if (NT_SUCCESS(Status) || (Status == STATUS_PRIVILEGE_NOT_HELD)) {
+
+ Status = NtPrivilegeObjectAuditAlarm(
+ &SubSystemName,
+ NULL,
+ Token,
+ 0,
+ &PrivilegeSet,
+ Privileged);
+ }
+
+ IgnoreStatus = NtClose(Token);
+ ASSERT(NT_SUCCESS(IgnoreStatus));
+ }
+
+ }
+
+ IgnoreStatus = I_RpcMapWin32Status(RpcRevertToSelf());
+ ASSERT( NT_SUCCESS(IgnoreStatus) );
+ }
+
+
+ //
+ // Handle unexpected errors
+ //
+
+ if (!NT_SUCCESS(Status)) {
+ return(RtlNtStatusToDosError(Status));
+ }
+
+
+ //
+ // If they failed the privilege check, return an error
+ //
+
+ if (!Privileged) {
+ return(ERROR_ACCESS_DENIED);
+ }
+
+ //
+ // They passed muster
+ //
+
+ return(ERROR_SUCCESS);
+}
+
+
+
+
+DWORD
+GetClientId(
+ PTSTR *UserName,
+ PTSTR *UserDomain
+ )
+/*++
+
+Routine Description:
+
+ Gets the name and domain of the caller, allocates and returns pointers
+ to the information.
+
+ Note we have RPC impersonate the client to discover their ID.
+
+Arguments:
+
+ UserName - a pointer to a NULL terminated string containing the client's
+ user name is returned here.
+
+ DomainName - a pointer to a NULL terminated string containing the client's
+ domain name is returned here.
+
+ The caller should free UserName and DomainName by calling DeleteClientId
+
+Return Value:
+
+ ERROR_SUCCESS - UserName and UserDomain contain valid pointers
+
+ Other - UserName and UserDomain are invalid
+
+--*/
+{
+ HANDLE TokenHandle;
+ DWORD cbNeeded;
+ PTOKEN_USER pUserToken;
+ BOOL ReturnValue=FALSE;
+ DWORD cbDomain;
+ DWORD cbName;
+ SID_NAME_USE SidNameUse;
+ DWORD Error;
+ DWORD IgnoreError;
+
+ //
+ // Prepare for failure
+ //
+
+ *UserName = NULL;
+ *UserDomain = NULL;
+
+
+ Error = RpcImpersonateClient(NULL);
+ if (Error != ERROR_SUCCESS) {
+ return(Error);
+ }
+
+ if (OpenThreadToken(GetCurrentThread(),
+ TOKEN_QUERY,
+ FALSE,
+ &TokenHandle)) {
+ //
+ // Get the user Sid
+ //
+
+ if (!GetTokenInformation(TokenHandle, TokenUser, (PVOID)NULL, 0, &cbNeeded)) {
+
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+
+ pUserToken = (PTOKEN_USER)LocalAlloc(LPTR, cbNeeded);
+
+ if (pUserToken != NULL) {
+
+ if (GetTokenInformation(TokenHandle, TokenUser, pUserToken,
+ cbNeeded, &cbNeeded)) {
+
+ //
+ // Convert User Sid to name/domain
+ //
+
+ cbName = 0;
+ cbDomain = 0;
+
+ if (!LookupAccountSid(NULL,
+ pUserToken->User.Sid,
+ NULL, &cbName,
+ NULL, &cbDomain,
+ &SidNameUse)) {
+
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+
+ *UserDomain = (PTSTR)LocalAlloc(LPTR, cbDomain*sizeof(TCHAR));
+ *UserName = (PTSTR)LocalAlloc(LPTR, cbName*sizeof(TCHAR));
+
+ if ((*UserDomain != NULL) && (*UserName != NULL)) {
+
+ ReturnValue = LookupAccountSid(
+ NULL,
+ pUserToken->User.Sid,
+ *UserName, &cbName,
+ *UserDomain, &cbDomain,
+ &SidNameUse);
+ }
+ }
+
+ }
+ }
+
+ LocalFree(pUserToken);
+ }
+ }
+ }
+
+ CloseHandle(TokenHandle);
+ }
+
+
+ IgnoreError = RpcRevertToSelf();
+ ASSERT(IgnoreError == ERROR_SUCCESS);
+
+
+ //
+ // Clean up on failure
+ //
+
+ if (ReturnValue) {
+ Error = ERROR_SUCCESS;
+ } else {
+
+ Error = GetLastError();
+
+ DeleteClientId(*UserName, *UserDomain);
+
+ *UserName = NULL;
+ *UserDomain = NULL;
+ }
+
+
+ return(Error);
+}
+
+
+
+
+VOID
+DeleteClientId(
+ PTSTR UserName,
+ PTSTR UserDomain
+ )
+/*++
+
+Routine Description:
+
+ Frees the client id returned previously by GetClientId
+
+Arguments:
+
+ UserName - a pointer to the username returned by GetClientId.
+
+ DomainName - a pointer to the domain name eturned by GetClientId
+
+Return Value:
+
+ None
+
+--*/
+{
+ if (UserName != NULL) {
+ LocalFree(UserName);
+ }
+
+ if (UserDomain != NULL) {
+ LocalFree(UserDomain);
+ }
+
+}
+
+
+
+
+BOOL
+InsertClientId(
+ HWND hDlg,
+ int ControlId,
+ PTSTR UserName,
+ PTSTR UserDomain
+ )
+/*++
+
+Routine Description:
+
+ Takes the text from the specified dialog control, treats it as a printf
+ formatting string and inserts the user name and domain as the first 2
+ string identifiers (%s)
+
+Arguments:
+
+ UserName - a pointer to the username returned by GetClientId.
+
+ DomainName - a pointer to the domain name eturned by GetClientId
+
+Return Value:
+
+ TRUE on success, FALSE on failure
+
+--*/
+{
+ DWORD StringLength;
+ DWORD StringBytes;
+ PTSTR FormatBuffer;
+ PTSTR Buffer;
+
+ //
+ // Allocate space for the formatting string out of the control
+ //
+
+ StringLength = (DWORD)SendMessage(GetDlgItem(hDlg, ControlId), WM_GETTEXTLENGTH, 0, 0);
+ StringBytes = (StringLength + 1) * sizeof(TCHAR); // Allow for terminator
+
+ FormatBuffer = (PTSTR)LocalAlloc(LPTR, StringBytes);
+ if (FormatBuffer == NULL) {
+ return(FALSE);
+ }
+
+ //
+ // Read the format string into the buffer
+ //
+
+ GetDlgItemText(hDlg, ControlId, FormatBuffer, StringLength);
+
+ //
+ // Calculate the maximum size of the string we'll create
+ // i.e. Formatting string + username + userdomain
+ //
+
+ StringLength += lstrlen(UserName);
+ StringLength += lstrlen(UserDomain);
+
+ //
+ // Allocate space for formatted string
+ //
+
+ StringBytes = (StringLength + 1) * sizeof(TCHAR); // Allow for terminator
+
+ Buffer = (PTSTR)LocalAlloc(LPTR, StringBytes);
+ if (Buffer == NULL) {
+ LocalFree(FormatBuffer);
+ return(FALSE);
+ }
+
+ //
+ // Insert the user id into the format string
+ //
+
+ wsprintf(Buffer, FormatBuffer, UserDomain, UserName);
+ ASSERT((lstrlen(Buffer) * sizeof(TCHAR)) < StringBytes);
+
+ //
+ // Replace the control text with our formatted result
+ //
+
+ SetDlgItemText(hDlg, ControlId, Buffer);
+
+ //
+ // Tidy up
+ //
+
+ LocalFree(FormatBuffer);
+ LocalFree(Buffer);
+
+
+ return(TRUE);
+}