Leaked source code of windows server 2003
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.

1119 lines
35 KiB

  1. /***************************** Module Header ******************************\
  2. * Module Name: csrstubs.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Routines to call CSR
  7. *
  8. * 02-27-95 JimA Created.
  9. *
  10. * Note: This file has been partitioned with #if defines so that the LPC
  11. * marshalling code can be inside 64bit code when running under wow64 (32bit on
  12. * 64bit NT). In wow64, the system DLLs for 32bit processes are 32bit.
  13. *
  14. * The marshalling code can only be depedent on functions in NTDLL.
  15. \**************************************************************************/
  16. #include "precomp.h"
  17. #pragma hdrstop
  18. #include "csrmsg.h"
  19. #include "csrhlpr.h"
  20. #include "strid.h"
  21. #include <dbt.h>
  22. #include <regstr.h>
  23. #include <winsta.h> // for WinStationGetTermSrvCountersValue
  24. #include <allproc.h> // for TS_COUNTER
  25. #define ALIGN_DOWN(length, type) \
  26. ((ULONG)(length) & ~(sizeof(type) - 1))
  27. #define ALIGN_UP(length, type) \
  28. (ALIGN_DOWN(((ULONG)(length) + sizeof(type) - 1), type))
  29. CONST WCHAR gszReliabilityKey[] = L"\\Registry\\Machine\\" REGSTR_PATH_RELIABILITY;
  30. CONST WCHAR gszReliabilityPolicyKey[] = L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows NT\\Reliability";
  31. #if defined(BUILD_CSRWOW64)
  32. #undef RIPERR0
  33. #undef RIPNTERR0
  34. #undef RIPMSG0
  35. #define RIPNTERR0(status, flags, szFmt) {if (NtCurrentTeb()) NtCurrentTeb()->LastErrorValue = RtlNtStatusToDosError(status);}
  36. #define RIPERR0(idErr, flags, szFmt) {if (NtCurrentTeb()) NtCurrentTeb()->LastErrorValue = (idErr);}
  37. #define RIPMSG0(flags, szFmt)
  38. #endif
  39. #define SET_LAST_ERROR_RETURNED() if (a->dwLastError) RIPERR0(a->dwLastError, RIP_VERBOSE, "")
  40. #if !defined(BUILD_WOW6432)
  41. NTSTATUS
  42. APIENTRY
  43. CallUserpExitWindowsEx(
  44. IN UINT uFlags,
  45. OUT PBOOL pfSuccess)
  46. {
  47. USER_API_MSG m;
  48. PEXITWINDOWSEXMSG a = &m.u.ExitWindowsEx;
  49. a->uFlags = uFlags;
  50. CsrClientCallServer( (PCSR_API_MSG)&m,
  51. NULL,
  52. CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX,
  53. UserpExitWindowsEx
  54. ),
  55. sizeof( *a )
  56. );
  57. if (NT_SUCCESS( m.ReturnValue ) || m.ReturnValue == STATUS_CANT_WAIT) {
  58. SET_LAST_ERROR_RETURNED();
  59. *pfSuccess = a->fSuccess;
  60. } else {
  61. RIPNTERR0(m.ReturnValue, RIP_VERBOSE, "");
  62. *pfSuccess = FALSE;
  63. }
  64. return m.ReturnValue;
  65. }
  66. #endif
  67. #if !defined(BUILD_CSRWOW64)
  68. typedef struct _EXITWINDOWSDATA {
  69. UINT uFlags;
  70. } EXITWINDOWSDATA, *PEXITWINDOWSDATA;
  71. __inline void GetShutdownType(LPWSTR pszBuff, int cch, DWORD dwFlags)
  72. {
  73. if ((dwFlags & (EWX_POWEROFF | EWX_WINLOGON_OLD_POWEROFF)) != 0) {
  74. LoadString(hmodUser, STR_SHUTDOWN_POWEROFF, pszBuff, cch);
  75. } else if ((dwFlags & (EWX_REBOOT | EWX_WINLOGON_OLD_REBOOT)) != 0) {
  76. LoadString(hmodUser, STR_SHUTDOWN_REBOOT, pszBuff, cch);
  77. } else if ((dwFlags & (EWX_SHUTDOWN | EWX_WINLOGON_OLD_SHUTDOWN)) != 0) {
  78. LoadString(hmodUser, STR_SHUTDOWN_SHUTDOWN, pszBuff, cch);
  79. } else {
  80. LoadString(hmodUser, STR_UNKNOWN, pszBuff, cch);
  81. }
  82. }
  83. /***************************************************************************\
  84. * CsrTestShutdownPrivilege
  85. *
  86. * Looks at the user token to determine if they have shutdown privilege
  87. *
  88. * Returns TRUE if the user has the privilege, otherwise FALSE
  89. *
  90. \***************************************************************************/
  91. BOOL
  92. CsrTestShutdownPrivilege(
  93. HANDLE UserToken
  94. )
  95. {
  96. NTSTATUS Status;
  97. LUID LuidPrivilege = RtlConvertLongToLuid(SE_SHUTDOWN_PRIVILEGE);
  98. LUID TokenPrivilege;
  99. ULONG BytesRequired;
  100. ULONG i;
  101. BOOL bHasPrivilege = FALSE;
  102. BOOL bNetWork = FALSE;
  103. PSID NetworkSid = NULL;
  104. PTOKEN_PRIVILEGES Privileges = NULL;
  105. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  106. Status = RtlAllocateAndInitializeSid(&NtAuthority,
  107. 1, SECURITY_NETWORK_RID,
  108. 0, 0, 0, 0, 0, 0, 0,
  109. &NetworkSid );
  110. if (!NT_SUCCESS(Status)) {
  111. goto Cleanup;
  112. }
  113. // Ok for this call to fail, in that case we assume local shutdown.
  114. if (CheckTokenMembership(UserToken, NetworkSid, &bNetWork)) {
  115. if (bNetWork) {
  116. LuidPrivilege = RtlConvertLongToLuid(SE_REMOTE_SHUTDOWN_PRIVILEGE);
  117. }
  118. }
  119. Status = NtQueryInformationToken(
  120. UserToken,
  121. TokenPrivileges,
  122. NULL,
  123. 0,
  124. &BytesRequired
  125. );
  126. if (Status != STATUS_BUFFER_TOO_SMALL) {
  127. goto Cleanup;
  128. }
  129. Privileges = (PTOKEN_PRIVILEGES)UserLocalAlloc(HEAP_ZERO_MEMORY,
  130. BytesRequired);
  131. if (Privileges == NULL) {
  132. goto Cleanup;
  133. }
  134. Status = NtQueryInformationToken(
  135. UserToken,
  136. TokenPrivileges,
  137. Privileges,
  138. BytesRequired,
  139. &BytesRequired
  140. );
  141. if (!NT_SUCCESS(Status)) {
  142. goto Cleanup;
  143. }
  144. for (i=0; i<Privileges->PrivilegeCount; i++) {
  145. TokenPrivilege = *((LUID UNALIGNED *) &Privileges->Privileges[i].Luid);
  146. if (RtlEqualLuid(&TokenPrivilege, &LuidPrivilege)) {
  147. bHasPrivilege = TRUE;
  148. break;
  149. }
  150. }
  151. Cleanup:
  152. if (NetworkSid) {
  153. RtlFreeSid(NetworkSid);
  154. }
  155. if (Privileges) {
  156. UserLocalFree(Privileges);
  157. }
  158. return bHasPrivilege;
  159. }
  160. FUNCLOG1(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, RecordShutdownReason, PSHUTDOWN_REASON, psr)
  161. BOOL RecordShutdownReason(
  162. PSHUTDOWN_REASON psr)
  163. {
  164. PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
  165. HANDLE hToken = NULL;
  166. DWORD dwEventID;
  167. DWORD dwTotalLen = 0; // length for the capture buffer.
  168. DWORD dwCntPointers = 0; // number of message pointers for the capture buffer.
  169. DWORD dwProcessNameLen = MAX_PATH + 1;
  170. DWORD dwShutdownTypeLen = SHUTDOWN_TYPE_LEN;
  171. BOOL bRet = FALSE;
  172. LPWSTR lpszBuf = NULL;
  173. USER_API_MSG m;
  174. NTSTATUS status;
  175. PRECORDSHUTDOWNREASONMSG a = &(m.u.RecordShutdownReason);
  176. // Check privilege. We dont want a user without shutdown privilege to call this.
  177. status = NtOpenThreadToken(NtCurrentThread(),TOKEN_QUERY, FALSE, &hToken);
  178. if (!NT_SUCCESS(status)) {
  179. status = NtOpenThreadToken(NtCurrentThread(),TOKEN_QUERY, TRUE, &hToken);
  180. if (!NT_SUCCESS(status)) {
  181. status = NtOpenProcessToken(NtCurrentProcess(),TOKEN_QUERY, &hToken);
  182. if (!NT_SUCCESS(status)) {
  183. RIPNTERR0(status, RIP_WARNING, "Cannot get token in RecordShutdownReason");
  184. goto Cleanup;
  185. }
  186. }
  187. }
  188. if (!CsrTestShutdownPrivilege(hToken)) {
  189. NtClose(hToken);
  190. RIPERR0(ERROR_ACCESS_DENIED, RIP_WARNING, "Access denied in RecordShutdownReason");
  191. goto Cleanup;
  192. }
  193. NtClose(hToken);
  194. // Validate the structure
  195. if (psr == NULL || psr->cbSize != sizeof(SHUTDOWN_REASON)) {
  196. RIPERR1(ERROR_INVALID_PARAMETER, RIP_WARNING, "Bad psr %p in RecordShutdownReason", psr);
  197. goto Cleanup;
  198. }
  199. dwCntPointers = 3;
  200. dwTotalLen = dwProcessNameLen * sizeof(WCHAR) + dwShutdownTypeLen * sizeof(WCHAR) + sizeof(SHUTDOWN_REASON);
  201. // Initialize all lengthes to 0
  202. a->dwProcessNameLen = a->dwShutdownTypeLen = a->dwCommentLen = 0;
  203. // Add Comment if we have one.
  204. if (psr->lpszComment && wcslen(psr->lpszComment)) {
  205. dwCntPointers++;
  206. a->dwCommentLen = wcslen(psr->lpszComment) + 1;
  207. dwTotalLen += a->dwCommentLen * sizeof(WCHAR);
  208. }
  209. // Adjust for the possible round up.
  210. dwTotalLen += dwCntPointers * (sizeof(PVOID) - 1);
  211. CaptureBuffer = CsrAllocateCaptureBuffer(dwCntPointers, dwTotalLen);
  212. if (CaptureBuffer == NULL) {
  213. goto Cleanup;
  214. }
  215. // lpszBuf is shared for both process name and shutdown type.
  216. // Make sure the len is the maximum of all of them.
  217. lpszBuf = (LPWSTR)UserLocalAlloc(0, (dwProcessNameLen >= dwShutdownTypeLen ?
  218. dwProcessNameLen : dwShutdownTypeLen) * sizeof(WCHAR));
  219. if (!lpszBuf) {
  220. goto Cleanup;
  221. }
  222. // Fill the process name
  223. if (!GetCurrentProcessName(lpszBuf, dwProcessNameLen)) {
  224. RIPMSG0(RIP_WARNING, "Failed to GetCurrentProcessName in RecordShutdownReason");
  225. goto Cleanup;
  226. }
  227. lpszBuf[MAX_PATH] = 0;
  228. a->dwProcessNameLen = wcslen(lpszBuf)+1;
  229. CsrAllocateMessagePointer(CaptureBuffer, ALIGN_UP(a->dwProcessNameLen * sizeof(WCHAR), PVOID), &a->pwchProcessName);
  230. wcscpy(a->pwchProcessName, lpszBuf);
  231. // Fill the shutdown type.
  232. GetShutdownType(lpszBuf, dwShutdownTypeLen, psr->uFlags);
  233. lpszBuf[SHUTDOWN_TYPE_LEN-1] = 0;
  234. a->dwShutdownTypeLen = wcslen(lpszBuf)+1;
  235. CsrAllocateMessagePointer(CaptureBuffer, ALIGN_UP(a->dwShutdownTypeLen * sizeof(WCHAR), PVOID), &a->pwchShutdownType);
  236. wcscpy(a->pwchShutdownType, lpszBuf);
  237. // copy over the SHUTDOWN_REASON.
  238. CsrAllocateMessagePointer(CaptureBuffer, ALIGN_UP(sizeof(SHUTDOWN_REASON), PVOID), &a->psr);
  239. memcpy(a->psr, psr, sizeof(SHUTDOWN_REASON));
  240. if (psr->lpszComment && !wcslen(psr->lpszComment)) {
  241. a->psr->lpszComment = NULL;
  242. }
  243. if (psr->lpszComment && wcslen(psr->lpszComment)){
  244. CsrAllocateMessagePointer(CaptureBuffer, ALIGN_UP(a->dwCommentLen * sizeof(WCHAR), PVOID), &a->pwchComment);
  245. wcscpy(a->pwchComment, psr->lpszComment);
  246. }
  247. switch (psr->dwEventType) {
  248. case SR_EVENT_EXITWINDOWS:
  249. if (psr->fShutdownCancelled) {
  250. dwEventID = WARNING_EW_SHUTDOWN_CANCELLED;
  251. } else {
  252. dwEventID = STATUS_SHUTDOWN_CLEAN;
  253. }
  254. break;
  255. case SR_EVENT_INITIATE_CLEAN:
  256. dwEventID = STATUS_SHUTDOWN_CLEAN;
  257. break;
  258. case SR_EVENT_INITIATE_CLEAN_ABORT:
  259. dwEventID = WARNING_ISSE_SHUTDOWN_CANCELLED;
  260. break;
  261. case SR_EVENT_DIRTY:
  262. dwEventID = WARNING_DIRTY_REBOOT;
  263. break;
  264. default:
  265. goto Cleanup;
  266. }
  267. a->dwEventID = dwEventID;
  268. a->dwEventType = psr->dwEventType;
  269. a->fShutdownCancelled = psr->fShutdownCancelled;
  270. status = CsrClientCallServer((PCSR_API_MSG)&m,
  271. CaptureBuffer,
  272. CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX,
  273. UserpRecordShutdownReason
  274. ),
  275. sizeof(*a)
  276. );
  277. bRet = NT_SUCCESS(status);
  278. Cleanup:
  279. if (CaptureBuffer) {
  280. CsrFreeCaptureBuffer(CaptureBuffer);
  281. }
  282. if (lpszBuf) {
  283. UserLocalFree(lpszBuf);
  284. }
  285. return bRet;
  286. }
  287. UINT GetLoggedOnUserCount(
  288. VOID)
  289. {
  290. int iCount = 0;
  291. BOOLEAN bSuccess;
  292. TS_COUNTER TSCountersDyn[2];
  293. TSCountersDyn[0].counterHead.dwCounterID = TERMSRV_CURRENT_DISC_SESSIONS;
  294. TSCountersDyn[1].counterHead.dwCounterID = TERMSRV_CURRENT_ACTIVE_SESSIONS;
  295. // access the termsrv counters to find out how many users are logged onto the system
  296. bSuccess = WinStationGetTermSrvCountersValue(SERVERNAME_CURRENT, 2, TSCountersDyn);
  297. if (bSuccess) {
  298. if (TSCountersDyn[0].counterHead.bResult)
  299. iCount += TSCountersDyn[0].dwValue;
  300. if (TSCountersDyn[1].counterHead.bResult)
  301. iCount += TSCountersDyn[1].dwValue;
  302. }
  303. return iCount;
  304. }
  305. BOOL IsSeShutdownNameEnabled()
  306. {
  307. BOOL bRet = FALSE; // assume the privilege is not held
  308. NTSTATUS Status;
  309. HANDLE hToken;
  310. // try to get the thread token
  311. Status = NtOpenThreadToken(GetCurrentThread(),
  312. TOKEN_QUERY,
  313. FALSE,
  314. &hToken);
  315. if (!NT_SUCCESS(Status)) {
  316. // try the process token if we failed to get the thread token
  317. Status = NtOpenProcessToken(GetCurrentProcess(),
  318. TOKEN_QUERY,
  319. &hToken);
  320. }
  321. if (NT_SUCCESS(Status)) {
  322. DWORD cbSize = 0;
  323. TOKEN_PRIVILEGES* ptp;
  324. NtQueryInformationToken(hToken,
  325. TokenPrivileges,
  326. NULL,
  327. 0,
  328. &cbSize);
  329. if (cbSize) {
  330. ptp = (TOKEN_PRIVILEGES*)UserLocalAlloc(0, cbSize);
  331. } else {
  332. ptp = NULL;
  333. }
  334. if (ptp) {
  335. Status = NtQueryInformationToken(hToken,
  336. TokenPrivileges,
  337. ptp,
  338. cbSize,
  339. &cbSize);
  340. if (NT_SUCCESS(Status)) {
  341. DWORD i;
  342. for (i = 0; i < ptp->PrivilegeCount; i++) {
  343. if (((ptp->Privileges[i].Luid.HighPart == 0) && (ptp->Privileges[i].Luid.LowPart == SE_SHUTDOWN_PRIVILEGE)) &&
  344. (ptp->Privileges[i].Attributes & (SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED))) {
  345. // found the privilege and it is enabled
  346. bRet = TRUE;
  347. break;
  348. }
  349. }
  350. }
  351. UserLocalFree(ptp);
  352. }
  353. NtClose(hToken);
  354. }
  355. return bRet;
  356. }
  357. BOOL NeedsDisplayWarning (UINT uNumUsers, UINT uExitWindowsFlags)
  358. {
  359. // If EWX_SYSTEM_CALLER then there's nobody on this session.
  360. // Add one from the number of users.
  361. if ((uExitWindowsFlags & EWX_SYSTEM_CALLER) && (uNumUsers > 0))
  362. {
  363. ++uNumUsers;
  364. }
  365. // If number of users > 1 or EWX_WINLOGON_CALLER display warning.
  366. return (uNumUsers > 1) || (uExitWindowsFlags & EWX_WINLOGON_CALLER);
  367. }
  368. FUNCLOG1(LOG_GENERAL, BOOL, APIENTRY, DisplayExitWindowsWarnings, UINT, uExitWindowsFlags)
  369. BOOL APIENTRY DisplayExitWindowsWarnings(UINT uExitWindowsFlags)
  370. {
  371. BOOL bContinue = TRUE;
  372. BOOL fIsRemote = ISREMOTESESSION();
  373. UINT uNumUsers = GetLoggedOnUserCount();
  374. UINT uID = 0;
  375. // it would be nice to check the HKCU\ControlPanel\Desktop\AutoEndTask value and not display any UI if it is set,
  376. // but since we are called from services it is probably better to not go mucking about in the per-user hive
  377. if (uExitWindowsFlags & (EWX_POWEROFF | EWX_WINLOGON_OLD_POWEROFF | EWX_SHUTDOWN | EWX_WINLOGON_OLD_SHUTDOWN)) {
  378. if (fIsRemote) {
  379. if (NeedsDisplayWarning(uNumUsers, uExitWindowsFlags)) {
  380. // Warn the user if remote shut down w/ active users
  381. uID = IDS_SHUTDOWN_REMOTE_OTHERUSERS;
  382. } else {
  383. // Warn the user of remote shut down (cut our own legs off!)
  384. uID = IDS_SHUTDOWN_REMOTE;
  385. }
  386. } else {
  387. if (NeedsDisplayWarning(uNumUsers, uExitWindowsFlags)) {
  388. // Warn the user if more than one user session active
  389. uID = IDS_SHUTDOWN_OTHERUSERS;
  390. }
  391. }
  392. } else if (uExitWindowsFlags & (EWX_REBOOT | EWX_WINLOGON_OLD_REBOOT)) {
  393. // Warn the user if more than one user session active.
  394. if (NeedsDisplayWarning(uNumUsers, uExitWindowsFlags)) {
  395. uID = IDS_RESTART_OTHERUSERS;
  396. }
  397. }
  398. if (uID != 0) {
  399. TCHAR szTitle[MAX_PATH];
  400. TCHAR szMessage[MAX_PATH];
  401. DWORD dwTimeout = INFINITE;
  402. UNICODE_STRING UnicodeString;
  403. extern CONST WCHAR szWindowsKey[];
  404. static CONST WCHAR szTimeout[] = L"ShutdownWarningDialogTimeout";
  405. OBJECT_ATTRIBUTES OA;
  406. HANDLE hKey;
  407. DWORD cbSize;
  408. struct {
  409. KEY_VALUE_PARTIAL_INFORMATION KeyInfo;
  410. DWORD dwTimeout;
  411. } KeyTimeout;
  412. RtlInitUnicodeString(&UnicodeString, szWindowsKey);
  413. InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL);
  414. if (NT_SUCCESS(NtOpenKey(&hKey, KEY_READ, &OA))) {
  415. NTSTATUS rc;
  416. RtlInitUnicodeString(&UnicodeString, szTimeout);
  417. rc = NtQueryValueKey(hKey,
  418. &UnicodeString,
  419. KeyValuePartialInformation,
  420. &KeyTimeout,
  421. sizeof KeyTimeout,
  422. &cbSize);
  423. if (NT_SUCCESS(rc)) {
  424. dwTimeout = *((PDWORD)KeyTimeout.KeyInfo.Data);
  425. RIPMSGF1(RIP_VERBOSE, "ShutdownWarningTimeout: set by the reg: %d", dwTimeout);
  426. }
  427. NtClose(hKey);
  428. }
  429. LoadString(hmodUser, IDS_EXITWINDOWS_TITLE, szTitle, sizeof(szTitle)/sizeof(szTitle[0]));
  430. LoadString(hmodUser, uID, szMessage, sizeof(szMessage)/sizeof(szMessage[0]));
  431. // We want to display the message box to be displayed to the user, and since this can be called from winlogon/services
  432. // we need to pass the MB_SERVICE_NOTIFICATION flag.
  433. if (MessageBoxTimeout(NULL, szMessage, szTitle,
  434. MB_ICONEXCLAMATION | MB_YESNO | MB_SERVICE_NOTIFICATION | MB_SYSTEMMODAL | MB_SETFOREGROUND,
  435. 0, dwTimeout) == IDNO) {
  436. bContinue = FALSE;
  437. }
  438. }
  439. return bContinue;
  440. }
  441. DWORD ExitWindowsThread(PVOID pvParam);
  442. BOOL WINAPI ExitWindowsWorker(
  443. UINT uFlags,
  444. BOOL fSecondThread)
  445. {
  446. EXITWINDOWSDATA ewd;
  447. HANDLE hThread;
  448. DWORD dwThreadId;
  449. DWORD dwExitCode;
  450. DWORD idWait;
  451. MSG msg;
  452. BOOL fSuccess;
  453. NTSTATUS Status;
  454. /*
  455. * Force a connection so apps will have a windowstation
  456. * to log off of.
  457. */
  458. if (PtiCurrent() == NULL) {
  459. return FALSE;
  460. }
  461. /*
  462. * Check for UI restrictions
  463. */
  464. if (!NtUserCallOneParam((ULONG_PTR)uFlags, SFI_PREPAREFORLOGOFF)) {
  465. RIPMSG0(RIP_WARNING, "ExitWindows called by a restricted thread\n");
  466. return FALSE;
  467. }
  468. Status = CallUserpExitWindowsEx(uFlags, &fSuccess);
  469. if (NT_SUCCESS( Status )) {
  470. return fSuccess;
  471. } else if (Status == STATUS_CANT_WAIT && !fSecondThread) {
  472. ewd.uFlags = uFlags;
  473. hThread = CreateThread(NULL, 0, ExitWindowsThread, &ewd,
  474. 0, &dwThreadId);
  475. if (hThread == NULL) {
  476. return FALSE;
  477. }
  478. while (1) {
  479. idWait = MsgWaitForMultipleObjectsEx(1, &hThread,
  480. INFINITE, QS_ALLINPUT, 0);
  481. /*
  482. * If the thread was signaled, we're done.
  483. */
  484. if (idWait == WAIT_OBJECT_0) {
  485. break;
  486. }
  487. /*
  488. * Process any waiting messages
  489. */
  490. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  491. DispatchMessage(&msg);
  492. }
  493. }
  494. GetExitCodeThread(hThread, &dwExitCode);
  495. NtClose(hThread);
  496. if (dwExitCode == ERROR_SUCCESS) {
  497. return TRUE;
  498. } else {
  499. RIPERR0(dwExitCode, RIP_VERBOSE, "");
  500. return FALSE;
  501. }
  502. } else {
  503. RIPNTERR0(Status, RIP_VERBOSE, "");
  504. return FALSE;
  505. }
  506. }
  507. DWORD ExitWindowsThread(
  508. PVOID pvParam)
  509. {
  510. PEXITWINDOWSDATA pewd = pvParam;
  511. DWORD dwExitCode;
  512. if (ExitWindowsWorker(pewd->uFlags, TRUE)) {
  513. dwExitCode = 0;
  514. } else {
  515. dwExitCode = GetLastError();
  516. }
  517. ExitThread(dwExitCode);
  518. return 0;
  519. }
  520. FUNCLOG2(LOG_GENERAL, BOOL, WINAPI, ExitWindowsEx, UINT, uFlags, DWORD, dwReasonCode)
  521. BOOL WINAPI ExitWindowsEx(
  522. UINT uFlags,
  523. DWORD dwReasonCode)
  524. {
  525. BOOL bSuccess;
  526. BOOL bShutdown = (uFlags & SHUTDOWN_FLAGS) != 0;
  527. SHUTDOWN_REASON sr;
  528. /*
  529. * Check to see if we should bring up UI warning that there are other
  530. * Terminal Server users connected to this machine. We only do this if the
  531. * caller has not specified the EWX_FORCE option.
  532. */
  533. if (bShutdown && !(uFlags & EWX_FORCE)) {
  534. /*
  535. * We don't want to display the warning dialog twice! (this function
  536. * can be called by an application and again by winlogon in response to
  537. * the first call)
  538. */
  539. if (!gfLogonProcess || (uFlags & EWX_WINLOGON_INITIATED)) {
  540. /*
  541. * Don't put up UI if termsrv is our caller. Termsrv uses this api to shutdown winlogon
  542. * on session 0 when a shutdown was initiated from a different session.
  543. */
  544. if (!(uFlags & EWX_TERMSRV_INITIATED)) {
  545. /*
  546. * There are a bunch of lame apps (including InstallShield v5.1) that call ExitWindowsEx and then when it fails
  547. * they go and enable the SE_SHUTDOWN_NAME privilege and then us call again. The problem is that we end up prompting the
  548. * user twice in these cases. So before we put up any UI we check for the SE_SHUTDOWN_NAME privilege.
  549. */
  550. if (IsSeShutdownNameEnabled()) {
  551. if (!DisplayExitWindowsWarnings(uFlags & ~(EWX_WINLOGON_CALLER | EWX_SYSTEM_CALLER))) {
  552. /*
  553. * We need to log a cancel event if SET is enabled.
  554. */
  555. if (IsSETEnabled()) {
  556. SHUTDOWN_REASON sr;
  557. sr.cbSize = sizeof(SHUTDOWN_REASON);
  558. sr.uFlags = uFlags;
  559. sr.dwReasonCode = 0;
  560. sr.fShutdownCancelled = TRUE;
  561. sr.dwEventType = SR_EVENT_EXITWINDOWS;
  562. sr.lpszComment = NULL;
  563. RecordShutdownReason(&sr);
  564. }
  565. /*
  566. * We only want to return the real error code if our caller was winlogon. We lie
  567. * to everyone else and tell them that everything succeeded. If we return failure
  568. * when the user cancel's the operation, a some of apps just call ExitWindowsEx
  569. * again, causing another dialog.
  570. */
  571. if (uFlags & EWX_WINLOGON_INITIATED) {
  572. SetLastError(ERROR_CANCELLED);
  573. return FALSE;
  574. } else {
  575. return TRUE;
  576. }
  577. }
  578. }
  579. }
  580. }
  581. }
  582. sr.cbSize = sizeof(SHUTDOWN_REASON);
  583. sr.uFlags = uFlags;
  584. sr.dwReasonCode = dwReasonCode;
  585. sr.fShutdownCancelled = FALSE;
  586. sr.dwEventType = SR_EVENT_EXITWINDOWS;
  587. sr.lpszComment = NULL;
  588. /*
  589. * If this is winlogon initiating the shutdown, we need to log before
  590. * calling ExitWindowsWorker. Otherwise, if the user or an app cancels the
  591. * shutdown, the cancel event will be logged before the initial shutdown
  592. * event.
  593. */
  594. if (gfLogonProcess && bShutdown && (uFlags & EWX_WINLOGON_INITIATED) != 0) {
  595. if (IsSETEnabled()) {
  596. RecordShutdownReason(&sr);
  597. }
  598. }
  599. bSuccess = ExitWindowsWorker(uFlags, FALSE);
  600. /*
  601. * Log this shutdown if:
  602. * 1) We're not winlogon (if we are, we might have logged above).
  603. * 2) The shutdown (inititally, at least) succeeded.
  604. * 3) We're actually shutting down (i.e., not logging off).
  605. * 4) The registry key telling us to log is set.
  606. */
  607. if (!gfLogonProcess && bSuccess && bShutdown && IsSETEnabled()) {
  608. RecordShutdownReason(&sr);
  609. }
  610. return bSuccess;
  611. }
  612. #endif
  613. #if !defined(BUILD_WOW6432)
  614. BOOL WINAPI EndTask(
  615. HWND hwnd,
  616. BOOL fShutdown,
  617. BOOL fForce)
  618. {
  619. USER_API_MSG m;
  620. PENDTASKMSG a = &m.u.EndTask;
  621. UNREFERENCED_PARAMETER(fShutdown);
  622. a->hwnd = hwnd;
  623. a->fForce = fForce;
  624. CsrClientCallServer( (PCSR_API_MSG)&m,
  625. NULL,
  626. CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX,
  627. UserpEndTask
  628. ),
  629. sizeof( *a )
  630. );
  631. if (NT_SUCCESS( m.ReturnValue )) {
  632. SET_LAST_ERROR_RETURNED();
  633. return a->fSuccess;
  634. } else {
  635. RIPNTERR0(m.ReturnValue, RIP_VERBOSE, "");
  636. return FALSE;
  637. }
  638. }
  639. VOID
  640. APIENTRY
  641. Logon(
  642. BOOL fLogon)
  643. {
  644. USER_API_MSG m;
  645. PLOGONMSG a = &m.u.Logon;
  646. a->fLogon = fLogon;
  647. CsrClientCallServer( (PCSR_API_MSG)&m,
  648. NULL,
  649. CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX,
  650. UserpLogon
  651. ),
  652. sizeof(*a)
  653. );
  654. }
  655. NTSTATUS
  656. APIENTRY
  657. CallUserpRegisterLogonProcess(
  658. IN DWORD dwProcessId)
  659. {
  660. USER_API_MSG m;
  661. PLOGONMSG a = &m.u.Logon;
  662. NTSTATUS Status;
  663. m.u.IdLogon = dwProcessId;
  664. Status = CsrClientCallServer( (PCSR_API_MSG)&m,
  665. NULL,
  666. CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX,
  667. UserpRegisterLogonProcess),
  668. sizeof(*a));
  669. return Status;
  670. }
  671. #endif
  672. #if !defined(BUILD_CSRWOW64)
  673. FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, RegisterLogonProcess, DWORD, dwProcessId, BOOL, fSecure)
  674. BOOL RegisterLogonProcess(
  675. DWORD dwProcessId,
  676. BOOL fSecure)
  677. {
  678. gfLogonProcess = (BOOL)NtUserCallTwoParam(dwProcessId, fSecure,
  679. SFI__REGISTERLOGONPROCESS);
  680. /*
  681. * Now, register the logon process into winsrv.
  682. */
  683. if (gfLogonProcess) {
  684. CallUserpRegisterLogonProcess(dwProcessId);
  685. }
  686. return gfLogonProcess;
  687. }
  688. #endif
  689. #if !defined(BUILD_WOW6432)
  690. BOOL
  691. WINAPI
  692. RegisterServicesProcess(
  693. DWORD dwProcessId)
  694. {
  695. USER_API_MSG m;
  696. PREGISTERSERVICESPROCESSMSG a = &m.u.RegisterServicesProcess;
  697. a->dwProcessId = dwProcessId;
  698. CsrClientCallServer( (PCSR_API_MSG)&m,
  699. NULL,
  700. CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX,
  701. UserpRegisterServicesProcess
  702. ),
  703. sizeof( *a )
  704. );
  705. if (NT_SUCCESS( m.ReturnValue )) {
  706. SET_LAST_ERROR_RETURNED();
  707. return a->fSuccess;
  708. } else {
  709. RIPNTERR0(m.ReturnValue, RIP_VERBOSE, "");
  710. return FALSE;
  711. }
  712. }
  713. HDESK WINAPI GetThreadDesktop(
  714. DWORD dwThreadId)
  715. {
  716. USER_API_MSG m;
  717. PGETTHREADCONSOLEDESKTOPMSG a = &m.u.GetThreadConsoleDesktop;
  718. a->dwThreadId = dwThreadId;
  719. CsrClientCallServer( (PCSR_API_MSG)&m,
  720. NULL,
  721. CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX,
  722. UserpGetThreadConsoleDesktop
  723. ),
  724. sizeof( *a )
  725. );
  726. if (NT_SUCCESS( m.ReturnValue )) {
  727. return NtUserGetThreadDesktop(dwThreadId, a->hdeskConsole);
  728. } else {
  729. RIPNTERR0(m.ReturnValue, RIP_VERBOSE, "");
  730. return NULL;
  731. }
  732. }
  733. /**************************************************************************\
  734. * DeviceEventWorker
  735. *
  736. * This is a private (not publicly exported) interface that the user-mode
  737. * pnp manager calls when it needs to send a WM_DEVICECHANGE message to a
  738. * specific window handle. The user-mode pnp manager is a service within
  739. * services.exe and as such is not on the interactive window station and
  740. * active desktop, so it can't directly call SendMessage. For broadcasted
  741. * messages (messages that go to all top-level windows), the user-mode pnp
  742. * manager calls BroadcastSystemMessage directly.
  743. *
  744. * PaulaT 06/04/97
  745. *
  746. \**************************************************************************/
  747. ULONG
  748. WINAPI
  749. DeviceEventWorker(
  750. IN HWND hWnd,
  751. IN WPARAM wParam,
  752. IN LPARAM lParam,
  753. IN DWORD dwFlags,
  754. OUT PDWORD pdwResult)
  755. {
  756. USER_API_MSG m;
  757. PDEVICEEVENTMSG a = &m.u.DeviceEvent;
  758. PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
  759. int cb = 0;
  760. a->hWnd = hWnd;
  761. a->wParam = wParam;
  762. a->lParam = lParam;
  763. a->dwFlags = dwFlags;
  764. a->dwResult = 0;
  765. //
  766. // If lParam is specified, it must be marshalled (see the defines
  767. // for this structure in dbt.h - the structure always starts with
  768. // DEV_BROADCAST_HDR structure).
  769. //
  770. if (lParam) {
  771. cb = ((PDEV_BROADCAST_HDR)lParam)->dbch_size;
  772. CaptureBuffer = CsrAllocateCaptureBuffer(1, cb);
  773. if (CaptureBuffer == NULL) {
  774. return STATUS_NO_MEMORY;
  775. }
  776. CsrCaptureMessageBuffer(CaptureBuffer,
  777. (PCHAR)lParam,
  778. cb,
  779. (PVOID *)&a->lParam);
  780. //
  781. // This ends up calling SrvDeviceEvent routine in the server.
  782. //
  783. CsrClientCallServer((PCSR_API_MSG)&m,
  784. CaptureBuffer,
  785. CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX,
  786. UserpDeviceEvent),
  787. sizeof(*a));
  788. CsrFreeCaptureBuffer(CaptureBuffer);
  789. } else {
  790. //
  791. // This ends up calling SrvDeviceEvent routine in the server.
  792. //
  793. CsrClientCallServer((PCSR_API_MSG)&m,
  794. NULL,
  795. CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX,
  796. UserpDeviceEvent),
  797. sizeof(*a));
  798. }
  799. if (NT_SUCCESS(m.ReturnValue)) {
  800. *pdwResult = (DWORD)a->dwResult;
  801. } else {
  802. RIPMSG0(RIP_WARNING, "DeviceEventWorker failed.");
  803. }
  804. return m.ReturnValue;
  805. }
  806. #if DBG
  807. VOID
  808. APIENTRY
  809. CsrWin32HeapFail(
  810. IN DWORD dwFlags,
  811. IN BOOL bFail)
  812. {
  813. USER_API_MSG m;
  814. PWIN32HEAPFAILMSG a = &m.u.Win32HeapFail;
  815. a->dwFlags = dwFlags;
  816. a->bFail = bFail;
  817. CsrClientCallServer((PCSR_API_MSG)&m,
  818. NULL,
  819. CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX,
  820. UserpWin32HeapFail),
  821. sizeof(*a));
  822. if (!NT_SUCCESS(m.ReturnValue)) {
  823. RIPNTERR0(m.ReturnValue, RIP_VERBOSE, "UserpWin32HeapFail failed");
  824. }
  825. }
  826. UINT
  827. APIENTRY
  828. CsrWin32HeapStat(
  829. PDBGHEAPSTAT phs,
  830. DWORD dwLen)
  831. {
  832. USER_API_MSG m;
  833. PWIN32HEAPSTATMSG a = &m.u.Win32HeapStat;
  834. PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
  835. a->dwLen = dwLen;
  836. CaptureBuffer = CsrAllocateCaptureBuffer(1, dwLen);
  837. if (CaptureBuffer == NULL) {
  838. return 0;
  839. }
  840. CsrCaptureMessageBuffer(CaptureBuffer,
  841. (PCHAR)phs,
  842. dwLen,
  843. (PVOID *)&a->phs);
  844. CsrClientCallServer((PCSR_API_MSG)&m,
  845. CaptureBuffer,
  846. CSR_MAKE_API_NUMBER(USERSRV_SERVERDLL_INDEX,
  847. UserpWin32HeapStat),
  848. sizeof(*a));
  849. if (!NT_SUCCESS(m.ReturnValue)) {
  850. RIPNTERR0(m.ReturnValue, RIP_VERBOSE, "UserpWin32HeapStat failed");
  851. a->dwMaxTag = 0;
  852. goto ErrExit;
  853. }
  854. RtlMoveMemory(phs, a->phs, dwLen);
  855. ErrExit:
  856. CsrFreeCaptureBuffer(CaptureBuffer);
  857. return a->dwMaxTag;
  858. }
  859. #endif // DBG
  860. #endif
  861. #if !defined(BUILD_CSRWOW64)
  862. /******************************************************************************\
  863. * CsrBroadcastSystemMessageExW
  864. *
  865. * Routine Description:
  866. *
  867. * This function is a private API used by the csrss server
  868. *
  869. * This function converts the csrss server thread into a GUI thread, then
  870. * performs a BroadcastSystemMessageExW(), and finally restore the thread's
  871. * desktop.
  872. *
  873. * Arguments:
  874. *
  875. * dwFlags - Broadcast System message flags
  876. *
  877. * lpdwRecipients - Intended recipients of the message
  878. *
  879. * uiMessage - Message type
  880. *
  881. * wParam - first message parameter
  882. *
  883. * lParam - second message parameter
  884. *
  885. * pBSMInfo - BroadcastSystemMessage information
  886. *
  887. * Return Value:
  888. *
  889. * Appropriate NTSTATUS code
  890. *
  891. \******************************************************************************/
  892. FUNCLOG6(LOG_GENERAL, NTSTATUS, APIENTRY, CsrBroadcastSystemMessageExW, DWORD, dwFlags, LPDWORD, lpdwRecipients, UINT, uiMessage, WPARAM, wParam, LPARAM, lParam, PBSMINFO, pBSMInfo)
  893. NTSTATUS
  894. APIENTRY
  895. CsrBroadcastSystemMessageExW(
  896. DWORD dwFlags,
  897. LPDWORD lpdwRecipients,
  898. UINT uiMessage,
  899. WPARAM wParam,
  900. LPARAM lParam,
  901. PBSMINFO pBSMInfo
  902. )
  903. {
  904. USERTHREAD_USEDESKTOPINFO utudi;
  905. long result;
  906. NTSTATUS Status;
  907. /*
  908. * Caller must be from the csrss server
  909. */
  910. if ( !gfServerProcess ) {
  911. return( STATUS_ACCESS_DENIED );
  912. }
  913. /*
  914. * Since this thread is a csrss thread, the thread is not a
  915. * GUI thread and does not have a desktop associated with it.
  916. * Must set the thread's desktop to the active desktop in
  917. * order to call BroadcastSystemMessageExW
  918. */
  919. utudi.hThread = NULL;
  920. utudi.drdRestore.pdeskRestore = NULL;
  921. Status = NtUserSetInformationThread( NtCurrentThread(),
  922. UserThreadUseActiveDesktop,
  923. &utudi,
  924. sizeof(utudi) );
  925. if ( NT_SUCCESS( Status ) ) {
  926. result = BroadcastSystemMessageExW(
  927. dwFlags,
  928. lpdwRecipients,
  929. uiMessage,
  930. wParam,
  931. lParam,
  932. pBSMInfo );
  933. /*
  934. * Restore the previous desktop of the thread
  935. */
  936. Status = NtUserSetInformationThread( NtCurrentThread(),
  937. UserThreadUseDesktop,
  938. &utudi,
  939. sizeof(utudi) );
  940. if ( NT_SUCCESS( Status ) && ( result <= 0 ) ) {
  941. Status = STATUS_UNSUCCESSFUL;
  942. }
  943. }
  944. return( Status );
  945. }
  946. #endif