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.

471 lines
16 KiB

  1. #include "msgina.h"
  2. // This gives me a yucky feeling, but we
  3. // use CRT all over the place in gina.
  4. #include <stdio.h>
  5. #include <windowsx.h>
  6. #include <regstr.h>
  7. #include <help.h>
  8. #include <Wtsapi32.h>
  9. #include "shtdnp.h"
  10. #define DIRTY_SHUTDOWN_TIMEOUT 120
  11. typedef struct _DIRTYDLGDATA
  12. {
  13. REASONDATA ReasonData;
  14. DWORD dwFlags;
  15. BOOL fEndDialogOnActivate;
  16. } DIRTYDLGDATA, *PDIRTYDLGDATA;
  17. // Internal function prototypes
  18. BOOL Dirty_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  19. BOOL Dirty_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  20. BOOL Dirty_OnEraseBkgnd(HWND hwnd, HDC hdc);
  21. INT_PTR CALLBACK Dirty_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  22. LPARAM lParam);
  23. INT_PTR DialogItemToGinaResult(DWORD dwDialogItem, BOOL fAutoPowerdown);
  24. // Enable the OK button based on the selected reason code and the comments / bug id.
  25. void Enable_OK( HWND hwnd, PDIRTYDLGDATA pdata ) {
  26. if ( ReasonCodeNeedsComment( pdata->ReasonData.dwReasonSelect )
  27. || ReasonCodeNeedsBugID( pdata->ReasonData.dwReasonSelect )) {
  28. // See if we have a comment.
  29. if ( pdata->ReasonData.cCommentLen == 0 ) {
  30. EnableWindow( GetDlgItem( hwnd, IDOK ), FALSE );
  31. return;
  32. }
  33. }
  34. // Don't care about bugID anymore.
  35. #if 0
  36. if ( ReasonCodeNeedsBugID( pdata->ReasonData.dwReasonSelect )) {
  37. // See if we have a BugID.
  38. if ( pdata->ReasonData.cBugIDLen == 0 ) {
  39. EnableWindow( GetDlgItem( hwnd, IDOK ), FALSE );
  40. return;
  41. }
  42. }
  43. #endif
  44. EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE );
  45. }
  46. BOOL Dirty_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  47. {
  48. PDIRTYDLGDATA pdata = (PDIRTYDLGDATA) lParam;
  49. HWND hwndCombo;
  50. int iOption;
  51. int iComboItem;
  52. int nComboItemCnt;
  53. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) lParam);
  54. if (!(pdata->dwFlags & SHTDN_NOBRANDINGBITMAP))
  55. {
  56. // Move all our controls down so the branding fits
  57. SizeForBranding(hwnd, FALSE);
  58. }
  59. // Set up the reason data.
  60. // Add the items specified to the combo box
  61. hwndCombo = GetDlgItem(hwnd, IDC_DIRTYREASONS_COMBO);
  62. for (iOption = 0; iOption < pdata->ReasonData.cReasons; iOption ++)
  63. {
  64. // Add the option
  65. iComboItem = ComboBox_AddString(hwndCombo,
  66. pdata->ReasonData.rgReasons[iOption]->szName);
  67. if (iComboItem != (int) CB_ERR)
  68. {
  69. // Store a pointer to the option
  70. ComboBox_SetItemData(hwndCombo, iComboItem,
  71. pdata->ReasonData.rgReasons[iOption]);
  72. // See if we should select this option
  73. if (pdata->ReasonData.rgReasons[iOption]->dwCode == pdata->ReasonData.dwReasonSelect)
  74. {
  75. ComboBox_SetCurSel(hwndCombo, iComboItem);
  76. }
  77. }
  78. }
  79. nComboItemCnt = ComboBox_GetCount(hwndCombo);
  80. if (nComboItemCnt > 0 && pdata->ReasonData.cCommentLen != 0)
  81. {
  82. int iItem;
  83. for (iItem = 0; iItem < nComboItemCnt; iItem++)
  84. {
  85. PREASON pReason = (PREASON) ComboBox_GetItemData(hwndCombo, iItem);
  86. if (pReason->dwCode == (UDIRTYUI | SHTDN_REASON_MAJOR_SYSTEM | SHTDN_REASON_MINOR_BLUESCREEN))
  87. {
  88. ComboBox_SetCurSel(hwndCombo, iItem);
  89. Edit_SetText(GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT), pdata->ReasonData.szComment);
  90. EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE );
  91. break;
  92. }
  93. }
  94. if (iItem == nComboItemCnt) // failed to find the needed reason
  95. {
  96. ComboBox_SetCurSel(hwndCombo, 0);
  97. Edit_SetText(GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT), pdata->ReasonData.szComment);
  98. EnableWindow( GetDlgItem( hwnd, IDOK ), TRUE );
  99. }
  100. SetReasonDescription(hwndCombo,
  101. GetDlgItem(hwnd, IDC_DIRTYREASONS_DESCRIPTION));
  102. }
  103. else
  104. {
  105. // If we don't have a selection in the combo, do a default selection
  106. if (ComboBox_GetCurSel(hwndCombo) == CB_ERR)
  107. {
  108. pdata->ReasonData.dwReasonSelect = pdata->ReasonData.rgReasons[ 0 ]->dwCode;
  109. ComboBox_SetCurSel(hwndCombo, 0);
  110. }
  111. SetReasonDescription(hwndCombo,
  112. GetDlgItem(hwnd, IDC_DIRTYREASONS_DESCRIPTION));
  113. // Enable the OK button
  114. Enable_OK( hwnd, pdata );
  115. }
  116. // Setup the comment box and BugId boxes
  117. // We must fix the maximum characters.
  118. SendMessage( GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT), EM_LIMITTEXT, (WPARAM)MAX_REASON_COMMENT_LEN-1, (LPARAM)0 );
  119. SendMessage( GetDlgItem(hwnd, IDC_DIRTYREASONS_BUGID), EM_LIMITTEXT, (WPARAM)MAX_REASON_BUGID_LEN-1, (LPARAM)0 );
  120. // If we get an activate message, dismiss the dialog, since we just lost
  121. // focus
  122. pdata->fEndDialogOnActivate = TRUE;
  123. CentreWindow(hwnd);
  124. return TRUE;
  125. }
  126. BOOL Dirty_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  127. {
  128. BOOL fHandled = FALSE;
  129. DWORD dwDlgResult = TRUE;
  130. PDIRTYDLGDATA pdata = (PDIRTYDLGDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  131. switch (id)
  132. {
  133. case IDOK:
  134. if (codeNotify == BN_CLICKED)
  135. {
  136. LPWSTR szComment = NULL;
  137. LPWSTR szBugID = NULL;
  138. LPWSTR szBugCheckString = NULL;
  139. DWORD dwCommentLen, dwBugIDLen, dwBugCheckStringLen;
  140. int ilen = 0;
  141. pdata->ReasonData.dwReasonSelect = GetReasonSelection(GetDlgItem(hwnd, IDC_DIRTYREASONS_COMBO));
  142. if (pdata->ReasonData.dwReasonSelect == SHTDN_REASON_UNKNOWN )
  143. {
  144. fHandled = TRUE;
  145. EndDialog(hwnd, (int) dwDlgResult);
  146. break;
  147. }
  148. dwBugCheckStringLen = (DWORD) wcslen (pdata->ReasonData.szComment);
  149. szComment = (LPWSTR)LocalAlloc(LPTR, (MAX_REASON_COMMENT_LEN)*sizeof(WCHAR));
  150. szBugID = (LPWSTR)LocalAlloc(LPTR, (MAX_REASON_BUGID_LEN)*sizeof(WCHAR));
  151. szBugCheckString = (LPWSTR)LocalAlloc(LPTR, (dwBugCheckStringLen+1)*sizeof(WCHAR));
  152. if ( szComment && szBugID && szBugCheckString )
  153. {
  154. wcscpy(szBugCheckString, pdata->ReasonData.szComment);
  155. // Fill the comment field with the Problem Id followed by the comment on a new line.
  156. dwBugIDLen = GetWindowText( GetDlgItem(hwnd, IDC_DIRTYREASONS_BUGID), szBugID, MAX_REASON_BUGID_LEN);
  157. dwCommentLen = GetWindowText( GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT),
  158. szComment,
  159. MAX_REASON_COMMENT_LEN);
  160. szComment[MAX_REASON_COMMENT_LEN-1] = szBugID[MAX_REASON_BUGID_LEN-1] = 0;
  161. ilen = _snwprintf (pdata->ReasonData.szComment,
  162. MAX_REASON_COMMENT_LEN,
  163. L"%d\n%s%d\n%s%d\n%s",
  164. dwBugIDLen, szBugID,
  165. dwBugCheckStringLen, szBugCheckString,
  166. dwCommentLen, szComment);
  167. pdata->ReasonData.szComment[MAX_REASON_COMMENT_LEN-1] = 0;
  168. if (ilen <= 0)
  169. pdata->ReasonData.cCommentLen = MAX_REASON_COMMENT_LEN-1;
  170. else
  171. pdata->ReasonData.cCommentLen = ilen;
  172. pdata->fEndDialogOnActivate = FALSE;
  173. }
  174. else
  175. {
  176. pdata->ReasonData.cCommentLen = 0;
  177. pdata->ReasonData.szComment[0] = 0;
  178. }
  179. LocalFree( szComment );
  180. LocalFree( szBugID );
  181. LocalFree( szBugCheckString );
  182. fHandled = TRUE;
  183. EndDialog(hwnd, (int) dwDlgResult);
  184. }
  185. break;
  186. case IDC_DIRTYREASONS_COMBO:
  187. if (codeNotify == CBN_SELCHANGE)
  188. {
  189. SetReasonDescription(hwndCtl,
  190. GetDlgItem(hwnd, IDC_DIRTYREASONS_DESCRIPTION));
  191. pdata->ReasonData.dwReasonSelect = GetReasonSelection(hwndCtl);
  192. Enable_OK( hwnd, pdata );
  193. fHandled = TRUE;
  194. }
  195. break;
  196. case IDC_DIRTYREASONS_COMMENT:
  197. if ( codeNotify == EN_CHANGE)
  198. {
  199. pdata->ReasonData.cCommentLen = GetWindowTextLength( GetDlgItem(hwnd, IDC_DIRTYREASONS_COMMENT));
  200. Enable_OK( hwnd, pdata );
  201. fHandled = TRUE;
  202. }
  203. break;
  204. case IDC_DIRTYREASONS_BUGID:
  205. if ( codeNotify == EN_CHANGE)
  206. {
  207. pdata->ReasonData.cBugIDLen = GetWindowTextLength( GetDlgItem(hwnd, IDC_DIRTYREASONS_BUGID));
  208. Enable_OK( hwnd, pdata );
  209. fHandled = TRUE;
  210. }
  211. break;
  212. case IDHELP:
  213. if (codeNotify == BN_CLICKED)
  214. {
  215. WinHelp(hwnd, TEXT("windows.hlp>proc4"), HELP_CONTEXT, (DWORD) IDH_TRAY_SHUTDOWN_HELP);
  216. }
  217. break;
  218. }
  219. return fHandled;
  220. }
  221. BOOL Dirty_OnEraseBkgnd(HWND hwnd, HDC hdc)
  222. {
  223. BOOL fRet;
  224. PDIRTYDLGDATA pdata = (PDIRTYDLGDATA) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  225. // Draw the branding bitmap
  226. if (!(pdata->dwFlags & SHTDN_NOBRANDINGBITMAP))
  227. {
  228. fRet = PaintBranding(hwnd, hdc, 0, FALSE, FALSE, COLOR_BTNFACE);
  229. }
  230. else
  231. {
  232. fRet = FALSE;
  233. }
  234. return fRet;
  235. }
  236. INT_PTR CALLBACK Dirty_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  237. LPARAM lParam)
  238. {
  239. switch (uMsg)
  240. {
  241. HANDLE_MSG(hwnd, WM_INITDIALOG, Dirty_OnInitDialog);
  242. HANDLE_MSG(hwnd, WM_COMMAND, Dirty_OnCommand);
  243. HANDLE_MSG(hwnd, WM_ERASEBKGND, Dirty_OnEraseBkgnd);
  244. case WLX_WM_SAS:
  245. {
  246. // If this is someone hitting C-A-D, swallow it.
  247. if (wParam == WLX_SAS_TYPE_CTRL_ALT_DEL)
  248. return TRUE;
  249. // Other SAS's (like timeout), return FALSE and let winlogon
  250. // deal with it.
  251. return FALSE;
  252. }
  253. break;
  254. case WM_INITMENUPOPUP:
  255. {
  256. EnableMenuItem((HMENU)wParam, SC_MOVE, MF_BYCOMMAND|MF_GRAYED);
  257. }
  258. break;
  259. case WM_SYSCOMMAND:
  260. // Blow off moves (only really needed for 32bit land).
  261. if ((wParam & ~0x0F) == SC_MOVE)
  262. return TRUE;
  263. break;
  264. }
  265. return FALSE;
  266. }
  267. /****************************************************************************
  268. WinlogonDirtyDialog
  269. --------------
  270. Launches the shutdown dialog.
  271. If hWlx and pfnWlxDialogBoxParam are non-null, pfnWlxDialogBoxParam will
  272. be used to launch the dialog box so we can intelligently respond to WLX
  273. messages. Only if WinLogon is the caller should this be done.
  274. Other flags are listed in shtdndlg.h.
  275. ****************************************************************************/
  276. INT_PTR
  277. WinlogonDirtyDialog(
  278. HWND hwndParent,
  279. PGLOBALS pGlobals
  280. )
  281. {
  282. // Array of shutdown options - the dialog data
  283. DIRTYDLGDATA data;
  284. DWORD dwResult = WLX_SAS_ACTION_LOGON;
  285. HKEY hKey = 0;
  286. DWORD rc;
  287. DWORD DirtyShutdownHappened;
  288. DWORD ValueSize = sizeof (DWORD);
  289. DWORD dwBugcheckStringSize = (MAX_REASON_COMMENT_LEN - 1)* sizeof(WCHAR);
  290. BOOL fNeedToWriteBack = FALSE;
  291. if (!pGlobals)
  292. return dwResult;
  293. if (! TestUserPrivilege (pGlobals->UserProcessData.UserToken, SE_SHUTDOWN_PRIVILEGE))
  294. goto cleanup;
  295. // Set the initially selected item
  296. data.ReasonData.dwReasonSelect = 0;
  297. data.ReasonData.rgReasons = 0;
  298. data.ReasonData.cReasons = 0;
  299. data.ReasonData.cReasonCapacity = 0;
  300. //
  301. // We only show this dialog if SET is enabled.
  302. //
  303. if (IsSETEnabled()) {
  304. //
  305. // We need to open the reliability key.
  306. //
  307. rc = RegCreateKeyEx (HKEY_LOCAL_MACHINE, REGSTR_PATH_RELIABILITY, 0, NULL, REG_OPTION_NON_VOLATILE,
  308. KEY_ALL_ACCESS, NULL, &hKey, NULL);
  309. ValueSize = sizeof(DWORD);
  310. if (rc == ERROR_SUCCESS)
  311. {
  312. rc = RegQueryValueEx (hKey, L"DirtyShutDown", NULL, NULL, (UCHAR *)&DirtyShutdownHappened, &ValueSize);
  313. if ( (rc == ERROR_SUCCESS) && (DirtyShutdownHappened) ) {
  314. // Read in the strings for the shutdown option names and descriptions
  315. if ( BuildReasonArray( &data.ReasonData, FALSE, TRUE ))
  316. {
  317. data.ReasonData.szBugID[ 0 ] = 0;
  318. data.ReasonData.cBugIDLen = 0;
  319. //If a bugcheck happenned, get the bugcheck string from registry.
  320. rc = RegQueryValueEx (hKey, L"BugcheckString", NULL, NULL, (LPBYTE)data.ReasonData.szComment, &dwBugcheckStringSize);
  321. if (rc != ERROR_SUCCESS)
  322. {
  323. data.ReasonData.szComment[ 0 ] = 0;
  324. data.ReasonData.cCommentLen = 0;
  325. }
  326. else
  327. {
  328. data.ReasonData.cCommentLen = dwBugcheckStringSize / sizeof(WCHAR);
  329. data.ReasonData.szComment[MAX_REASON_COMMENT_LEN - 1] = 0;
  330. }
  331. // Display the dialog and return the user's selection
  332. // Figure out what flags to pass
  333. // for sure no help button
  334. data.dwFlags = SHTDN_NOHELP;
  335. // On terminal server, no branding bitmap either
  336. if ( GetSystemMetrics( SM_REMOTESESSION ))
  337. {
  338. data.dwFlags |= SHTDN_NOBRANDINGBITMAP;
  339. }
  340. pWlxFuncs->WlxSetTimeout(pGlobals->hGlobalWlx, DIRTY_SHUTDOWN_TIMEOUT);
  341. dwResult = ( DWORD )pWlxFuncs->WlxDialogBoxParam( pGlobals->hGlobalWlx,
  342. hDllInstance, MAKEINTRESOURCE( IDD_DIRTY_DIALOG ),
  343. hwndParent, Dirty_DialogProc, ( LPARAM )&data );
  344. // If we timed out then log the user off.
  345. if ( (int)dwResult <= 0 )
  346. {
  347. DestroyReasons( &data.ReasonData );
  348. dwResult = WLX_SAS_ACTION_LOGOFF;
  349. }
  350. else
  351. {
  352. dwResult = WLX_SAS_ACTION_LOGON;
  353. if ( RegDeleteValue( hKey, L"DirtyShutDown" ) == ERROR_SUCCESS )
  354. {
  355. // Record the event.
  356. SHUTDOWN_REASON sr;
  357. sr.cbSize = sizeof(SHUTDOWN_REASON);
  358. sr.uFlags = EWX_SHUTDOWN;
  359. sr.dwReasonCode = data.ReasonData.dwReasonSelect;
  360. sr.dwEventType = SR_EVENT_DIRTY;
  361. sr.lpszComment = data.ReasonData.szComment;
  362. if (ImpersonateLoggedOnUser(pGlobals->UserProcessData.UserToken))
  363. {
  364. RecordShutdownReason(&sr);
  365. RevertToSelf();
  366. RegDeleteValue( hKey, L"BugcheckString");
  367. dwResult = TRUE;
  368. }
  369. else
  370. {
  371. fNeedToWriteBack = TRUE;
  372. }
  373. }
  374. // Destroy the allocated data.
  375. DestroyReasons( &data.ReasonData );
  376. }
  377. }
  378. }
  379. }
  380. else
  381. {
  382. hKey = NULL;
  383. }
  384. }
  385. cleanup:
  386. if (hKey && fNeedToWriteBack)
  387. {
  388. DWORD dwDirtyShutdownFlag = 1;
  389. RegSetValueEx( hKey,
  390. L"DirtyShutDown",
  391. 0,
  392. REG_DWORD,
  393. (PUCHAR) &dwDirtyShutdownFlag,
  394. sizeof(DWORD));
  395. }
  396. if (hKey)
  397. RegCloseKey (hKey);
  398. return dwResult;
  399. }