remote shutdown API
remote shutdown API
2011年11月02日
#include "precomp.h"
#pragma hdrstop
#include "shutinit.h" #define RPC_NO_WINDOWS_H
#include // // // // // // //
// 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;
PSID NetworkSid ; //
// Data captured during initialization
// PTERMINAL pShutDownTerm;
PUNICODE_STRING ShutdownBuiltinName ;
PUNICODE_STRING ShutdownSystemName ;
HANDLE ShutdownNameWait ; //
// Private prototypes
// DWORD
InitializeShutdownData(
BOOLEAN NoClientName,
PUNICODE_STRING lpMessage,
DWORD dwTimeout,
BOOL bForceAppsClosed,
BOOL bRebootAfterShutdown
); ULONG
BaseInitiateShutdownEx(
PREGISTRY_SERVER_NAME ServerName,
PREG_UNICODE_STRING lpMessage OPTIONAL,
DWORD dwTimeout,
BOOLEAN bForceAppsClosed,
BOOLEAN bRebootAfterShutdown,
DWORD dwReason
); VOID
FreeShutdownData(
VOID
); INT_PTR 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
); //+----------------------------------------------- ----------------------------
//
// Function: ShutdownGetSystemName
//
// Synopsis: Loops getting the locallized name for system
// (NT_AUTHORITY\SYSTEM) from the LSA as soon as it initializes
//
// Arguments: [Ignored] --
// [Timeout] --
//
// History: 3-04-98 RichardW Created
//
// Notes:
//
//------------------------------------------------ ----------------------------
VOID
ShutdownGetSystemName(
PVOID Ignored,
BOOLEAN Timeout
)
{ NTSTATUS Status ; if ( ShutdownSystemName )
{
return ;
} while ( TRUE )
{
Status = LsaGetUserName( &ShutdownSystemName, &ShutdownBuiltinName ); if ( NT_SUCCESS( Status ) )
{
break;
} Sleep( 15 * 1000 ); } return ;
} BOOL
InitializeShutdownModule(
VOID
)
{
NTSTATUS Status;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY ; //
// Initialize global variables
// ShutdownInProgress = FALSE; //
// Initialize critical section to protect globals
// Status = RtlInitializeCriticalSection(&ShutdownCriticalSect ion); #if DBG
if (!NT_SUCCESS(Status)) {
DbgPrint("InitializeShutdownModule: Failed to initialize critical section\n");
}
#endif Status = RtlAllocateAndInitializeSid( &NtAuthority,
1, SECURITY_NETWORK_RID,
0, 0, 0, 0, 0, 0, 0,
&NetworkSid ); ShutdownNameWait = SetTimerQueueTimer(
NULL,
ShutdownGetSystemName,
NULL,
10 * 1000,
INFINITE,
FALSE ); return(NT_SUCCESS(Status));
} ULONG
StartSystemShutdown(
IN BOOLEAN NoClientName,
IN PUNICODE_STRING lpMessage OPTIONAL,
IN DWORD dwTimeout,
IN BOOLEAN bForceAppsClosed,
IN BOOLEAN bRebootAfterShutdown
)
{
NTSTATUS Status;
DWORD 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 ||
ShutdownHasBegun ) { Error = ERROR_SHUTDOWN_IN_PROGRESS; } else { //
// Set up our globals for the shutdown thread to use.
// Error = InitializeShutdownData(NoClientName,
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()
// pShutDownTerm->LogoffFlags = EWX_WINLOGON_API_SHUTDOWN | ExitWindowsFlags;
Result = InitiateLogoff( pShutDownTerm,
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); } ULONG
BaseInitiateShutdown(
IN PREGISTRY_SERVER_NAME ServerName,
IN PREG_UNICODE_STRING lpMessage OPTIONAL,
IN DWORD dwTimeout,
IN BOOLEAN bForceAppsClosed,
IN BOOLEAN bRebootAfterShutdown
)
{
//
// pass through to BaseInitiateShutdownEx, but pass a reason code of 0xFF (unknown)
// return BaseInitiateShutdownEx (ServerName,
lpMessage,
dwTimeout,
bForceAppsClosed,
bRebootAfterShutdown,
REASON_UNKNOWN);
} ULONG
BaseInitiateShutdownEx(
IN PREGISTRY_SERVER_NAME ServerName,
IN PREG_UNICODE_STRING lpMessage OPTIONAL,
IN DWORD dwTimeout,
IN BOOLEAN bForceAppsClosed,
IN BOOLEAN bRebootAfterShutdown,
IN DWORD dwReason
)
{
DWORD Error ;
ULONG rc ;
HKEY hKey ; Error = TestClientPrivilege();
if (Error != ERROR_SUCCESS) {
return(Error);
} //
// Write the reason code to the registry
// rc = RegCreateKeyExW (HKEY_LOCAL_MACHINE, REGSTR_PATH_RELIABILITY, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hKey, NULL); if (rc == ERROR_SUCCESS) {
RegSetValueExW (hKey, REGSTR_VAL_SHUTDOWNREASON, 0, REG_DWORD, (UCHAR *)(&dwReason), sizeof(DWORD));
} RegCloseKey (hKey); ExitWindowsFlags = 0 ; return StartSystemShutdown( FALSE,
(PUNICODE_STRING)lpMessage,
dwTimeout,
bForceAppsClosed,
bRebootAfterShutdown ); UNREFERENCED_PARAMETER(ServerName);
} NTSTATUS
LocalInitiateSystemShutdown(
PUNICODE_STRING Message,
ULONG Timeout,
BOOLEAN bForceAppsClosed,
BOOLEAN bRebootAfterShutdown
)
{
LUID PrivilegeRequired;
PRIVILEGE_SET PrivilegeSet;
UNICODE_STRING SubSystemName; // LATER this should be global
HANDLE Token ;
NTSTATUS Status ;
PUNICODE_STRING Name ;
PUNICODE_STRING Domain ; RtlInitUnicodeString(&SubSystemName, L"Win32 SystemShutdown module"); Status = NtOpenProcessToken( NtCurrentProcess(),
MAXIMUM_ALLOWED,
&Token ); if ( !NT_SUCCESS( Status ) )
{
return Status ;
} PrivilegeRequired = RtlConvertLongToLuid( SE_SHUTDOWN_PRIVILEGE ); PrivilegeSet.PrivilegeCount = 1;
PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
PrivilegeSet.Privilege[0].Luid = PrivilegeRequired;
PrivilegeSet.Privilege[0].Attributes = 0; Status = NtPrivilegeObjectAuditAlarm(
&SubSystemName,
NULL,
Token,
0,
&PrivilegeSet,
TRUE ); NtClose( Token ); //
// Get our name. Note: we will leak this memory, but
// we're shutting down, so who cares?
// if ( ShutdownSystemName )
{
Name = ShutdownSystemName;
Domain = ShutdownBuiltinName ;
Status = STATUS_SUCCESS ; }
else
{
Status = LsaGetUserName(
&Name, &Domain ); } if ( NT_SUCCESS( Status ) )
{
UserName = LocalAlloc( LMEM_FIXED, Name->Length + 2 ); if ( UserName )
{
CopyMemory( UserName, Name->Buffer, Name->Length );
UserName[ Name->Length / 2 ] = L'\0';
} UserDomain = LocalAlloc( LMEM_FIXED, Domain->Length + 2 ); if ( UserDomain )
{
CopyMemory( UserDomain, Domain->Buffer, Domain->Length ); UserDomain[ Domain->Length / 2 ]= L'\0';
}
}
else
{
UserName = AllocAndDuplicateString( L"" );
UserDomain = AllocAndDuplicateString( L"" );
} ExitWindowsFlags = EWX_SYSTEM_CALLER ; SystemProcessShutdown = TRUE ; return StartSystemShutdown(
TRUE,
Message,
Timeout,
bForceAppsClosed,
bRebootAfterShutdown ); } DWORD
InitializeShutdownData(
BOOLEAN NoClientName,
PUNICODE_STRING lpMessage,
DWORD dwTimeout,
BOOL bForceAppsClosed,
BOOL bRebootAfterShutdown
)
{
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.
// if ( !NoClientName )
{
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
)
{
if (ShutdownMessage != NULL) {
LocalFree(ShutdownMessage);
ShutdownMessage = NULL;
} DeleteClientId(UserName, UserDomain);
UserName = NULL;
UserDomain = NULL;
} BOOLEAN
ShutdownThread(
PULONG Flags
)
{
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 ); pShutDownTerm->LastGinaRet = GinaCode; ShutdownHasBegun = TRUE; if ( pShutDownTerm->UserLoggedOn )
{
//
// If a user is logged on, do the logoff first. The correct bits are
// already set in the EWX_WINLOGON_OLD_XXX bits, so the correct behavior
// will be preserved. If no one is logged on, we need the EWX_SHUTDOWN flag
// to go all the way through.
// *Flags &= ~(EWX_SHUTDOWN | EWX_REBOOT | EWX_POWEROFF);
} return( TRUE ); } hdesk = GetActiveDesktop(pShutDownTerm,
&CloseDesktopHandle,
&Locked); while (hdesk != NULL)
{
DebugLog((DEB_TRACE, "Starting shutdown dialog on desktop %x\n", hdesk)); if (Locked)
{
UnlockWindowStation(pShutDownTerm->pWinStaWinlogon-> hwinsta);
} Success = SetThreadDesktop(hdesk);
if (!Success)
{
DebugLog((DEB_TRACE, "Unable to set desktop, %d\n", GetLastError()));
} if (Locked)
{
LockWindowStation(pShutDownTerm->pWinStaWinlogon->hw insta);
} ShutdownDesktop = pShutDownTerm->pWinStaWinlogon->ActiveDesktop; //
// Push the timeout past the shutdown delay, so that we can
// catch the messages we want, without stomping on the timeout
// structures.
//
Result = (DWORD)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(pShutDownTerm,
&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 )
{
pShutDownTerm->LastGinaRet = GinaCode; ShutdownHasBegun = TRUE; if ( SystemProcessShutdown )
{
//
// This is the panic shutdown when a system process has terminated.
// Just shut down immediately.
// RevertToSelf(); Result = EnablePrivilege(SE_SHUTDOWN_PRIVILEGE, TRUE); NtShutdownSystem( ShutdownReboot ); //
// This shouldn't return. We should have enabled the privilege (we're a
// system thread in this case), and this should have rebooted the machine.
// if it didn't, then we press on to the rest of the shutdown path.
// }
} //
// Tell the caller if he should shut down.
// if ( DoShutdown )
{
if ( pShutDownTerm->UserLoggedOn )
{
//
// If a user is logged on, do the logoff first. The correct bits are
// already set in the EWX_WINLOGON_OLD_XXX bits, so the correct behavior
// will be preserved. If no one is logged on, we need the EWX_SHUTDOWN flag
// to go all the way through.
// *Flags &= ~(EWX_SHUTDOWN | EWX_REBOOT | EWX_POWEROFF);
}
} return (DoShutdown != 0); } INT_PTR WINAPI
ShutdownApiDlgProc(
HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
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
// pShutDownTerm->ShutdownStarted = TRUE; return(TRUE); case WM_TIMER: //
// Check for abort flag
// if (AbortShutdown) {
pShutDownTerm->ShutdownStarted = FALSE;
EndDialog(hDlg, SHUTDOWN_CANCELLED);
return(TRUE);
} if ( pShutDownTerm->pWinStaWinlogon->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
// EndDialog(hDlg, SHUTDOWN_SUCCESS); return(TRUE); } } // We didn't process this message
return FALSE; UNREFERENCED_PARAMETER(lParam);
} BOOL
UpdateTimeToShutdown(
HWND hDlg
)
{
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("d:d:d"), HoursRemaining, MinutesRemaining, SecondsRemaining);
} SetDlgItemText(hDlg, IDD_TIMER, Message); return(FALSE);
} ULONG
BaseAbortShutdown(
IN PREGISTRY_SERVER_NAME ServerName
)
{
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
)
{
NTSTATUS Status, IgnoreStatus;
BOOL LocalConnection;
LUID PrivilegeRequired;
PRIVILEGE_SET PrivilegeSet;
BOOLEAN Privileged;
HANDLE Token;
PTOKEN_GROUPS Groups ;
ULONG Size ;
ULONG i ;
RPC_STATUS RpcStatus ;
BOOL Network ; UNICODE_STRING SubSystemName; // LATER this should be global
RtlInitUnicodeString(&SubSystemName, L"Win32 Registry/SystemShutdown module"); RpcStatus = RpcImpersonateClient( NULL ); if ( RpcStatus != 0 )
{
return RpcStatus ;
} Status = NtOpenThreadToken( NtCurrentThread(),
TOKEN_QUERY,
TRUE,
&Token ); if ( !NT_SUCCESS( Status ) )
{
//
// Forget it.
// RevertToSelf(); return RtlNtStatusToDosError( Status );
} //
// Now, see if this guy has the NETWORK sid in the token:
// PrivilegeRequired = RtlConvertLongToLuid(SE_SHUTDOWN_PRIVILEGE); if ( CheckTokenMembership( Token, NetworkSid, &Network ) )
{
if ( Network )
{
PrivilegeRequired = RtlConvertLongToLuid(SE_REMOTE_SHUTDOWN_PRIVILEGE) ;
}
}
else
{
RevertToSelf(); return GetLastError();
} //
// See if the client has the required privilege
// PrivilegeSet.PrivilegeCount = 1;
PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
PrivilegeSet.Privilege[0].Luid = PrivilegeRequired;
PrivilegeSet.Privilege[0].Attributes = 0; Status = NtPrivilegeCheck(Token,
&PrivilegeSet,
&Privileged); if (NT_SUCCESS(Status) || (Status == STATUS_PRIVILEGE_NOT_HELD))
{ Status = NtPrivilegeObjectAuditAlarm(
&SubSystemName,
NULL,
Token,
0,
&PrivilegeSet,
Privileged);
} NtClose( Token ); RevertToSelf(); //
// 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
)
{
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
)
{
if (UserName != NULL) {
LocalFree(UserName);
} if (UserDomain != NULL) {
LocalFree(UserDomain);
} } BOOL
InsertClientId(
HWND hDlg,
int ControlId,
PTSTR UserName,
PTSTR UserDomain
)
{
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
// if ( UserName == NULL )
{
UserName = L"" ;
}
if ( UserDomain == NULL )
{
UserDomain = L"" ;
} 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);
}
猜你喜欢
转载自ioo226ux.iteye.com/blog/1359501
今日推荐
周排行