|
|
/***************************** Module Header ******************************\
* Module Name: csrstubs.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Routines to call CSR * * 02-27-95 JimA Created. * * Note: This file has been partitioned with #if defines so that the LPC * marshalling code can be inside 64bit code when running under wow64 (32bit on * 64bit NT). In wow64, the system DLLs for 32bit processes are 32bit. * * The marshalling code can only be depedent on functions in NTDLL. \**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "csrmsg.h"
#include "csrhlpr.h"
#include "strid.h"
#include <dbt.h>
#include <regstr.h>
#include <winsta.h> // for WinStationGetTermSrvCountersValue
#include <allproc.h> // for TS_COUNTER
#define ALIGN_DOWN(length, type) \
((ULONG)(length) & ~(sizeof(type) - 1))
#define ALIGN_UP(length, type) \
(ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))
CONST WCHAR gszReliabilityKey[] = L"\\Registry\\Machine\\" REGSTR_PATH_RELIABILITY; CONST WCHAR gszReliabilityPolicyKey[] = L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT\\Reliability";
#if defined(BUILD_CSRWOW64)
#undef RIPERR0
#undef RIPNTERR0
#undef RIPMSG0
#define RIPNTERR0(status, flags, szFmt) {if (NtCurrentTeb()) NtCurrentTeb()->LastErrorValue = RtlNtStatusToDosError(status);}
#define RIPERR0(idErr, flags, szFmt) {if (NtCurrentTeb()) NtCurrentTeb()->LastErrorValue = (idErr);}
#define RIPMSG0(flags, szFmt)
#endif
#define SET_LAST_ERROR_RETURNED() if (a->dwLastError) RIPERR0(a->dwLastError, RIP_VERBOSE, "")
#if !defined(BUILD_WOW6432)
NTSTATUS APIENTRY CallUserpExitWindowsEx( IN UINT uFlags, OUT PBOOL pfSuccess) {
USER_API_MSG m; PEXITWINDOWSEXMSG a = &m.u.ExitWindowsEx;
a->uFlags = uFlags; CsrClientCallServer( (PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX, UserpExitWindowsEx ), sizeof( *a ) );
if (NT_SUCCESS( m.ReturnValue ) || m.ReturnValue == STATUS_CANT_WAIT) { SET_LAST_ERROR_RETURNED(); *pfSuccess = a->fSuccess; } else { RIPNTERR0(m.ReturnValue, RIP_VERBOSE, ""); *pfSuccess = FALSE; }
return m.ReturnValue;
}
#endif
#if !defined(BUILD_CSRWOW64)
typedef struct _EXITWINDOWSDATA { UINT uFlags; } EXITWINDOWSDATA, *PEXITWINDOWSDATA;
__inline void GetShutdownType(LPWSTR pszBuff, int cch, DWORD dwFlags) { if ((dwFlags & (EWX_POWEROFF | EWX_WINLOGON_OLD_POWEROFF)) != 0) { LoadString(hmodUser, STR_SHUTDOWN_POWEROFF, pszBuff, cch); } else if ((dwFlags & (EWX_REBOOT | EWX_WINLOGON_OLD_REBOOT)) != 0) { LoadString(hmodUser, STR_SHUTDOWN_REBOOT, pszBuff, cch); } else if ((dwFlags & (EWX_SHUTDOWN | EWX_WINLOGON_OLD_SHUTDOWN)) != 0) { LoadString(hmodUser, STR_SHUTDOWN_SHUTDOWN, pszBuff, cch); } else { LoadString(hmodUser, STR_UNKNOWN, pszBuff, cch); } }
/***************************************************************************\
* CsrTestShutdownPrivilege * * Looks at the user token to determine if they have shutdown privilege * * Returns TRUE if the user has the privilege, otherwise FALSE * \***************************************************************************/ BOOL CsrTestShutdownPrivilege( HANDLE UserToken ) { NTSTATUS Status; LUID LuidPrivilege = RtlConvertLongToLuid(SE_SHUTDOWN_PRIVILEGE); LUID TokenPrivilege; ULONG BytesRequired; ULONG i; BOOL bHasPrivilege = FALSE; BOOL bNetWork = FALSE; PSID NetworkSid = NULL; PTOKEN_PRIVILEGES Privileges = NULL; SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
Status = RtlAllocateAndInitializeSid(&NtAuthority, 1, SECURITY_NETWORK_RID, 0, 0, 0, 0, 0, 0, 0, &NetworkSid );
if (!NT_SUCCESS(Status)) { goto Cleanup; }
// Ok for this call to fail, in that case we assume local shutdown.
if (CheckTokenMembership(UserToken, NetworkSid, &bNetWork)) { if (bNetWork) { LuidPrivilege = RtlConvertLongToLuid(SE_REMOTE_SHUTDOWN_PRIVILEGE); } }
Status = NtQueryInformationToken( UserToken, TokenPrivileges, NULL, 0, &BytesRequired );
if (Status != STATUS_BUFFER_TOO_SMALL) { goto Cleanup; }
Privileges = (PTOKEN_PRIVILEGES)UserLocalAlloc(HEAP_ZERO_MEMORY, BytesRequired); if (Privileges == NULL) { goto Cleanup; }
Status = NtQueryInformationToken( UserToken, TokenPrivileges, Privileges, BytesRequired, &BytesRequired );
if (!NT_SUCCESS(Status)) { goto Cleanup; }
for (i=0; i<Privileges->PrivilegeCount; i++) { TokenPrivilege = *((LUID UNALIGNED *) &Privileges->Privileges[i].Luid); if (RtlEqualLuid(&TokenPrivilege, &LuidPrivilege)) { bHasPrivilege = TRUE; break; } }
Cleanup: if (NetworkSid) { RtlFreeSid(NetworkSid); }
if (Privileges) { UserLocalFree(Privileges); } return bHasPrivilege; }
FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, RecordShutdownReason, PSHUTDOWN_REASON, psr) BOOL RecordShutdownReason( PSHUTDOWN_REASON psr) { PCSR_CAPTURE_HEADER CaptureBuffer = NULL; HANDLE hToken = NULL; DWORD dwEventID; DWORD dwTotalLen = 0; // length for the capture buffer.
DWORD dwCntPointers = 0; // number of message pointers for the capture buffer.
DWORD dwProcessNameLen = MAX_PATH + 1; DWORD dwShutdownTypeLen = SHUTDOWN_TYPE_LEN; BOOL bRet = FALSE; LPWSTR lpszBuf = NULL; USER_API_MSG m; NTSTATUS status; PRECORDSHUTDOWNREASONMSG a = &(m.u.RecordShutdownReason);
// Check privilege. We dont want a user without shutdown privilege to call this.
status = NtOpenThreadToken(NtCurrentThread(),TOKEN_QUERY, FALSE, &hToken); if (!NT_SUCCESS(status)) { status = NtOpenThreadToken(NtCurrentThread(),TOKEN_QUERY, TRUE, &hToken); if (!NT_SUCCESS(status)) { status = NtOpenProcessToken(NtCurrentProcess(),TOKEN_QUERY, &hToken); if (!NT_SUCCESS(status)) { RIPNTERR0(status, RIP_WARNING, "Cannot get token in RecordShutdownReason"); goto Cleanup; } } }
if (!CsrTestShutdownPrivilege(hToken)) { NtClose(hToken); RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied in RecordShutdownReason"); goto Cleanup; } NtClose(hToken);
// Validate the structure
if (psr == NULL || psr->cbSize != sizeof(SHUTDOWN_REASON)) { RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Bad psr %p in RecordShutdownReason", psr); goto Cleanup; }
dwCntPointers = 3; dwTotalLen = dwProcessNameLen * sizeof(WCHAR) + dwShutdownTypeLen * sizeof(WCHAR) + sizeof(SHUTDOWN_REASON);
// Initialize all lengthes to 0
a->dwProcessNameLen = a->dwShutdownTypeLen = a->dwCommentLen = 0;
// Add Comment if we have one.
if (psr->lpszComment && wcslen(psr->lpszComment)) { dwCntPointers++; a->dwCommentLen = wcslen(psr->lpszComment) + 1; dwTotalLen += a->dwCommentLen * sizeof(WCHAR); }
// Adjust for the possible round up.
dwTotalLen += dwCntPointers * (sizeof(PVOID) - 1);
CaptureBuffer = CsrAllocateCaptureBuffer(dwCntPointers, dwTotalLen); if (CaptureBuffer == NULL) { goto Cleanup; }
// lpszBuf is shared for both process name and shutdown type.
// Make sure the len is the maximum of all of them.
lpszBuf = (LPWSTR)UserLocalAlloc(0, (dwProcessNameLen >= dwShutdownTypeLen ? dwProcessNameLen : dwShutdownTypeLen) * sizeof(WCHAR)); if (!lpszBuf) { goto Cleanup; }
// Fill the process name
if (!GetCurrentProcessName(lpszBuf, dwProcessNameLen)) { RIPMSG0(RIP_WARNING, "Failed to GetCurrentProcessName in RecordShutdownReason"); goto Cleanup; } lpszBuf[MAX_PATH] = 0; a->dwProcessNameLen = wcslen(lpszBuf)+1; CsrAllocateMessagePointer(CaptureBuffer, ALIGN_UP(a->dwProcessNameLen * sizeof(WCHAR), PVOID), &a->pwchProcessName); wcscpy(a->pwchProcessName, lpszBuf);
// Fill the shutdown type.
GetShutdownType(lpszBuf, dwShutdownTypeLen, psr->uFlags); lpszBuf[SHUTDOWN_TYPE_LEN-1] = 0; a->dwShutdownTypeLen = wcslen(lpszBuf)+1; CsrAllocateMessagePointer(CaptureBuffer, ALIGN_UP(a->dwShutdownTypeLen * sizeof(WCHAR), PVOID), &a->pwchShutdownType); wcscpy(a->pwchShutdownType, lpszBuf);
// copy over the SHUTDOWN_REASON.
CsrAllocateMessagePointer(CaptureBuffer, ALIGN_UP(sizeof(SHUTDOWN_REASON), PVOID), &a->psr); memcpy(a->psr, psr, sizeof(SHUTDOWN_REASON));
if (psr->lpszComment && !wcslen(psr->lpszComment)) { a->psr->lpszComment = NULL; }
if (psr->lpszComment && wcslen(psr->lpszComment)){ CsrAllocateMessagePointer(CaptureBuffer, ALIGN_UP(a->dwCommentLen * sizeof(WCHAR), PVOID), &a->pwchComment); wcscpy(a->pwchComment, psr->lpszComment); }
switch (psr->dwEventType) { case SR_EVENT_EXITWINDOWS: if (psr->fShutdownCancelled) { dwEventID = WARNING_EW_SHUTDOWN_CANCELLED; } else { dwEventID = STATUS_SHUTDOWN_CLEAN; } break; case SR_EVENT_INITIATE_CLEAN: dwEventID = STATUS_SHUTDOWN_CLEAN; break; case SR_EVENT_INITIATE_CLEAN_ABORT: dwEventID = WARNING_ISSE_SHUTDOWN_CANCELLED; break; case SR_EVENT_DIRTY: dwEventID = WARNING_DIRTY_REBOOT; break; default: goto Cleanup; }
a->dwEventID = dwEventID; a->dwEventType = psr->dwEventType; a->fShutdownCancelled = psr->fShutdownCancelled;
status = CsrClientCallServer((PCSR_API_MSG)&m, CaptureBuffer, CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpRecordShutdownReason ), sizeof(*a) );
bRet = NT_SUCCESS(status);
Cleanup: if (CaptureBuffer) { CsrFreeCaptureBuffer(CaptureBuffer); }
if (lpszBuf) { UserLocalFree(lpszBuf); }
return bRet; }
UINT GetLoggedOnUserCount( VOID) { int iCount = 0; BOOLEAN bSuccess;
TS_COUNTER TSCountersDyn[2];
TSCountersDyn[0].counterHead.dwCounterID = TERMSRV_CURRENT_DISC_SESSIONS; TSCountersDyn[1].counterHead.dwCounterID = TERMSRV_CURRENT_ACTIVE_SESSIONS;
// access the termsrv counters to find out how many users are logged onto the system
bSuccess = WinStationGetTermSrvCountersValue(SERVERNAME_CURRENT, 2, TSCountersDyn);
if (bSuccess) { if (TSCountersDyn[0].counterHead.bResult) iCount += TSCountersDyn[0].dwValue;
if (TSCountersDyn[1].counterHead.bResult) iCount += TSCountersDyn[1].dwValue; }
return iCount; }
BOOL IsSeShutdownNameEnabled() { BOOL bRet = FALSE; // assume the privilege is not held
NTSTATUS Status; HANDLE hToken;
// try to get the thread token
Status = NtOpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken); if (!NT_SUCCESS(Status)) { // try the process token if we failed to get the thread token
Status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); }
if (NT_SUCCESS(Status)) { DWORD cbSize = 0; TOKEN_PRIVILEGES* ptp;
NtQueryInformationToken(hToken, TokenPrivileges, NULL, 0, &cbSize); if (cbSize) { ptp = (TOKEN_PRIVILEGES*)UserLocalAlloc(0, cbSize); } else { ptp = NULL; }
if (ptp) { Status = NtQueryInformationToken(hToken, TokenPrivileges, ptp, cbSize, &cbSize); if (NT_SUCCESS(Status)) { DWORD i; for (i = 0; i < ptp->PrivilegeCount; i++) { if (((ptp->Privileges[i].Luid.HighPart == 0) && (ptp->Privileges[i].Luid.LowPart == SE_SHUTDOWN_PRIVILEGE)) && (ptp->Privileges[i].Attributes & (SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED))) { // found the privilege and it is enabled
bRet = TRUE; break; } } }
UserLocalFree(ptp); }
NtClose(hToken); }
return bRet; }
BOOL NeedsDisplayWarning (UINT uNumUsers, UINT uExitWindowsFlags) {
// If EWX_SYSTEM_CALLER then there's nobody on this session.
// Add one from the number of users.
if ((uExitWindowsFlags & EWX_SYSTEM_CALLER) && (uNumUsers > 0)) { ++uNumUsers; }
// If number of users > 1 or EWX_WINLOGON_CALLER display warning.
return (uNumUsers > 1) || (uExitWindowsFlags & EWX_WINLOGON_CALLER); }
FUNCLOG1(LOG_GENERAL, BOOL, APIENTRY, DisplayExitWindowsWarnings, UINT, uExitWindowsFlags) BOOL APIENTRY DisplayExitWindowsWarnings(UINT uExitWindowsFlags) { BOOL bContinue = TRUE; BOOL fIsRemote = ISREMOTESESSION(); UINT uNumUsers = GetLoggedOnUserCount(); UINT uID = 0;
// it would be nice to check the HKCU\ControlPanel\Desktop\AutoEndTask value and not display any UI if it is set,
// but since we are called from services it is probably better to not go mucking about in the per-user hive
if (uExitWindowsFlags & (EWX_POWEROFF | EWX_WINLOGON_OLD_POWEROFF | EWX_SHUTDOWN | EWX_WINLOGON_OLD_SHUTDOWN)) { if (fIsRemote) { if (NeedsDisplayWarning(uNumUsers, uExitWindowsFlags)) { // Warn the user if remote shut down w/ active users
uID = IDS_SHUTDOWN_REMOTE_OTHERUSERS; } else { // Warn the user of remote shut down (cut our own legs off!)
uID = IDS_SHUTDOWN_REMOTE; } } else { if (NeedsDisplayWarning(uNumUsers, uExitWindowsFlags)) { // Warn the user if more than one user session active
uID = IDS_SHUTDOWN_OTHERUSERS; } } } else if (uExitWindowsFlags & (EWX_REBOOT | EWX_WINLOGON_OLD_REBOOT)) { // Warn the user if more than one user session active.
if (NeedsDisplayWarning(uNumUsers, uExitWindowsFlags)) { uID = IDS_RESTART_OTHERUSERS; } }
if (uID != 0) { TCHAR szTitle[MAX_PATH]; TCHAR szMessage[MAX_PATH]; DWORD dwTimeout = INFINITE; UNICODE_STRING UnicodeString; extern CONST WCHAR szWindowsKey[]; static CONST WCHAR szTimeout[] = L"ShutdownWarningDialogTimeout"; OBJECT_ATTRIBUTES OA; HANDLE hKey; DWORD cbSize; struct { KEY_VALUE_PARTIAL_INFORMATION KeyInfo; DWORD dwTimeout; } KeyTimeout;
RtlInitUnicodeString(&UnicodeString, szWindowsKey); InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
if (NT_SUCCESS(NtOpenKey(&hKey, KEY_READ, &OA))) { NTSTATUS rc;
RtlInitUnicodeString(&UnicodeString, szTimeout);
rc = NtQueryValueKey(hKey, &UnicodeString, KeyValuePartialInformation, &KeyTimeout, sizeof KeyTimeout, &cbSize); if (NT_SUCCESS(rc)) { dwTimeout = *((PDWORD)KeyTimeout.KeyInfo.Data); RIPMSGF1(RIP_VERBOSE, "ShutdownWarningTimeout: set by the reg: %d", dwTimeout); }
NtClose(hKey); }
LoadString(hmodUser, IDS_EXITWINDOWS_TITLE, szTitle, sizeof(szTitle)/sizeof(szTitle[0])); LoadString(hmodUser, uID, szMessage, sizeof(szMessage)/sizeof(szMessage[0]));
// We want to display the message box to be displayed to the user, and since this can be called from winlogon/services
// we need to pass the MB_SERVICE_NOTIFICATION flag.
if (MessageBoxTimeout(NULL, szMessage, szTitle, MB_ICONEXCLAMATION | MB_YESNO | MB_SERVICE_NOTIFICATION | MB_SYSTEMMODAL | MB_SETFOREGROUND, 0, dwTimeout) == IDNO) { bContinue = FALSE; } }
return bContinue; }
DWORD ExitWindowsThread(PVOID pvParam);
BOOL WINAPI ExitWindowsWorker( UINT uFlags, BOOL fSecondThread) { EXITWINDOWSDATA ewd; HANDLE hThread; DWORD dwThreadId; DWORD dwExitCode; DWORD idWait; MSG msg; BOOL fSuccess; NTSTATUS Status;
/*
* Force a connection so apps will have a windowstation * to log off of. */ if (PtiCurrent() == NULL) { return FALSE; }
/*
* Check for UI restrictions */ if (!NtUserCallOneParam((ULONG_PTR)uFlags, SFI_PREPAREFORLOGOFF)) { RIPMSG0(RIP_WARNING, "ExitWindows called by a restricted thread\n"); return FALSE; }
Status = CallUserpExitWindowsEx(uFlags, &fSuccess);
if (NT_SUCCESS( Status )) { return fSuccess; } else if (Status == STATUS_CANT_WAIT && !fSecondThread) { ewd.uFlags = uFlags; hThread = CreateThread(NULL, 0, ExitWindowsThread, &ewd, 0, &dwThreadId); if (hThread == NULL) { return FALSE; }
while (1) { idWait = MsgWaitForMultipleObjectsEx(1, &hThread, INFINITE, QS_ALLINPUT, 0);
/*
* If the thread was signaled, we're done. */ if (idWait == WAIT_OBJECT_0) { break; }
/*
* Process any waiting messages */ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { DispatchMessage(&msg); } } GetExitCodeThread(hThread, &dwExitCode); NtClose(hThread); if (dwExitCode == ERROR_SUCCESS) { return TRUE; } else { RIPERR0(dwExitCode, RIP_VERBOSE, ""); return FALSE; } } else { RIPNTERR0(Status, RIP_VERBOSE, ""); return FALSE; } }
DWORD ExitWindowsThread( PVOID pvParam) { PEXITWINDOWSDATA pewd = pvParam; DWORD dwExitCode;
if (ExitWindowsWorker(pewd->uFlags, TRUE)) { dwExitCode = 0; } else { dwExitCode = GetLastError(); }
ExitThread(dwExitCode); return 0; }
FUNCLOG2(LOG_GENERAL, BOOL, WINAPI, ExitWindowsEx, UINT, uFlags, DWORD, dwReasonCode) BOOL WINAPI ExitWindowsEx( UINT uFlags, DWORD dwReasonCode) { BOOL bSuccess; BOOL bShutdown = (uFlags & SHUTDOWN_FLAGS) != 0; SHUTDOWN_REASON sr;
/*
* Check to see if we should bring up UI warning that there are other * Terminal Server users connected to this machine. We only do this if the * caller has not specified the EWX_FORCE option. */ if (bShutdown && !(uFlags & EWX_FORCE)) { /*
* We don't want to display the warning dialog twice! (this function * can be called by an application and again by winlogon in response to * the first call) */ if (!gfLogonProcess || (uFlags & EWX_WINLOGON_INITIATED)) { /*
* Don't put up UI if termsrv is our caller. Termsrv uses this api to shutdown winlogon * on session 0 when a shutdown was initiated from a different session. */ if (!(uFlags & EWX_TERMSRV_INITIATED)) { /*
* There are a bunch of lame apps (including InstallShield v5.1) that call ExitWindowsEx and then when it fails * they go and enable the SE_SHUTDOWN_NAME privilege and then us call again. The problem is that we end up prompting the * user twice in these cases. So before we put up any UI we check for the SE_SHUTDOWN_NAME privilege. */ if (IsSeShutdownNameEnabled()) { if (!DisplayExitWindowsWarnings(uFlags & ~(EWX_WINLOGON_CALLER | EWX_SYSTEM_CALLER))) { /*
* We need to log a cancel event if SET is enabled. */ if (IsSETEnabled()) { SHUTDOWN_REASON sr; sr.cbSize = sizeof(SHUTDOWN_REASON); sr.uFlags = uFlags; sr.dwReasonCode = 0; sr.fShutdownCancelled = TRUE; sr.dwEventType = SR_EVENT_EXITWINDOWS; sr.lpszComment = NULL; RecordShutdownReason(&sr); }
/*
* We only want to return the real error code if our caller was winlogon. We lie * to everyone else and tell them that everything succeeded. If we return failure * when the user cancel's the operation, a some of apps just call ExitWindowsEx * again, causing another dialog. */ if (uFlags & EWX_WINLOGON_INITIATED) { SetLastError(ERROR_CANCELLED); return FALSE; } else { return TRUE; } } } } } }
sr.cbSize = sizeof(SHUTDOWN_REASON); sr.uFlags = uFlags; sr.dwReasonCode = dwReasonCode; sr.fShutdownCancelled = FALSE; sr.dwEventType = SR_EVENT_EXITWINDOWS; sr.lpszComment = NULL;
/*
* If this is winlogon initiating the shutdown, we need to log before * calling ExitWindowsWorker. Otherwise, if the user or an app cancels the * shutdown, the cancel event will be logged before the initial shutdown * event. */ if (gfLogonProcess && bShutdown && (uFlags & EWX_WINLOGON_INITIATED) != 0) { if (IsSETEnabled()) { RecordShutdownReason(&sr); } }
bSuccess = ExitWindowsWorker(uFlags, FALSE);
/*
* Log this shutdown if: * 1) We're not winlogon (if we are, we might have logged above). * 2) The shutdown (inititally, at least) succeeded. * 3) We're actually shutting down (i.e., not logging off). * 4) The registry key telling us to log is set. */ if (!gfLogonProcess && bSuccess && bShutdown && IsSETEnabled()) { RecordShutdownReason(&sr); }
return bSuccess; }
#endif
#if !defined(BUILD_WOW6432)
BOOL WINAPI EndTask( HWND hwnd, BOOL fShutdown, BOOL fForce) { USER_API_MSG m; PENDTASKMSG a = &m.u.EndTask;
UNREFERENCED_PARAMETER(fShutdown); a->hwnd = hwnd; a->fForce = fForce; CsrClientCallServer( (PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX, UserpEndTask ), sizeof( *a ) ); if (NT_SUCCESS( m.ReturnValue )) { SET_LAST_ERROR_RETURNED(); return a->fSuccess; } else { RIPNTERR0(m.ReturnValue, RIP_VERBOSE, ""); return FALSE; } }
VOID APIENTRY Logon( BOOL fLogon) { USER_API_MSG m; PLOGONMSG a = &m.u.Logon;
a->fLogon = fLogon; CsrClientCallServer( (PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX, UserpLogon ), sizeof(*a) ); }
NTSTATUS APIENTRY CallUserpRegisterLogonProcess( IN DWORD dwProcessId) {
USER_API_MSG m; PLOGONMSG a = &m.u.Logon; NTSTATUS Status;
m.u.IdLogon = dwProcessId; Status = CsrClientCallServer( (PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX, UserpRegisterLogonProcess), sizeof(*a));
return Status; }
#endif
#if !defined(BUILD_CSRWOW64)
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, RegisterLogonProcess, DWORD, dwProcessId, BOOL, fSecure) BOOL RegisterLogonProcess( DWORD dwProcessId, BOOL fSecure) { gfLogonProcess = (BOOL)NtUserCallTwoParam(dwProcessId, fSecure, SFI__REGISTERLOGONPROCESS);
/*
* Now, register the logon process into winsrv. */ if (gfLogonProcess) { CallUserpRegisterLogonProcess(dwProcessId); }
return gfLogonProcess; }
#endif
#if !defined(BUILD_WOW6432)
BOOL WINAPI RegisterServicesProcess( DWORD dwProcessId) { USER_API_MSG m; PREGISTERSERVICESPROCESSMSG a = &m.u.RegisterServicesProcess;
a->dwProcessId = dwProcessId; CsrClientCallServer( (PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX, UserpRegisterServicesProcess ), sizeof( *a ) ); if (NT_SUCCESS( m.ReturnValue )) { SET_LAST_ERROR_RETURNED(); return a->fSuccess; } else { RIPNTERR0(m.ReturnValue, RIP_VERBOSE, ""); return FALSE; } }
HDESK WINAPI GetThreadDesktop( DWORD dwThreadId) { USER_API_MSG m; PGETTHREADCONSOLEDESKTOPMSG a = &m.u.GetThreadConsoleDesktop;
a->dwThreadId = dwThreadId; CsrClientCallServer( (PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX, UserpGetThreadConsoleDesktop ), sizeof( *a ) ); if (NT_SUCCESS( m.ReturnValue )) { return NtUserGetThreadDesktop(dwThreadId, a->hdeskConsole); } else { RIPNTERR0(m.ReturnValue, RIP_VERBOSE, ""); return NULL; } }
/**************************************************************************\
* DeviceEventWorker * * This is a private (not publicly exported) interface that the user-mode * pnp manager calls when it needs to send a WM_DEVICECHANGE message to a * specific window handle. The user-mode pnp manager is a service within * services.exe and as such is not on the interactive window station and * active desktop, so it can't directly call SendMessage. For broadcasted * messages (messages that go to all top-level windows), the user-mode pnp * manager calls BroadcastSystemMessage directly. * * PaulaT 06/04/97 * \**************************************************************************/ ULONG WINAPI DeviceEventWorker( IN HWND hWnd, IN WPARAM wParam, IN LPARAM lParam, IN DWORD dwFlags, OUT PDWORD pdwResult) { USER_API_MSG m; PDEVICEEVENTMSG a = &m.u.DeviceEvent; PCSR_CAPTURE_HEADER CaptureBuffer = NULL; int cb = 0;
a->hWnd = hWnd; a->wParam = wParam; a->lParam = lParam; a->dwFlags = dwFlags; a->dwResult = 0;
//
// If lParam is specified, it must be marshalled (see the defines
// for this structure in dbt.h - the structure always starts with
// DEV_BROADCAST_HDR structure).
//
if (lParam) {
cb = ((PDEV_BROADCAST_HDR)lParam)->dbch_size;
CaptureBuffer = CsrAllocateCaptureBuffer(1, cb); if (CaptureBuffer == NULL) { return STATUS_NO_MEMORY; }
CsrCaptureMessageBuffer(CaptureBuffer, (PCHAR)lParam, cb, (PVOID *)&a->lParam);
//
// This ends up calling SrvDeviceEvent routine in the server.
//
CsrClientCallServer((PCSR_API_MSG)&m, CaptureBuffer, CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpDeviceEvent), sizeof(*a));
CsrFreeCaptureBuffer(CaptureBuffer);
} else {
//
// This ends up calling SrvDeviceEvent routine in the server.
//
CsrClientCallServer((PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpDeviceEvent), sizeof(*a)); }
if (NT_SUCCESS(m.ReturnValue)) { *pdwResult = (DWORD)a->dwResult; } else { RIPMSG0(RIP_WARNING, "DeviceEventWorker failed."); }
return m.ReturnValue; }
#if DBG
VOID APIENTRY CsrWin32HeapFail( IN DWORD dwFlags, IN BOOL bFail) { USER_API_MSG m; PWIN32HEAPFAILMSG a = &m.u.Win32HeapFail;
a->dwFlags = dwFlags; a->bFail = bFail;
CsrClientCallServer((PCSR_API_MSG)&m, NULL, CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpWin32HeapFail), sizeof(*a));
if (!NT_SUCCESS(m.ReturnValue)) { RIPNTERR0(m.ReturnValue, RIP_VERBOSE, "UserpWin32HeapFail failed"); } }
UINT APIENTRY CsrWin32HeapStat( PDBGHEAPSTAT phs, DWORD dwLen) { USER_API_MSG m; PWIN32HEAPSTATMSG a = &m.u.Win32HeapStat; PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
a->dwLen = dwLen;
CaptureBuffer = CsrAllocateCaptureBuffer(1, dwLen); if (CaptureBuffer == NULL) { return 0; }
CsrCaptureMessageBuffer(CaptureBuffer, (PCHAR)phs, dwLen, (PVOID *)&a->phs);
CsrClientCallServer((PCSR_API_MSG)&m, CaptureBuffer, CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX, UserpWin32HeapStat), sizeof(*a));
if (!NT_SUCCESS(m.ReturnValue)) { RIPNTERR0(m.ReturnValue, RIP_VERBOSE, "UserpWin32HeapStat failed"); a->dwMaxTag = 0; goto ErrExit; } RtlMoveMemory(phs, a->phs, dwLen);
ErrExit: CsrFreeCaptureBuffer(CaptureBuffer);
return a->dwMaxTag; }
#endif // DBG
#endif
#if !defined(BUILD_CSRWOW64)
/******************************************************************************\
* CsrBroadcastSystemMessageExW * * Routine Description: * * This function is a private API used by the csrss server * * This function converts the csrss server thread into a GUI thread, then * performs a BroadcastSystemMessageExW(), and finally restore the thread's * desktop. * * Arguments: * * dwFlags - Broadcast System message flags * * lpdwRecipients - Intended recipients of the message * * uiMessage - Message type * * wParam - first message parameter * * lParam - second message parameter * * pBSMInfo - BroadcastSystemMessage information * * Return Value: * * Appropriate NTSTATUS code * \******************************************************************************/ FUNCLOG6(LOG_GENERAL, NTSTATUS, APIENTRY, CsrBroadcastSystemMessageExW, DWORD, dwFlags, LPDWORD, lpdwRecipients, UINT, uiMessage, WPARAM, wParam, LPARAM, lParam, PBSMINFO, pBSMInfo) NTSTATUS APIENTRY CsrBroadcastSystemMessageExW( DWORD dwFlags, LPDWORD lpdwRecipients, UINT uiMessage, WPARAM wParam, LPARAM lParam, PBSMINFO pBSMInfo ) { USERTHREAD_USEDESKTOPINFO utudi; long result; NTSTATUS Status;
/*
* Caller must be from the csrss server */ if ( !gfServerProcess ) { return( STATUS_ACCESS_DENIED ); }
/*
* Since this thread is a csrss thread, the thread is not a * GUI thread and does not have a desktop associated with it. * Must set the thread's desktop to the active desktop in * order to call BroadcastSystemMessageExW */
utudi.hThread = NULL; utudi.drdRestore.pdeskRestore = NULL;
Status = NtUserSetInformationThread( NtCurrentThread(), UserThreadUseActiveDesktop, &utudi, sizeof(utudi) );
if ( NT_SUCCESS( Status ) ) { result = BroadcastSystemMessageExW( dwFlags, lpdwRecipients, uiMessage, wParam, lParam, pBSMInfo );
/*
* Restore the previous desktop of the thread */ Status = NtUserSetInformationThread( NtCurrentThread(), UserThreadUseDesktop, &utudi, sizeof(utudi) );
if ( NT_SUCCESS( Status ) && ( result <= 0 ) ) { Status = STATUS_UNSUCCESSFUL; } }
return( Status ); }
#endif
|