Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1395 lines
29 KiB

/*++
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);
}