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.

2139 lines
67 KiB

  1. #include "stdafx.h"
  2. #include "grpinfo.h"
  3. #include "unpage.h"
  4. #include "netpage.h"
  5. #include "password.h"
  6. #include "cryptui.h" // for certificate mgr
  7. #pragma hdrstop
  8. // Certificate Manager helper static functions and delay-load stuff
  9. class CCertificateAPI
  10. {
  11. public:
  12. static BOOL ManagePasswords(HWND hwnd);
  13. static BOOL Wizard(HWND hwnd);
  14. private:
  15. static BOOL m_fFailed;
  16. static HINSTANCE m_hInstCryptUI;
  17. };
  18. BOOL CCertificateAPI::m_fFailed = FALSE;
  19. HINSTANCE CCertificateAPI::m_hInstCryptUI = NULL;
  20. // CCertificateAPI::ManagePasswords - launch certificate manager
  21. typedef BOOL (WINAPI *PFNCRYPTUIDLGCERTMGR)(IN PCCRYPTUI_CERT_MGR_STRUCT pCryptUICertMgr);
  22. BOOL CCertificateAPI::ManagePasswords(HWND hwnd)
  23. {
  24. // Use shellexecuteex to open up the keyring control panel
  25. SHELLEXECUTEINFO shexinfo = {0};
  26. shexinfo.cbSize = sizeof (shexinfo);
  27. shexinfo.fMask = SEE_MASK_DOENVSUBST;
  28. shexinfo.nShow = SW_SHOWNORMAL;
  29. shexinfo.lpFile = L"%windir%\\system32\\rundll32.exe";
  30. shexinfo.lpParameters = L"shell32.dll,Control_RunDLL keymgr.dll";
  31. shexinfo.lpVerb = TEXT("open");
  32. return ShellExecuteEx(&shexinfo);
  33. }
  34. // CCertificateAPI::Wizard - launch the enrollment wizard
  35. typedef BOOL (WINAPI *PFNCRYPTUIWIZCERTREQUEST)(IN DWORD dwFlags,
  36. IN OPTIONAL HWND, IN OPTIONAL LPCWSTR pwszWizardTitle,
  37. IN PCCRYPTUI_WIZ_CERT_REQUEST_INFO pCertRequestInfo,
  38. OUT OPTIONAL PCCERT_CONTEXT *ppCertContext,
  39. OUT OPTIONAL DWORD *pCAdwStatus);
  40. BOOL CCertificateAPI::Wizard(HWND hwnd)
  41. {
  42. static PFNCRYPTUIWIZCERTREQUEST pCryptUIWizCertRequest = NULL;
  43. if ((m_hInstCryptUI == NULL) && (!m_fFailed))
  44. {
  45. m_hInstCryptUI = LoadLibrary(TEXT("cryptui.dll"));
  46. }
  47. if (m_hInstCryptUI != NULL)
  48. {
  49. pCryptUIWizCertRequest = (PFNCRYPTUIWIZCERTREQUEST)
  50. GetProcAddress(m_hInstCryptUI, "CryptUIWizCertRequest");
  51. }
  52. if (pCryptUIWizCertRequest)
  53. {
  54. CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW CertRequestPvkNew = {0};
  55. CertRequestPvkNew.dwSize=sizeof(CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW);
  56. CRYPTUI_WIZ_CERT_REQUEST_INFO CertRequestInfo = {0};
  57. CertRequestInfo.dwSize=sizeof(CRYPTUI_WIZ_CERT_REQUEST_INFO);
  58. CertRequestInfo.dwPurpose=CRYPTUI_WIZ_CERT_ENROLL;
  59. CertRequestInfo.dwPvkChoice=CRYPTUI_WIZ_CERT_REQUEST_PVK_CHOICE_NEW;
  60. CertRequestInfo.pPvkNew=&CertRequestPvkNew;
  61. // This can take a while!
  62. CWaitCursor cur;
  63. pCryptUIWizCertRequest(0, hwnd, NULL, &CertRequestInfo, NULL, NULL);
  64. }
  65. else
  66. {
  67. m_fFailed = TRUE;
  68. }
  69. return (!m_fFailed);
  70. }
  71. // handle auto logon of users
  72. class CAutologonUserDlg: public CDialog
  73. {
  74. public:
  75. CAutologonUserDlg(LPTSTR szInitialUser)
  76. {m_pszUsername = szInitialUser;}
  77. private:
  78. virtual INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  79. BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  80. BOOL OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  81. LPTSTR m_pszUsername;
  82. };
  83. INT_PTR CAutologonUserDlg::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  84. {
  85. switch(uMsg)
  86. {
  87. HANDLE_MSG(hwndDlg, WM_INITDIALOG, OnInitDialog);
  88. HANDLE_MSG(hwndDlg, WM_COMMAND, OnCommand);
  89. }
  90. return FALSE;
  91. }
  92. BOOL CAutologonUserDlg::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  93. {
  94. HWND hwndUsername = GetDlgItem(hwnd, IDC_USER);
  95. HWND hwndPassword = GetDlgItem(hwnd, IDC_PASSWORD);
  96. HWND hwndConfirm = GetDlgItem(hwnd, IDC_CONFIRMPASSWORD);
  97. // limit the text with of the controls
  98. Edit_LimitText(hwndUsername, MAX_USER);
  99. Edit_LimitText(hwndPassword, MAX_PASSWORD);
  100. Edit_LimitText(hwndConfirm, MAX_PASSWORD);
  101. // Populate the username field and set focus to password
  102. SetWindowText(hwndUsername, m_pszUsername);
  103. SetFocus(hwndPassword);
  104. BOOL fSetDefaultFocus = FALSE;
  105. return (fSetDefaultFocus);
  106. }
  107. BOOL CAutologonUserDlg::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  108. {
  109. switch (id)
  110. {
  111. case IDOK:
  112. {
  113. TCHAR szUsername[MAX_USER + 1];
  114. TCHAR szPassword[MAX_PASSWORD + 1];
  115. TCHAR szConfirm[MAX_PASSWORD + 1];
  116. FetchText(hwnd, IDC_USER, szUsername, ARRAYSIZE(szUsername));
  117. GetWindowText(GetDlgItem(hwnd, IDC_PASSWORD), szPassword, ARRAYSIZE(szPassword));
  118. GetWindowText(GetDlgItem(hwnd, IDC_CONFIRMPASSWORD), szConfirm, ARRAYSIZE(szConfirm));
  119. if (StrCmp(szConfirm, szPassword) != 0)
  120. {
  121. // Display a message saying the passwords don't match
  122. DisplayFormatMessage(hwnd, IDS_USR_APPLET_CAPTION, IDS_ERR_PWDNOMATCH, MB_OK | MB_ICONERROR);
  123. break;
  124. }
  125. else
  126. {
  127. // Actually apply the autologon
  128. SetAutoLogon(szUsername, szPassword);
  129. SecureZeroMemory(szPassword, ARRAYSIZE(szPassword));
  130. }
  131. }
  132. // Fall through
  133. case IDCANCEL:
  134. EndDialog(hwnd, id);
  135. }
  136. return (TRUE);
  137. }
  138. // user list page (the main page the user sees)
  139. class CUserlistPropertyPage: public CPropertyPage
  140. {
  141. public:
  142. CUserlistPropertyPage(CUserManagerData* pdata): m_pData(pdata)
  143. {m_himlLarge = NULL;}
  144. ~CUserlistPropertyPage();
  145. static HRESULT AddUserToListView(HWND hwndList, CUserInfo* pUserInfo, BOOL fSelectUser = FALSE);
  146. private:
  147. virtual INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  148. BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  149. BOOL OnNotify(HWND hwnd, int idCtrl, LPNMHDR pnmh);
  150. BOOL OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  151. BOOL OnGetInfoTip(HWND hwndList, LPNMLVGETINFOTIP pGetInfoTip);
  152. BOOL OnListViewItemChanged(HWND hwnd);
  153. BOOL OnListViewDeleteItem(HWND hwndList, int iItem);
  154. BOOL OnHelp(HWND hwnd, LPHELPINFO pHelpInfo);
  155. BOOL OnContextMenu(HWND hwnd);
  156. BOOL OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg);
  157. long OnApply(HWND hwnd);
  158. HRESULT InitializeListView(HWND hwndList, BOOL fShowDomain);
  159. HRESULT LaunchNewUserWizard(HWND hwndParent);
  160. HRESULT LaunchAddNetUserWizard(HWND hwndParent);
  161. HRESULT LaunchUserProperties(HWND hwndParent);
  162. HRESULT LaunchSetPasswordDialog(HWND hwndParent);
  163. CUserInfo* GetSelectedUserInfo(HWND hwndList);
  164. void OnRemove(HWND hwnd);
  165. int ConfirmRemove(HWND hwnd, CUserInfo* pUserInfo);
  166. void RemoveSelectedUserFromList(HWND hwndList, BOOL fFreeUserInfo);
  167. void SetPageState(HWND hwnd);
  168. HRESULT SetAutologonState(HWND hwnd, BOOL fAutologon);
  169. void SetupList(HWND hwnd);
  170. HPSXA AddExtraUserPropPages(ADDPROPSHEETDATA* ppsd, PSID psid);
  171. static int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2,
  172. LPARAM lParamSort);
  173. CUserManagerData* m_pData;
  174. HIMAGELIST m_himlLarge;
  175. // When a column header is clicked, the list is sorted based on that column
  176. // When this happens, we store the column number here so that if the same
  177. // column is clicked again, we sort it in reverse. A 0 is stored if no
  178. // column should be sorted in reverse when clicked.
  179. int m_iReverseColumnIfSelected;
  180. BOOL m_fAutologonCheckChanged;
  181. };
  182. // Help ID array
  183. static const DWORD rgUserListHelpIds[] =
  184. {
  185. IDC_AUTOLOGON_CHECK, IDH_AUTOLOGON_CHECK,
  186. IDC_LISTTITLE_STATIC, IDH_USER_LIST,
  187. IDC_USER_LIST, IDH_USER_LIST,
  188. IDC_ADDUSER_BUTTON, IDH_ADDUSER_BUTTON,
  189. IDC_REMOVEUSER_BUTTON, IDH_REMOVEUSER_BUTTON,
  190. IDC_USERPROPERTIES_BUTTON, IDH_USERPROPERTIES_BUTTON,
  191. IDC_PASSWORD_STATIC, IDH_PASSWORD_BUTTON,
  192. IDC_CURRENTUSER_ICON, IDH_PASSWORD_BUTTON,
  193. IDC_PASSWORD_BUTTON, IDH_PASSWORD_BUTTON,
  194. IDC_PWGROUP_STATIC, (DWORD) -1,
  195. IDC_ULISTPG_TEXT, (DWORD) -1,
  196. IDC_USERLISTPAGE_ICON, (DWORD) -1,
  197. 0, 0
  198. };
  199. // Control ID arrays for enabling/disabling/moving
  200. static const UINT rgidDisableOnAutologon[] =
  201. {
  202. IDC_USER_LIST,
  203. IDC_ADDUSER_BUTTON,
  204. IDC_REMOVEUSER_BUTTON,
  205. IDC_USERPROPERTIES_BUTTON,
  206. IDC_PASSWORD_BUTTON
  207. };
  208. static const UINT rgidDisableOnNoSelection[] =
  209. {
  210. IDC_REMOVEUSER_BUTTON,
  211. IDC_USERPROPERTIES_BUTTON,
  212. IDC_PASSWORD_BUTTON
  213. };
  214. static const UINT rgidMoveOnNoAutologonCheck[] =
  215. {
  216. IDC_LISTTITLE_STATIC,
  217. IDC_USER_LIST,
  218. };
  219. CUserlistPropertyPage::~CUserlistPropertyPage()
  220. {
  221. if (m_himlLarge != NULL)
  222. ImageList_Destroy(m_himlLarge);
  223. }
  224. INT_PTR CUserlistPropertyPage::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  225. {
  226. switch (uMsg)
  227. {
  228. HANDLE_MSG(hwndDlg, WM_INITDIALOG, OnInitDialog);
  229. HANDLE_MSG(hwndDlg, WM_NOTIFY, OnNotify);
  230. HANDLE_MSG(hwndDlg, WM_COMMAND, OnCommand);
  231. HANDLE_MSG(hwndDlg, WM_SETCURSOR, OnSetCursor);
  232. case WM_HELP:
  233. return OnHelp(hwndDlg, (LPHELPINFO) lParam);
  234. case WM_CONTEXTMENU:
  235. return OnContextMenu((HWND) wParam);
  236. case WM_ADDUSERTOLIST:
  237. return SUCCEEDED(AddUserToListView(GetDlgItem(hwndDlg, IDC_USER_LIST), (CUserInfo*)lParam, (BOOL) wParam));
  238. }
  239. return FALSE;
  240. }
  241. BOOL CUserlistPropertyPage::OnHelp(HWND hwnd, LPHELPINFO pHelpInfo)
  242. {
  243. WinHelp((HWND) pHelpInfo->hItemHandle, m_pData->GetHelpfilePath(),
  244. HELP_WM_HELP, (ULONG_PTR) (LPTSTR)rgUserListHelpIds);
  245. return TRUE;
  246. }
  247. BOOL CUserlistPropertyPage::OnContextMenu(HWND hwnd)
  248. {
  249. WinHelp(hwnd, m_pData->GetHelpfilePath(),
  250. HELP_CONTEXTMENU, (ULONG_PTR) (LPTSTR)rgUserListHelpIds);
  251. return TRUE;
  252. }
  253. BOOL CUserlistPropertyPage::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  254. {
  255. HWND hwndList = GetDlgItem(hwnd, IDC_USER_LIST);
  256. InitializeListView(hwndList, m_pData->IsComputerInDomain());
  257. m_pData->Initialize(hwnd);
  258. SetupList(hwnd);
  259. m_fAutologonCheckChanged = FALSE;
  260. return TRUE;
  261. }
  262. BOOL CUserlistPropertyPage::OnListViewDeleteItem(HWND hwndList, int iItem)
  263. {
  264. LVITEM lvi = {0};
  265. lvi.iItem = iItem;
  266. lvi.mask = LVIF_PARAM;
  267. ListView_GetItem(hwndList, &lvi);
  268. CUserInfo* pUserInfo = (CUserInfo*)lvi.lParam;
  269. if (NULL != pUserInfo)
  270. {
  271. delete pUserInfo;
  272. }
  273. return TRUE;
  274. }
  275. BOOL CUserlistPropertyPage::OnNotify(HWND hwnd, int idCtrl, LPNMHDR pnmh)
  276. {
  277. switch (pnmh->code)
  278. {
  279. case PSN_APPLY:
  280. {
  281. long applyEffect = OnApply(hwnd);
  282. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, applyEffect);
  283. break;
  284. }
  285. case LVN_GETINFOTIP:
  286. return OnGetInfoTip(pnmh->hwndFrom, (LPNMLVGETINFOTIP) pnmh);
  287. break;
  288. case LVN_ITEMCHANGED:
  289. return OnListViewItemChanged(hwnd);
  290. break;
  291. case LVN_DELETEITEM:
  292. return OnListViewDeleteItem(GetDlgItem(hwnd, IDC_USER_LIST), ((LPNMLISTVIEW) pnmh)->iItem);
  293. case NM_DBLCLK:
  294. LaunchUserProperties(hwnd);
  295. return TRUE;
  296. case LVN_COLUMNCLICK:
  297. {
  298. int iColumn = ((LPNMLISTVIEW) pnmh)->iSubItem;
  299. // Want to work with 1-based columns so we can use zero as
  300. // a special value
  301. iColumn += 1;
  302. // If we aren't showing the domain column because we're in
  303. // non-domain mode, then map column 2 (group since we're not in
  304. // domain mode to column 3 since the callback always expects
  305. // the columns to be, "username", "domain", "group".
  306. if ((iColumn == 2) && (!m_pData->IsComputerInDomain()))
  307. {
  308. iColumn = 3;
  309. }
  310. if (m_iReverseColumnIfSelected == iColumn)
  311. {
  312. m_iReverseColumnIfSelected = 0;
  313. iColumn = -iColumn;
  314. }
  315. else
  316. {
  317. m_iReverseColumnIfSelected = iColumn;
  318. }
  319. ListView_SortItems(pnmh->hwndFrom, ListCompare, (LPARAM) iColumn);
  320. return TRUE;
  321. }
  322. default:
  323. return FALSE;
  324. }
  325. return TRUE;
  326. }
  327. BOOL CUserlistPropertyPage::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  328. {
  329. switch (id)
  330. {
  331. case IDC_ADDUSER_BUTTON:
  332. if (m_pData->IsComputerInDomain())
  333. {
  334. // Launch the wizard to add a network user to a local group
  335. LaunchAddNetUserWizard(hwnd);
  336. }
  337. else
  338. {
  339. // No domain; create a new local machine user
  340. LaunchNewUserWizard(hwnd);
  341. }
  342. return TRUE;
  343. case IDC_REMOVEUSER_BUTTON:
  344. OnRemove(hwnd);
  345. return TRUE;
  346. case IDC_AUTOLOGON_CHECK:
  347. {
  348. m_fAutologonCheckChanged = TRUE;
  349. BOOL fAutoLogon = (BST_UNCHECKED == SendMessage(GetDlgItem(hwnd, IDC_AUTOLOGON_CHECK), BM_GETCHECK, 0, 0));
  350. SetAutologonState(hwnd, fAutoLogon);
  351. SetPageState(hwnd);
  352. break;
  353. }
  354. case IDC_ADVANCED_BUTTON:
  355. {
  356. static const TCHAR szMMCCommandLineFormat[] = TEXT("mmc.exe /computer=%s %%systemroot%%\\system32\\lusrmgr.msc");
  357. TCHAR szMMCCommandLine[MAX_PATH];
  358. TCHAR szExpandedCommandLine[MAX_PATH];
  359. wnsprintf(szMMCCommandLine, ARRAYSIZE(szMMCCommandLine), szMMCCommandLineFormat, m_pData->GetComputerName());
  360. if (ExpandEnvironmentStrings(szMMCCommandLine, szExpandedCommandLine, ARRAYSIZE(szExpandedCommandLine)) > 0)
  361. {
  362. PROCESS_INFORMATION pi;
  363. STARTUPINFO si = {0};
  364. si.cb = sizeof (si);
  365. if (CreateProcess(NULL, szExpandedCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
  366. {
  367. CloseHandle(pi.hProcess);
  368. CloseHandle(pi.hThread);
  369. }
  370. }
  371. break;
  372. }
  373. case IDC_PASSWORD_BUTTON:
  374. LaunchSetPasswordDialog(hwnd);
  375. break;
  376. case IDC_USERPROPERTIES_BUTTON:
  377. LaunchUserProperties(hwnd);
  378. break;
  379. }
  380. return FALSE;
  381. }
  382. BOOL CUserlistPropertyPage::OnSetCursor(HWND hwnd, HWND hwndCursor, UINT codeHitTest, UINT msg)
  383. {
  384. BOOL fHandled = FALSE;
  385. if (m_pData->GetUserListLoader()->InitInProgress())
  386. {
  387. // If the thread is filling, handle by setting the appstarting cursor
  388. SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
  389. fHandled = TRUE;
  390. }
  391. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, fHandled);
  392. return TRUE;
  393. }
  394. BOOL CUserlistPropertyPage::OnGetInfoTip(HWND hwndList, LPNMLVGETINFOTIP pGetInfoTip)
  395. {
  396. // Get the UserInfo structure for the selected item
  397. LVITEM lvi;
  398. lvi.mask = LVIF_PARAM;
  399. lvi.iItem = pGetInfoTip->iItem;
  400. lvi.iSubItem = 0;
  401. if ((lvi.iItem >= 0) && (ListView_GetItem(hwndList, &lvi)))
  402. {
  403. // Ensure full name and comment are available
  404. CUserInfo* pUserInfo = (CUserInfo*)lvi.lParam;
  405. pUserInfo->GetExtraUserInfo();
  406. // Make a string containing our "Full Name: %s\nComment: %s" message
  407. if ((pUserInfo->m_szFullName[0] != TEXT('\0')) &&
  408. (pUserInfo->m_szComment[0] != TEXT('\0')))
  409. {
  410. // We have a full name and comment
  411. FormatMessageString(IDS_USR_TOOLTIPBOTH_FORMAT, pGetInfoTip->pszText, pGetInfoTip->cchTextMax, pUserInfo->m_szFullName, pUserInfo->m_szComment);
  412. }
  413. else if (pUserInfo->m_szFullName[0] != TEXT('\0'))
  414. {
  415. // We only have full name
  416. FormatMessageString(IDS_USR_TOOLTIPFULLNAME_FORMAT, pGetInfoTip->pszText, pGetInfoTip->cchTextMax, pUserInfo->m_szFullName);
  417. }
  418. else if (pUserInfo->m_szComment[0] != TEXT('\0'))
  419. {
  420. // We only have comment
  421. FormatMessageString(IDS_USR_TOOLTIPCOMMENT_FORMAT, pGetInfoTip->pszText, pGetInfoTip->cchTextMax, pUserInfo->m_szComment);
  422. }
  423. else
  424. {
  425. // We have no extra information - do nothing (show no tip)
  426. }
  427. }
  428. return TRUE;
  429. }
  430. struct MYCOLINFO
  431. {
  432. int percentWidth;
  433. UINT idString;
  434. };
  435. HRESULT CUserlistPropertyPage::InitializeListView(HWND hwndList, BOOL fShowDomain)
  436. {
  437. // Array of icon ids icons 0, 1, and 2 respectively
  438. static const UINT rgIcons[] =
  439. {
  440. IDI_USR_LOCALUSER_ICON,
  441. IDI_USR_DOMAINUSER_ICON,
  442. IDI_USR_GROUP_ICON
  443. };
  444. // Array of relative column widths, for columns 0, 1, and 2 respectively
  445. static const MYCOLINFO rgColWidthsWithDomain[] =
  446. {
  447. {40, IDS_USR_NAME_COLUMN},
  448. {30, IDS_USR_DOMAIN_COLUMN},
  449. {30, IDS_USR_GROUP_COLUMN}
  450. };
  451. static const MYCOLINFO rgColWidthsNoDomain[] =
  452. {
  453. {50, IDS_USR_NAME_COLUMN},
  454. {50, IDS_USR_GROUP_COLUMN}
  455. };
  456. // Create a listview with three columns
  457. RECT rect;
  458. GetClientRect(hwndList, &rect);
  459. // Width of our window minus width of a verticle scroll bar minus one for the
  460. // little bevel at the far right of the header.
  461. int cxListView = (rect.right - rect.left) - GetSystemMetrics(SM_CXVSCROLL) - 1;
  462. // Make our columns
  463. int i;
  464. int nColumns;
  465. const MYCOLINFO* pColInfo;
  466. if (fShowDomain)
  467. {
  468. nColumns = ARRAYSIZE(rgColWidthsWithDomain);
  469. pColInfo = rgColWidthsWithDomain;
  470. }
  471. else
  472. {
  473. nColumns = ARRAYSIZE(rgColWidthsNoDomain);
  474. pColInfo = rgColWidthsNoDomain;
  475. }
  476. LVCOLUMN lvc;
  477. lvc.mask = LVCF_TEXT | LVCF_SUBITEM | LVCF_WIDTH;
  478. for (i = 0; i < nColumns; i++)
  479. {
  480. TCHAR szText[MAX_PATH];
  481. // Load this column's caption
  482. LoadString(g_hinst, pColInfo[i].idString, szText, ARRAYSIZE(szText));
  483. lvc.iSubItem = i;
  484. lvc.cx = (int) MulDiv(pColInfo[i].percentWidth, cxListView, 100);
  485. lvc.pszText = szText;
  486. ListView_InsertColumn(hwndList, i, &lvc);
  487. }
  488. UINT flags = ILC_MASK;
  489. if(IS_WINDOW_RTL_MIRRORED(hwndList))
  490. {
  491. flags |= ILC_MIRROR;
  492. }
  493. // Create an image list for the listview
  494. HIMAGELIST himlSmall = ImageList_Create(16, 16, flags, 0, ARRAYSIZE(rgIcons));
  495. // Large image lists for the "set password" group icon
  496. m_himlLarge = ImageList_Create(32, 32, flags, 0, ARRAYSIZE(rgIcons));
  497. if (himlSmall && m_himlLarge)
  498. {
  499. // Add our icons to the image list
  500. for(i = 0; i < ARRAYSIZE(rgIcons); i ++)
  501. {
  502. HICON hIconSmall = (HICON) LoadImage(g_hinst, MAKEINTRESOURCE(rgIcons[i]), IMAGE_ICON, 16, 16, 0);
  503. if (hIconSmall)
  504. {
  505. ImageList_AddIcon(himlSmall, hIconSmall);
  506. DestroyIcon(hIconSmall);
  507. }
  508. HICON hIconLarge = (HICON) LoadImage(g_hinst, MAKEINTRESOURCE(rgIcons[i]), IMAGE_ICON, 32, 32, 0);
  509. if (hIconLarge)
  510. {
  511. ImageList_AddIcon(m_himlLarge, hIconLarge);
  512. DestroyIcon(hIconLarge);
  513. }
  514. }
  515. }
  516. ListView_SetImageList(hwndList, himlSmall, LVSIL_SMALL);
  517. // Set extended styles for the listview
  518. ListView_SetExtendedListViewStyleEx(hwndList,
  519. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP,
  520. LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
  521. // Set some settings for our tooltips - stolen from defview.cpp code
  522. HWND hwndInfoTip = ListView_GetToolTips(hwndList);
  523. if (hwndInfoTip != NULL)
  524. {
  525. //make the tooltip window to be topmost window
  526. SetWindowPos(hwndInfoTip, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  527. // increase the ShowTime (the delay before we show the tooltip) to 2 times the default value
  528. LRESULT uiShowTime = SendMessage(hwndInfoTip, TTM_GETDELAYTIME, TTDT_INITIAL, 0);
  529. SendMessage(hwndInfoTip, TTM_SETDELAYTIME, TTDT_INITIAL, uiShowTime * 2);
  530. }
  531. return S_OK;
  532. }
  533. HRESULT CUserlistPropertyPage::AddUserToListView(HWND hwndList,
  534. CUserInfo* pUserInfo,
  535. BOOL fSelectUser /* = FALSE */)
  536. {
  537. if (!pUserInfo->m_fAccountDisabled)
  538. {
  539. LVITEM lvi = { 0 };
  540. lvi.iItem = 0;
  541. lvi.iSubItem = 0;
  542. lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
  543. lvi.pszText = pUserInfo->m_szUsername;
  544. lvi.iImage = pUserInfo->m_userType;
  545. lvi.lParam = (LPARAM) pUserInfo;
  546. // Always select the first loaded user
  547. if (ListView_GetItemCount(hwndList) == 0)
  548. fSelectUser = TRUE;
  549. if (fSelectUser)
  550. {
  551. lvi.mask |= LVIF_STATE;
  552. lvi.state = lvi.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
  553. }
  554. int iItem = ListView_InsertItem(hwndList, &lvi);
  555. if (iItem >= 0)
  556. {
  557. if (fSelectUser)
  558. ListView_EnsureVisible(hwndList, iItem, FALSE); // Make the item visible
  559. // Success! Now add the subitems (domain, groups)
  560. lvi.iItem = iItem;
  561. lvi.mask = LVIF_TEXT;
  562. // Only add the domain field if the user is in a domain
  563. if (::IsComputerInDomain())
  564. {
  565. lvi.iSubItem = 1;
  566. lvi.pszText = pUserInfo->m_szDomain;
  567. ListView_SetItem(hwndList, &lvi);
  568. // User is in a domain; group should be third column
  569. lvi.iSubItem = 2;
  570. }
  571. else
  572. {
  573. // User isn't in a domain, group should be second column
  574. lvi.iSubItem = 1;
  575. }
  576. // Add group regardless of whether user is in a domain
  577. lvi.pszText = pUserInfo->m_szGroups;
  578. ListView_SetItem(hwndList, &lvi);
  579. }
  580. }
  581. /*
  582. else
  583. {
  584. // Do we leak the pUserInfo for disabled user accounts?
  585. }
  586. */
  587. return S_OK;
  588. }
  589. HRESULT CUserlistPropertyPage::LaunchNewUserWizard(HWND hwndParent)
  590. {
  591. static const int nPages = 3;
  592. int cPages = 0;
  593. HPROPSHEETPAGE rghPages[nPages];
  594. // Create a new user record
  595. CUserInfo* pNewUser = new CUserInfo;
  596. if ( !pNewUser )
  597. {
  598. DisplayFormatMessage(hwndParent, IDS_USR_NEWUSERWIZARD_CAPTION, IDS_USR_CREATE_MISC_ERROR, MB_OK | MB_ICONERROR);
  599. return E_OUTOFMEMORY;
  600. }
  601. pNewUser->InitializeForNewUser();
  602. pNewUser->m_userType = CUserInfo::LOCALUSER;
  603. PROPSHEETPAGE psp = {0};
  604. // Common propsheetpage settings
  605. psp.dwSize = sizeof (psp);
  606. psp.hInstance = g_hinst;
  607. psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
  608. // Page 1: Username entry page
  609. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_USERNAME_WIZARD_PAGE);
  610. CUsernameWizardPage page1(pNewUser);
  611. page1.SetPropSheetPageMembers(&psp);
  612. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  613. // Page 2: Password page
  614. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_PASSWORD_WIZARD_PAGE);
  615. CPasswordWizardPage page2(pNewUser);
  616. page2.SetPropSheetPageMembers(&psp);
  617. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  618. // Page 3: Local group addition
  619. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_CHOOSEGROUP_WIZARD_PAGE);
  620. CGroupWizardPage page3(pNewUser, m_pData->GetGroupList());
  621. page3.SetPropSheetPageMembers(&psp);
  622. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  623. PROPSHEETHEADER psh = {0};
  624. psh.dwSize = sizeof (psh);
  625. psh.dwFlags = PSH_NOCONTEXTHELP | PSH_WIZARD | PSH_WIZARD_LITE;
  626. psh.hwndParent = hwndParent;
  627. psh.hInstance = g_hinst;
  628. psh.nPages = nPages;
  629. psh.phpage = rghPages;
  630. if (PropertySheet(&psh) == IDOK)
  631. {
  632. AddUserToListView(GetDlgItem(hwndParent, IDC_USER_LIST), pNewUser, TRUE);
  633. }
  634. else
  635. {
  636. // User clicked cancel
  637. delete pNewUser;
  638. pNewUser = NULL;
  639. }
  640. return S_OK;
  641. }
  642. HRESULT CUserlistPropertyPage::LaunchAddNetUserWizard(HWND hwndParent)
  643. {
  644. HRESULT hr = S_OK;
  645. static const int nPages = 2;
  646. int cPages = 0;
  647. HPROPSHEETPAGE rghPages[nPages];
  648. // Create a new user record
  649. CUserInfo* pNewUser = new CUserInfo;
  650. if ( !pNewUser )
  651. {
  652. DisplayFormatMessage(hwndParent, IDS_USR_NEWUSERWIZARD_CAPTION, IDS_USR_CREATE_MISC_ERROR, MB_OK | MB_ICONERROR);
  653. return E_OUTOFMEMORY;
  654. }
  655. pNewUser->InitializeForNewUser();
  656. pNewUser->m_userType = CUserInfo::DOMAINUSER;
  657. PROPSHEETPAGE psp = {0};
  658. // Common propsheetpage settings
  659. psp.dwSize = sizeof (psp);
  660. psp.hInstance = g_hinst;
  661. psp.dwFlags = PSP_DEFAULT | PSP_HIDEHEADER;
  662. // Page 1: Find a network user page
  663. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_FINDNETUSER_WIZARD_PAGE);
  664. CNetworkUserWizardPage page1(pNewUser);
  665. page1.SetPropSheetPageMembers(&psp);
  666. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  667. // Page 2: Local group addition
  668. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_CHOOSEGROUP_WIZARD_PAGE);
  669. CGroupWizardPage page2(pNewUser, m_pData->GetGroupList());
  670. page2.SetPropSheetPageMembers(&psp);
  671. rghPages[cPages++] = CreatePropertySheetPage(&psp);
  672. PROPSHEETHEADER psh = {0};
  673. psh.dwSize = sizeof (psh);
  674. psh.dwFlags = PSH_NOCONTEXTHELP | PSH_WIZARD | PSH_WIZARD_LITE;
  675. psh.hwndParent = hwndParent;
  676. psh.hInstance = g_hinst;
  677. psh.nPages = nPages;
  678. psh.phpage = rghPages;
  679. if (PropertySheet(&psh) == IDOK)
  680. {
  681. AddUserToListView(GetDlgItem(hwndParent, IDC_USER_LIST), pNewUser, TRUE);
  682. m_pData->UserInfoChanged(pNewUser->m_szUsername, pNewUser->m_szDomain);
  683. }
  684. else
  685. {
  686. // No errors, but the user clicked Cancel...
  687. delete pNewUser;
  688. pNewUser = NULL;
  689. }
  690. return S_OK;
  691. }
  692. HRESULT CUserlistPropertyPage::LaunchUserProperties(HWND hwndParent)
  693. {
  694. HRESULT hr = S_OK;
  695. HWND hwndList = GetDlgItem(hwndParent, IDC_USER_LIST);
  696. CUserInfo* pUserInfo = GetSelectedUserInfo(hwndList);
  697. if (pUserInfo != NULL)
  698. {
  699. pUserInfo->GetExtraUserInfo();
  700. // page addition information
  701. ADDPROPSHEETDATA apsd;
  702. apsd.nPages = 0;
  703. // Common propsheetpage settings
  704. PROPSHEETPAGE psp = {0};
  705. psp.dwSize = sizeof (psp);
  706. psp.hInstance = g_hinst;
  707. psp.dwFlags = PSP_DEFAULT;
  708. // If we have a local user, show both the username and group page, ow
  709. // just the group page
  710. // Page 1: Username entry page
  711. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_USERNAME_PROP_PAGE);
  712. CUsernamePropertyPage page1(pUserInfo);
  713. page1.SetPropSheetPageMembers(&psp);
  714. // Only actually create the prop page if we have a local user
  715. if (pUserInfo->m_userType == CUserInfo::LOCALUSER)
  716. {
  717. apsd.rgPages[apsd.nPages++] = CreatePropertySheetPage(&psp);
  718. }
  719. // Always add the second page
  720. // Page 2: Local group addition
  721. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_CHOOSEGROUP_PROP_PAGE);
  722. CGroupPropertyPage page2(pUserInfo, m_pData->GetGroupList());
  723. page2.SetPropSheetPageMembers(&psp);
  724. apsd.rgPages[apsd.nPages++] = CreatePropertySheetPage(&psp);
  725. HPSXA hpsxa = AddExtraUserPropPages(&apsd, pUserInfo->m_psid);
  726. PROPSHEETHEADER psh = {0};
  727. psh.dwSize = sizeof (psh);
  728. psh.dwFlags = PSH_DEFAULT | PSH_PROPTITLE;
  729. TCHAR szDomainUser[MAX_USER + MAX_DOMAIN + 2];
  730. MakeDomainUserString(pUserInfo->m_szDomain, pUserInfo->m_szUsername, szDomainUser, ARRAYSIZE(szDomainUser));
  731. psh.pszCaption = szDomainUser;
  732. psh.hwndParent = hwndParent;
  733. psh.hInstance = g_hinst;
  734. psh.nPages = apsd.nPages;
  735. psh.phpage = apsd.rgPages;
  736. int iRetCode = (int)PropertySheet(&psh);
  737. if (hpsxa != NULL)
  738. SHDestroyPropSheetExtArray(hpsxa);
  739. if (iRetCode == IDOK)
  740. {
  741. // PropSheet_Changed(GetParent(hwndParent), hwndParent);
  742. // So that we don't delete this pUserInfo when we remove
  743. // this user from the list:
  744. m_pData->UserInfoChanged(pUserInfo->m_szUsername, (pUserInfo->m_szDomain[0] == 0) ? NULL : pUserInfo->m_szDomain);
  745. RemoveSelectedUserFromList(hwndList, FALSE);
  746. AddUserToListView(hwndList, pUserInfo, TRUE);
  747. }
  748. }
  749. return S_OK;
  750. }
  751. CUserInfo* CUserlistPropertyPage::GetSelectedUserInfo(HWND hwndList)
  752. {
  753. int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  754. if (iItem >= 0)
  755. {
  756. LVITEM lvi = {0};
  757. lvi.mask = LVIF_PARAM;
  758. lvi.iItem = iItem;
  759. if (ListView_GetItem(hwndList, &lvi))
  760. {
  761. return (CUserInfo*)lvi.lParam;
  762. }
  763. }
  764. return NULL;
  765. }
  766. void CUserlistPropertyPage::RemoveSelectedUserFromList(HWND hwndList, BOOL fFreeUserInfo)
  767. {
  768. int iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  769. // If we don't want to delete this user info, better set it to NULL
  770. if (!fFreeUserInfo)
  771. {
  772. LVITEM lvi = {0};
  773. lvi.iItem = iItem;
  774. lvi.mask = LVIF_PARAM;
  775. lvi.lParam = (LPARAM) (CUserInfo*) NULL;
  776. ListView_SetItem(hwndList, &lvi);
  777. }
  778. ListView_DeleteItem(hwndList, iItem);
  779. int iSelect = iItem > 0 ? iItem - 1 : 0;
  780. ListView_SetItemState(hwndList, iSelect, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  781. SetFocus(hwndList);
  782. }
  783. void CUserlistPropertyPage::OnRemove(HWND hwnd)
  784. {
  785. HWND hwndList = GetDlgItem(hwnd, IDC_USER_LIST);
  786. CUserInfo* pUserInfo = GetSelectedUserInfo(hwndList);
  787. if (pUserInfo)
  788. {
  789. if (ConfirmRemove(hwnd, pUserInfo) == IDYES)
  790. {
  791. if (SUCCEEDED(pUserInfo->Remove()))
  792. {
  793. RemoveSelectedUserFromList(hwndList, TRUE);
  794. }
  795. else
  796. {
  797. TCHAR szDisplayName[MAX_USER + MAX_DOMAIN + 2];
  798. ::MakeDomainUserString(pUserInfo->m_szDomain, pUserInfo->m_szUsername,
  799. szDisplayName, ARRAYSIZE(szDisplayName));
  800. DisplayFormatMessage(hwnd, IDS_USR_APPLET_CAPTION,
  801. IDS_USR_REMOVE_MISC_ERROR, MB_ICONERROR | MB_OK, szDisplayName);
  802. }
  803. }
  804. }
  805. }
  806. int CUserlistPropertyPage::ConfirmRemove(HWND hwnd, CUserInfo* pUserInfo)
  807. {
  808. TCHAR szDomainUser[MAX_USER + MAX_DOMAIN + 2];
  809. MakeDomainUserString(pUserInfo->m_szDomain, pUserInfo->m_szUsername, szDomainUser, ARRAYSIZE(szDomainUser));
  810. return DisplayFormatMessage(hwnd, IDS_USR_APPLET_CAPTION, IDS_USR_REMOVEUSER_WARNING,
  811. MB_ICONEXCLAMATION | MB_YESNO, szDomainUser);
  812. }
  813. void CUserlistPropertyPage::SetPageState(HWND hwnd)
  814. {
  815. BOOL fAutologon = (BST_UNCHECKED ==
  816. SendMessage(GetDlgItem(hwnd, IDC_AUTOLOGON_CHECK), BM_GETCHECK, 0, 0));
  817. EnableControls(hwnd, rgidDisableOnAutologon, ARRAYSIZE(rgidDisableOnAutologon),
  818. !fAutologon);
  819. HWND hwndList = GetDlgItem(hwnd, IDC_USER_LIST);
  820. CUserInfo* pUserInfo = GetSelectedUserInfo(hwndList);
  821. if (pUserInfo)
  822. {
  823. TCHAR szPWGroup[128];
  824. FormatMessageString(IDS_USR_PWGROUP_FORMAT, szPWGroup, ARRAYSIZE(szPWGroup), pUserInfo->m_szUsername);
  825. SetWindowText(GetDlgItem(hwnd, IDC_PWGROUP_STATIC), szPWGroup);
  826. TCHAR szPWMessage[128];
  827. // If the logged on user is the selected user
  828. CUserInfo* pLoggedOnUser = m_pData->GetLoggedOnUserInfo();
  829. if ((StrCmpI(pUserInfo->m_szUsername, pLoggedOnUser->m_szUsername) == 0) &&
  830. (StrCmpI(pUserInfo->m_szDomain, pLoggedOnUser->m_szDomain) == 0))
  831. {
  832. LoadString(g_hinst, IDS_USR_YOURPWMESSAGE_FORMAT, szPWMessage, ARRAYSIZE(szPWMessage));
  833. EnableWindow(GetDlgItem(hwnd, IDC_PASSWORD_BUTTON), FALSE);
  834. }
  835. // If the user is a local user
  836. else if (pUserInfo->m_userType == CUserInfo::LOCALUSER)
  837. {
  838. // We can set this user's password
  839. FormatMessageString(IDS_USR_PWMESSAGE_FORMAT, szPWMessage, ARRAYSIZE(szPWMessage), pUserInfo->m_szUsername);
  840. }
  841. else
  842. {
  843. // Nothing can be done with this user's password
  844. // the selected user may be a domain user or a group or something
  845. // We can set this user's password
  846. FormatMessageString(IDS_USR_CANTCHANGEPW_FORMAT, szPWMessage, ARRAYSIZE(szPWMessage), pUserInfo->m_szUsername);
  847. EnableWindow(GetDlgItem(hwnd, IDC_PASSWORD_BUTTON), FALSE);
  848. }
  849. SetWindowText(GetDlgItem(hwnd, IDC_PASSWORD_STATIC), szPWMessage);
  850. // Set the icon for the user
  851. HICON hIcon = ImageList_GetIcon(m_himlLarge, pUserInfo->m_userType, ILD_NORMAL);
  852. Static_SetIcon(GetDlgItem(hwnd, IDC_CURRENTUSER_ICON), hIcon);
  853. }
  854. else
  855. {
  856. EnableControls(hwnd, rgidDisableOnNoSelection, ARRAYSIZE(rgidDisableOnNoSelection), FALSE);
  857. }
  858. }
  859. HRESULT CUserlistPropertyPage::SetAutologonState(HWND hwnd, BOOL fAutologon)
  860. {
  861. PropSheet_Changed(GetParent(hwnd), hwnd);
  862. return S_OK;
  863. }
  864. BOOL CUserlistPropertyPage::OnListViewItemChanged(HWND hwnd)
  865. {
  866. SetPageState(hwnd);
  867. return TRUE;
  868. }
  869. long CUserlistPropertyPage::OnApply(HWND hwnd)
  870. {
  871. long applyEffect = PSNRET_NOERROR;
  872. BOOL fAutologonSet = (BST_UNCHECKED == SendMessage(GetDlgItem(hwnd, IDC_AUTOLOGON_CHECK), BM_GETCHECK, 0, 0));
  873. if (!fAutologonSet)
  874. {
  875. ClearAutoLogon(); // Ensure autologon is cleared
  876. }
  877. else if (m_fAutologonCheckChanged)
  878. {
  879. CUserInfo* pSelectedUser = GetSelectedUserInfo(GetDlgItem(hwnd, IDC_USER_LIST));
  880. TCHAR szNullName[] = TEXT("");
  881. CAutologonUserDlg dlg((pSelectedUser != NULL) ? pSelectedUser->m_szUsername : szNullName);
  882. if (dlg.DoModal(g_hinst, MAKEINTRESOURCE(IDD_USR_AUTOLOGON_DLG), hwnd) == IDCANCEL)
  883. {
  884. applyEffect = PSNRET_INVALID_NOCHANGEPAGE;
  885. }
  886. }
  887. m_fAutologonCheckChanged = FALSE;
  888. if (applyEffect == PSNRET_INVALID_NOCHANGEPAGE)
  889. {
  890. m_pData->Initialize(hwnd); // Reload the data and list
  891. SetupList(hwnd);
  892. }
  893. return applyEffect;
  894. }
  895. void CUserlistPropertyPage::SetupList(HWND hwnd)
  896. {
  897. HWND hwndList = GetDlgItem(hwnd, IDC_USER_LIST);
  898. // Disable autologon check box in the domain case where autologon isn't // enabled
  899. HWND hwndCheck = GetDlgItem(hwnd, IDC_AUTOLOGON_CHECK);
  900. if (m_pData->IsComputerInDomain() && !m_pData->IsAutologonEnabled())
  901. {
  902. ShowWindow(hwndCheck, SW_HIDE);
  903. EnableWindow(hwndCheck, FALSE);
  904. // Move most controls up a bit if the autologon is not visible
  905. RECT rcBottom;
  906. GetWindowRect(GetDlgItem(hwnd, IDC_LISTTITLE_STATIC), &rcBottom);
  907. RECT rcTop;
  908. GetWindowRect(hwndCheck, &rcTop);
  909. int dy = rcTop.top - rcBottom.top;
  910. OffsetControls(hwnd, rgidMoveOnNoAutologonCheck,
  911. ARRAYSIZE(rgidMoveOnNoAutologonCheck), 0, dy);
  912. // Grow the list by this amount also
  913. RECT rcList;
  914. GetWindowRect(hwndList, &rcList);
  915. SetWindowPos(hwndList, NULL, 0, 0, rcList.right - rcList.left,
  916. rcList.bottom - rcList.top - dy, SWP_NOZORDER|SWP_NOMOVE);
  917. }
  918. SendMessage(hwndCheck, BM_SETCHECK,
  919. m_pData->IsAutologonEnabled() ? BST_UNCHECKED : BST_CHECKED, 0);
  920. // Set the text in the set password group.
  921. SetPageState(hwnd);
  922. }
  923. HRESULT CUserlistPropertyPage::LaunchSetPasswordDialog(HWND hwndParent)
  924. {
  925. CUserInfo* pUserInfo = GetSelectedUserInfo(GetDlgItem(hwndParent, IDC_USER_LIST));
  926. if ((pUserInfo != NULL) && (pUserInfo->m_userType == CUserInfo::LOCALUSER))
  927. {
  928. CChangePasswordDlg dlg(pUserInfo);
  929. dlg.DoModal(g_hinst, MAKEINTRESOURCE(IDD_USR_SETPASSWORD_DLG), hwndParent);
  930. return S_OK;
  931. }
  932. return E_FAIL;
  933. }
  934. #define MAX_EXTRA_PAGES 10
  935. HPSXA CUserlistPropertyPage::AddExtraUserPropPages(ADDPROPSHEETDATA* ppsd, PSID psid)
  936. {
  937. HPSXA hpsxa = NULL;
  938. IDataObject *pdo;
  939. HRESULT hr = CUserSidDataObject_CreateInstance(psid, &pdo);
  940. if (SUCCEEDED(hr))
  941. {
  942. hpsxa = SHCreatePropSheetExtArrayEx(HKEY_LOCAL_MACHINE, REGSTR_USERPROPERTIES_SHEET, MAX_EXTRA_PAGES, pdo);
  943. if (hpsxa)
  944. {
  945. SHAddFromPropSheetExtArray(hpsxa, AddPropSheetPageCallback, (LPARAM) ppsd);
  946. }
  947. pdo->Release();
  948. }
  949. return hpsxa;
  950. }
  951. // ListCompare
  952. // Compares list items in for sorting the listview by column
  953. // lParamSort gets the 1-based column index. If lParamSort is negative
  954. // it indicates that the given column should be sorted in reverse.
  955. int CUserlistPropertyPage::ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  956. {
  957. CUserInfo* pUserInfo1 = (CUserInfo*)lParam1;
  958. CUserInfo* pUserInfo2 = (CUserInfo*)lParam2;
  959. int iColumn = (int)lParamSort;
  960. BOOL fReverse = FALSE;
  961. if (iColumn < 0)
  962. {
  963. fReverse = TRUE;
  964. iColumn = -iColumn;
  965. }
  966. int iResult = 0; // they match...
  967. switch (iColumn)
  968. {
  969. case 1:
  970. iResult = lstrcmpi(pUserInfo1->m_szUsername, pUserInfo2->m_szUsername);
  971. break;
  972. case 2:
  973. iResult = lstrcmpi(pUserInfo1->m_szDomain, pUserInfo2->m_szDomain);
  974. break;
  975. case 3:
  976. iResult = lstrcmpi(pUserInfo1->m_szGroups, pUserInfo2->m_szGroups);
  977. break;
  978. }
  979. if (fReverse)
  980. iResult = -iResult;
  981. return iResult;
  982. }
  983. // The DoModal call for this dialog will return IDOK if the applet should be
  984. // shown or IDCANCEL if the users.cpl should exit without displaying the applet.
  985. // dsheldon - TODO: Remove this dialog and don't let non-admins runas the cpl
  986. class CSecurityCheckDlg: public CDialog
  987. {
  988. public:
  989. CSecurityCheckDlg(LPCTSTR pszDomainUser):
  990. m_pszDomainUser(pszDomainUser)
  991. {}
  992. private:
  993. virtual INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  994. BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  995. BOOL OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  996. BOOL OnNotify(HWND hwnd, int id, NMHDR* pnmhdr);
  997. HRESULT RelaunchAsUser(HWND hwnd);
  998. LPCTSTR m_pszDomainUser;
  999. };
  1000. // implementation
  1001. INT_PTR CSecurityCheckDlg::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1002. {
  1003. switch(uMsg)
  1004. {
  1005. HANDLE_MSG(hwndDlg, WM_INITDIALOG, OnInitDialog);
  1006. HANDLE_MSG(hwndDlg, WM_COMMAND, OnCommand);
  1007. HANDLE_MSG(hwndDlg, WM_NOTIFY, OnNotify);
  1008. }
  1009. return FALSE;
  1010. }
  1011. BOOL CSecurityCheckDlg::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  1012. {
  1013. // First we must check if the current user is a local administrator; if this is
  1014. // the case, our dialog doesn't even display
  1015. BOOL fIsLocalAdmin;
  1016. if (SUCCEEDED(IsUserLocalAdmin(NULL, &fIsLocalAdmin)))
  1017. {
  1018. if (fIsLocalAdmin)
  1019. {
  1020. EndDialog(hwnd, IDOK); // We want to continue and launch the applet (don't display the security check dlg)
  1021. }
  1022. }
  1023. else
  1024. {
  1025. EndDialog(hwnd, IDCANCEL);
  1026. }
  1027. // Set the "can't launch User Options" message
  1028. TCHAR szUsername[MAX_USER + 1];
  1029. DWORD cchUsername = ARRAYSIZE(szUsername);
  1030. TCHAR szDomain[MAX_DOMAIN + 1];
  1031. DWORD cchDomain = ARRAYSIZE(szDomain);
  1032. if (GetCurrentUserAndDomainName(szUsername, &cchUsername, szDomain, &cchDomain))
  1033. {
  1034. TCHAR szDomainAndUsername[MAX_DOMAIN + MAX_USER + 2];
  1035. MakeDomainUserString(szDomain, szUsername, szDomainAndUsername, ARRAYSIZE(szDomainAndUsername));
  1036. TCHAR szMessage[256];
  1037. if (FormatMessageString(IDS_USR_CANTRUNCPL_FORMAT, szMessage, ARRAYSIZE(szMessage), szDomainAndUsername))
  1038. {
  1039. SetWindowText(GetDlgItem(hwnd, IDC_CANTRUNCPL_STATIC), szMessage);
  1040. }
  1041. TCHAR szAdministrator[MAX_USER + 1];
  1042. LoadString(g_hinst, IDS_ADMINISTRATOR, szAdministrator, ARRAYSIZE(szAdministrator));
  1043. SetWindowText(GetDlgItem(hwnd, IDC_USER), szAdministrator);
  1044. TCHAR szMachine[MAX_COMPUTERNAME + 1];
  1045. DWORD dwSize = ARRAYSIZE(szMachine);
  1046. ::GetComputerName(szMachine, &dwSize);
  1047. SetWindowText(GetDlgItem(hwnd, IDC_DOMAIN), szMachine);
  1048. }
  1049. // Limit the text in the edit fields
  1050. HWND hwndUsername = GetDlgItem(hwnd, IDC_USER);
  1051. Edit_LimitText(hwndUsername, MAX_USER);
  1052. HWND hwndDomain = GetDlgItem(hwnd, IDC_DOMAIN);
  1053. Edit_LimitText(hwndDomain, MAX_DOMAIN);
  1054. HWND hwndPassword = GetDlgItem(hwnd, IDC_PASSWORD);
  1055. Edit_LimitText(hwndPassword, MAX_PASSWORD);
  1056. if (!IsComputerInDomain())
  1057. {
  1058. // Don't need domain box
  1059. EnableWindow(hwndDomain, FALSE);
  1060. ShowWindow(hwndDomain, SW_HIDE);
  1061. ShowWindow(GetDlgItem(hwnd, IDC_DOMAIN_STATIC), SW_HIDE);
  1062. // Move up the OK/Cancel buttons and text and shrink the dialog
  1063. RECT rcDomain;
  1064. GetWindowRect(hwndDomain, &rcDomain);
  1065. RECT rcPassword;
  1066. GetWindowRect(hwndPassword, &rcPassword);
  1067. int dy = (rcPassword.top - rcDomain.top);
  1068. // dy is negative
  1069. OffsetWindow(GetDlgItem(hwnd, IDOK), 0, dy);
  1070. OffsetWindow(GetDlgItem(hwnd, IDCANCEL), 0, dy);
  1071. OffsetWindow(GetDlgItem(hwnd, IDC_PASSWORD_STATIC), 0, dy);
  1072. OffsetWindow(GetDlgItem(hwnd, IDC_OTHEROPTIONS_LINK), 0, dy);
  1073. RECT rcDialog;
  1074. GetWindowRect(hwnd, &rcDialog);
  1075. rcDialog.bottom += dy;
  1076. MoveWindow(hwnd, rcDialog.left, rcDialog.top, rcDialog.right-rcDialog.left,
  1077. rcDialog.bottom-rcDialog.top, FALSE);
  1078. }
  1079. return TRUE;
  1080. }
  1081. BOOL CSecurityCheckDlg::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1082. {
  1083. switch (id)
  1084. {
  1085. case IDOK:
  1086. if (SUCCEEDED(RelaunchAsUser(hwnd)))
  1087. {
  1088. EndDialog(hwnd, IDCANCEL);
  1089. }
  1090. return TRUE;
  1091. case IDCANCEL:
  1092. EndDialog(hwnd, IDCANCEL);
  1093. return TRUE;
  1094. }
  1095. return FALSE;
  1096. }
  1097. BOOL CSecurityCheckDlg::OnNotify(HWND hwnd, int id, NMHDR *pnmhdr)
  1098. {
  1099. BOOL fHandled = FALSE;
  1100. switch (pnmhdr->code)
  1101. {
  1102. // Handle link window clicks
  1103. case NM_CLICK:
  1104. case NM_RETURN:
  1105. {
  1106. if (IDC_OTHEROPTIONS_LINK == id)
  1107. {
  1108. // First link in the control is "manage passwords", second is "passport wizard"
  1109. NMLINKWND* pnm = (NMLINKWND*) pnmhdr;
  1110. if (0 == pnm->item.iLink)
  1111. {
  1112. // Launch "manage passwords"
  1113. CCertificateAPI::ManagePasswords(hwnd);
  1114. }
  1115. else if (1 == pnm->item.iLink)
  1116. {
  1117. // Launch passport wizard
  1118. IPassportWizard *pPW;
  1119. if (SUCCEEDED(CoCreateInstance(CLSID_PassportWizard, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPassportWizard, &pPW))))
  1120. {
  1121. pPW->SetOptions(PPW_LAUNCHEDBYUSER);
  1122. pPW->Show(hwnd);
  1123. pPW->Release();
  1124. }
  1125. }
  1126. fHandled = TRUE;
  1127. }
  1128. }
  1129. break;
  1130. };
  1131. return fHandled;
  1132. }
  1133. HRESULT CSecurityCheckDlg::RelaunchAsUser(HWND hwnd)
  1134. {
  1135. USES_CONVERSION;
  1136. HRESULT hr = E_FAIL;
  1137. TCHAR szUsername[MAX_USER + 1];
  1138. FetchText(hwnd, IDC_USER, szUsername, ARRAYSIZE(szUsername));
  1139. TCHAR szDomain[MAX_DOMAIN + 1];
  1140. FetchText(hwnd, IDC_DOMAIN, szDomain, ARRAYSIZE(szDomain));
  1141. // If the user didn't type a domain
  1142. if (szDomain[0] == TEXT('\0'))
  1143. {
  1144. // Use this machine as the domain
  1145. DWORD cchComputername = ARRAYSIZE(szDomain);
  1146. ::GetComputerName(szDomain, &cchComputername);
  1147. }
  1148. TCHAR szPassword[MAX_PASSWORD + 1];
  1149. GetWindowText(GetDlgItem(hwnd, IDC_PASSWORD), szPassword, ARRAYSIZE(szPassword));
  1150. // Now relaunch ourselves with this information
  1151. STARTUPINFO startupinfo = {0};
  1152. startupinfo.cb = sizeof (startupinfo);
  1153. WCHAR c_szCommandLineFormat[] = L"rundll32.exe netplwiz.dll,UsersRunDll %s";
  1154. // Put the "real" user name in the command-line so that we know what user is
  1155. // actually logged on to the machine even though we are re-launching in a different
  1156. // user context
  1157. WCHAR szCommandLine[ARRAYSIZE(c_szCommandLineFormat) + MAX_DOMAIN + MAX_USER + 2];
  1158. wnsprintf(szCommandLine, ARRAYSIZE(szCommandLine), c_szCommandLineFormat, m_pszDomainUser);
  1159. PROCESS_INFORMATION process_information;
  1160. if (CreateProcessWithLogonW(szUsername, szDomain, szPassword, LOGON_WITH_PROFILE, NULL,
  1161. szCommandLine, 0, NULL, NULL, &startupinfo, &process_information))
  1162. {
  1163. CloseHandle(process_information.hProcess);
  1164. CloseHandle(process_information.hThread);
  1165. hr = S_OK;
  1166. }
  1167. else
  1168. {
  1169. DisplayFormatMessage(hwnd, IDS_USR_APPLET_CAPTION, IDS_USR_CANTOPENCPLASUSER_ERROR, MB_OK|MB_ICONERROR);
  1170. }
  1171. return hr;
  1172. }
  1173. // Advanced Property Page
  1174. class CAdvancedPropertyPage: public CPropertyPage
  1175. {
  1176. public:
  1177. CAdvancedPropertyPage(CUserManagerData* pdata):
  1178. m_pData(pdata),
  1179. m_fRebootRequired(FALSE) {}
  1180. private:
  1181. virtual INT_PTR DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  1182. BOOL OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  1183. BOOL OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  1184. BOOL OnNotify(HWND hwnd, int idCtrl, LPNMHDR pnmh);
  1185. BOOL OnHelp(HWND hwnd, LPHELPINFO pHelpInfo);
  1186. BOOL OnContextMenu(HWND hwnd);
  1187. void ReadRequireCad(BOOL* pfRequireCad, BOOL* pfSetInPolicy);
  1188. void WriteRequireCad(BOOL fRequireCad);
  1189. CUserManagerData* m_pData;
  1190. BOOL m_fRebootRequired;
  1191. };
  1192. // Relevant regkeys/regvals
  1193. #define REGKEY_WINLOGON \
  1194. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
  1195. #define REGKEY_WINLOGON_POLICY \
  1196. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System")
  1197. #define REGVAL_DISABLE_CAD TEXT("DisableCAD")
  1198. void CAdvancedPropertyPage::ReadRequireCad(BOOL* pfRequireCad, BOOL* pfSetInPolicy)
  1199. {
  1200. HKEY hkey;
  1201. DWORD dwSize;
  1202. DWORD dwType;
  1203. BOOL fDisableCad;
  1204. NT_PRODUCT_TYPE nttype;
  1205. *pfRequireCad = TRUE;
  1206. *pfSetInPolicy = FALSE;
  1207. if (!RtlGetNtProductType(&nttype))
  1208. {
  1209. nttype = NtProductWinNt;
  1210. }
  1211. // By default, don't require CAD for workstations not
  1212. // on a domain only
  1213. if ((NtProductWinNt == nttype) && !IsComputerInDomain())
  1214. {
  1215. *pfRequireCad = FALSE;
  1216. }
  1217. // Read the setting from the machine preferences
  1218. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WINLOGON, 0,
  1219. KEY_READ, &hkey) == ERROR_SUCCESS)
  1220. {
  1221. dwSize = sizeof(fDisableCad);
  1222. if (ERROR_SUCCESS == RegQueryValueEx (hkey, REGVAL_DISABLE_CAD, NULL, &dwType,
  1223. (LPBYTE) &fDisableCad, &dwSize))
  1224. {
  1225. *pfRequireCad = !fDisableCad;
  1226. }
  1227. RegCloseKey (hkey);
  1228. }
  1229. // Check if C-A-D is disabled via policy
  1230. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WINLOGON_POLICY, 0, KEY_READ,
  1231. &hkey) == ERROR_SUCCESS)
  1232. {
  1233. dwSize = sizeof(fDisableCad);
  1234. if (ERROR_SUCCESS == RegQueryValueEx (hkey, REGVAL_DISABLE_CAD, NULL, &dwType,
  1235. (LPBYTE) &fDisableCad, &dwSize))
  1236. {
  1237. *pfRequireCad = !fDisableCad;
  1238. *pfSetInPolicy = TRUE;
  1239. }
  1240. RegCloseKey (hkey);
  1241. }
  1242. }
  1243. void CAdvancedPropertyPage::WriteRequireCad(BOOL fRequireCad)
  1244. {
  1245. HKEY hkey;
  1246. DWORD dwDisp;
  1247. BOOL fDisableCad = !fRequireCad;
  1248. if (ERROR_SUCCESS == RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEY_WINLOGON, 0,
  1249. NULL, 0, KEY_WRITE, NULL, &hkey, &dwDisp))
  1250. {
  1251. RegSetValueEx(hkey, REGVAL_DISABLE_CAD, 0, REG_DWORD,
  1252. (LPBYTE) &fDisableCad, sizeof(fDisableCad));
  1253. RegCloseKey (hkey);
  1254. }
  1255. }
  1256. static const DWORD rgAdvHelpIds[] =
  1257. {
  1258. IDC_ADVANCED_BUTTON, IDH_ADVANCED_BUTTON,
  1259. IDC_BOOT_ICON, IDH_SECUREBOOT_CHECK,
  1260. IDC_BOOT_TEXT, IDH_SECUREBOOT_CHECK,
  1261. IDC_REQUIRECAD, IDH_SECUREBOOT_CHECK,
  1262. IDC_MANAGEPWD_BUTTON, IDH_MANAGEPWD_BUTTON,
  1263. IDC_PASSPORTWIZARD, IDH_PASSPORTWIZARD,
  1264. IDC_CERT_ICON, (DWORD) -1,
  1265. IDC_CERT_TEXT, (DWORD) -1,
  1266. 0, 0
  1267. };
  1268. INT_PTR CAdvancedPropertyPage::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1269. {
  1270. switch (uMsg)
  1271. {
  1272. HANDLE_MSG(hwndDlg, WM_INITDIALOG, OnInitDialog);
  1273. HANDLE_MSG(hwndDlg, WM_COMMAND, OnCommand);
  1274. HANDLE_MSG(hwndDlg, WM_NOTIFY, OnNotify);
  1275. case WM_HELP: return OnHelp(hwndDlg, (LPHELPINFO) lParam);
  1276. case WM_CONTEXTMENU: return OnContextMenu((HWND) wParam);
  1277. }
  1278. return FALSE;
  1279. }
  1280. BOOL CAdvancedPropertyPage::OnNotify(HWND hwnd, int idCtrl, LPNMHDR pnmh)
  1281. {
  1282. BOOL fReturn = FALSE;
  1283. switch (pnmh->code)
  1284. {
  1285. case PSN_APPLY:
  1286. {
  1287. HWND hwndCheck = GetDlgItem(hwnd, IDC_REQUIRECAD);
  1288. BOOL fRequireCad = (BST_CHECKED == Button_GetCheck(hwndCheck));
  1289. // See if a change is really necessary
  1290. BOOL fOldRequireCad;
  1291. BOOL fDummy;
  1292. ReadRequireCad(&fOldRequireCad, &fDummy);
  1293. if (fRequireCad != fOldRequireCad)
  1294. {
  1295. WriteRequireCad(fRequireCad);
  1296. // m_fRebootRequired = TRUE;
  1297. // Uncomment the line above if it ever becomes necessary to reboot the machine - it isn't now.
  1298. }
  1299. // xxx->lParam == 0 means Ok as opposed to Apply
  1300. if ((((PSHNOTIFY*) pnmh)->lParam) && m_fRebootRequired)
  1301. {
  1302. PropSheet_RebootSystem(GetParent(hwnd));
  1303. }
  1304. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
  1305. fReturn = TRUE;
  1306. }
  1307. break;
  1308. }
  1309. return fReturn;
  1310. }
  1311. BOOL CAdvancedPropertyPage::OnHelp(HWND hwnd, LPHELPINFO pHelpInfo)
  1312. {
  1313. WinHelp((HWND) pHelpInfo->hItemHandle, m_pData->GetHelpfilePath(),
  1314. HELP_WM_HELP, (ULONG_PTR) (LPTSTR)rgAdvHelpIds);
  1315. return TRUE;
  1316. }
  1317. BOOL CAdvancedPropertyPage::OnContextMenu(HWND hwnd)
  1318. {
  1319. WinHelp(hwnd, m_pData->GetHelpfilePath(), HELP_CONTEXTMENU, (ULONG_PTR) (LPTSTR)rgAdvHelpIds);
  1320. return TRUE;
  1321. }
  1322. BOOL CAdvancedPropertyPage::OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  1323. {
  1324. // Do the required mucking for the Require C-A-D checkbox...
  1325. // Read the setting for the require CAD checkbox
  1326. BOOL fRequireCad;
  1327. BOOL fSetInPolicy;
  1328. ReadRequireCad(&fRequireCad, &fSetInPolicy);
  1329. HWND hwndCheck = GetDlgItem(hwnd, IDC_REQUIRECAD);
  1330. // Disable the check if set in policy
  1331. EnableWindow(hwndCheck, !fSetInPolicy);
  1332. // Set the check accordingly
  1333. Button_SetCheck(hwndCheck,
  1334. fRequireCad ? BST_CHECKED : BST_UNCHECKED);
  1335. return TRUE;
  1336. }
  1337. BOOL CAdvancedPropertyPage::OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1338. {
  1339. switch (id)
  1340. {
  1341. case IDC_MANAGEPWD_BUTTON:
  1342. {
  1343. CCertificateAPI::ManagePasswords(hwnd);
  1344. }
  1345. break;
  1346. case IDC_PASSPORTWIZARD:
  1347. {
  1348. IPassportWizard *pPW;
  1349. if (SUCCEEDED(CoCreateInstance(CLSID_PassportWizard, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPassportWizard, &pPW))))
  1350. {
  1351. pPW->SetOptions(PPW_LAUNCHEDBYUSER);
  1352. pPW->Show(hwnd);
  1353. pPW->Release();
  1354. }
  1355. }
  1356. break;
  1357. case IDC_ADVANCED_BUTTON:
  1358. {
  1359. // Launch the MMC local user manager
  1360. STARTUPINFO startupinfo = {0};
  1361. startupinfo.cb = sizeof (startupinfo);
  1362. PROCESS_INFORMATION process_information;
  1363. static const TCHAR szMMCCommandLine[] =
  1364. TEXT("mmc.exe %systemroot%\\system32\\lusrmgr.msc computername=localmachine");
  1365. TCHAR szExpandedCommandLine[MAX_PATH];
  1366. if (ExpandEnvironmentStrings(szMMCCommandLine, szExpandedCommandLine,
  1367. ARRAYSIZE(szExpandedCommandLine)) > 0)
  1368. {
  1369. if (CreateProcess(NULL, szExpandedCommandLine, NULL, NULL, FALSE, 0, NULL, NULL,
  1370. &startupinfo, &process_information))
  1371. {
  1372. CloseHandle(process_information.hProcess);
  1373. CloseHandle(process_information.hThread);
  1374. }
  1375. }
  1376. }
  1377. break;
  1378. case IDC_REQUIRECAD:
  1379. PropSheet_Changed(GetParent(hwnd), hwnd);
  1380. break;
  1381. }
  1382. return FALSE;
  1383. }
  1384. // users control panel entry point
  1385. void APIENTRY UsersRunDll(HWND hwndStub, HINSTANCE hAppInstance, LPSTR pszCmdLine, int nCmdShow)
  1386. {
  1387. HRESULT hr = S_OK;
  1388. TCHAR szDomainUser[MAX_USER + MAX_DOMAIN + 2];
  1389. *szDomainUser = 0;
  1390. // Get the "real" user of this machine - this may be passed in the cmdline
  1391. if (0 == *pszCmdLine)
  1392. {
  1393. // user wasn't passed, assume its the currently logged on user
  1394. TCHAR szUser[MAX_USER + 1];
  1395. DWORD cchUser = ARRAYSIZE(szUser);
  1396. TCHAR szDomain[MAX_DOMAIN + 1];
  1397. DWORD cchDomain = ARRAYSIZE(szDomain);
  1398. if (0 != GetCurrentUserAndDomainName(szUser, &cchUser, szDomain, &cchDomain))
  1399. {
  1400. MakeDomainUserString(szDomain, szUser, szDomainUser, ARRAYSIZE(szDomainUser));
  1401. }
  1402. }
  1403. else
  1404. {
  1405. // User name was passed in, just copy it
  1406. MultiByteToWideChar(GetACP(), 0, pszCmdLine, -1, szDomainUser, ARRAYSIZE(szDomainUser));
  1407. }
  1408. // Initialize COM, but continue even if this fails.
  1409. BOOL fComInited = SUCCEEDED(CoInitialize(NULL));
  1410. // See if we're already running
  1411. TCHAR szCaption[256];
  1412. LoadString(g_hinst, IDS_USR_APPLET_CAPTION, szCaption, ARRAYSIZE(szCaption));
  1413. CEnsureSingleInstance ESI(szCaption);
  1414. if (!ESI.ShouldExit())
  1415. {
  1416. LinkWindow_RegisterClass();
  1417. // Create the security check dialog to ensure the logged-on user
  1418. // is a local admin
  1419. CSecurityCheckDlg dlg(szDomainUser);
  1420. if (dlg.DoModal(g_hinst, MAKEINTRESOURCE(IDD_USR_SECURITYCHECK_DLG), NULL) == IDOK)
  1421. {
  1422. // Create the shared user mgr object
  1423. CUserManagerData data(szDomainUser);
  1424. // Create the property sheet and page template
  1425. // Maximum number of pages
  1426. ADDPROPSHEETDATA ppd;
  1427. ppd.nPages = 0;
  1428. // Settings common to all pages
  1429. PROPSHEETPAGE psp = {0};
  1430. psp.dwSize = sizeof (psp);
  1431. psp.hInstance = g_hinst;
  1432. // Create the userlist property sheet page and its managing object
  1433. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_USERLIST_PAGE);
  1434. CUserlistPropertyPage userListPage(&data);
  1435. userListPage.SetPropSheetPageMembers(&psp);
  1436. ppd.rgPages[ppd.nPages++] = CreatePropertySheetPage(&psp);
  1437. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_ADVANCED_PAGE);
  1438. CAdvancedPropertyPage advancedPage(&data);
  1439. advancedPage.SetPropSheetPageMembers(&psp);
  1440. ppd.rgPages[ppd.nPages++] = CreatePropertySheetPage(&psp);
  1441. HPSXA hpsxa = SHCreatePropSheetExtArrayEx(HKEY_LOCAL_MACHINE, REGSTR_USERSANDPASSWORDS_CPL, 10, NULL);
  1442. if (hpsxa != NULL)
  1443. SHAddFromPropSheetExtArray(hpsxa, AddPropSheetPageCallback, (LPARAM)&ppd);
  1444. // Create the prop sheet
  1445. PROPSHEETHEADER psh = {0};
  1446. psh.dwSize = sizeof (psh);
  1447. psh.dwFlags = PSH_DEFAULT;
  1448. psh.hwndParent = hwndStub;
  1449. psh.hInstance = g_hinst;
  1450. psh.pszCaption = szCaption;
  1451. psh.nPages = ppd.nPages;
  1452. psh.phpage = ppd.rgPages;
  1453. // Show the property sheet
  1454. int iRetCode = PropertySheetIcon(&psh, MAKEINTRESOURCE(IDI_USR_USERS));
  1455. if (hpsxa != NULL)
  1456. {
  1457. SHDestroyPropSheetExtArray(hpsxa);
  1458. }
  1459. if (iRetCode == -1)
  1460. {
  1461. hr = E_FAIL;
  1462. }
  1463. else
  1464. {
  1465. hr = S_OK;
  1466. // Special case when we must restart or reboot
  1467. if (iRetCode == ID_PSREBOOTSYSTEM)
  1468. {
  1469. RestartDialogEx(NULL, NULL, EWX_REBOOT, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG);
  1470. }
  1471. else if (iRetCode == ID_PSRESTARTWINDOWS)
  1472. {
  1473. RestartDialogEx(NULL, NULL, EWX_REBOOT, SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG);
  1474. }
  1475. else if (data.LogoffRequired())
  1476. {
  1477. int iLogoff = DisplayFormatMessage(NULL, IDS_USERSANDPASSWORDS, IDS_LOGOFFREQUIRED, MB_YESNO | MB_ICONQUESTION);
  1478. if (iLogoff == IDYES)
  1479. {
  1480. // Tell explorer to log off the "real" logged on user. We need to do this
  1481. // since they may be running U&P as a different user.
  1482. HWND hwnd = FindWindow(TEXT("Shell_TrayWnd"), TEXT(""));
  1483. if ( hwnd )
  1484. {
  1485. UINT uMsg = RegisterWindowMessage(TEXT("Logoff User"));
  1486. PostMessage(hwnd, uMsg, 0,0);
  1487. }
  1488. }
  1489. }
  1490. }
  1491. }
  1492. else
  1493. {
  1494. // Security check told us to exit; either another instance of the CPL is starting
  1495. // with admin priviledges or the user cancelled on the sec. check. dlg.
  1496. hr = E_FAIL;
  1497. }
  1498. }
  1499. if (fComInited)
  1500. CoUninitialize();
  1501. }
  1502. // user property property page object
  1503. class CUserPropertyPages: public IShellExtInit, IShellPropSheetExt
  1504. {
  1505. public:
  1506. CUserPropertyPages();
  1507. ~CUserPropertyPages();
  1508. // IUnknown
  1509. STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv);
  1510. STDMETHODIMP_(ULONG) AddRef();
  1511. STDMETHODIMP_(ULONG) Release();
  1512. // IShellExtInit
  1513. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdo, HKEY hkeyProgID);
  1514. // IShellPropSheetExt
  1515. STDMETHODIMP AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam);
  1516. STDMETHODIMP ReplacePage(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam)
  1517. { return E_NOTIMPL; }
  1518. private:
  1519. LONG _cRef;
  1520. CUserInfo *_pUserInfo; // The user for the property sheet
  1521. CUsernamePropertyPage *_pUserNamePage; // Basic info page, only shown for local users
  1522. CGroupPropertyPage *_pGroupPage; // The group page, which is common to both local and domain users
  1523. CGroupInfoList _GroupList; // The group list, used by the group page
  1524. };
  1525. CUserPropertyPages::CUserPropertyPages() :
  1526. _cRef(1)
  1527. {
  1528. DllAddRef();
  1529. }
  1530. CUserPropertyPages::~CUserPropertyPages()
  1531. {
  1532. if (_pUserInfo)
  1533. delete _pUserInfo;
  1534. if (_pUserNamePage)
  1535. delete _pUserNamePage;
  1536. if (_pGroupPage)
  1537. delete _pGroupPage;
  1538. DllRelease();
  1539. }
  1540. ULONG CUserPropertyPages::AddRef()
  1541. {
  1542. return InterlockedIncrement(&_cRef);
  1543. }
  1544. ULONG CUserPropertyPages::Release()
  1545. {
  1546. ASSERT( 0 != _cRef );
  1547. ULONG cRef = InterlockedDecrement(&_cRef);
  1548. if ( 0 == cRef )
  1549. {
  1550. delete this;
  1551. }
  1552. return cRef;
  1553. }
  1554. HRESULT CUserPropertyPages::QueryInterface(REFIID riid, LPVOID* ppv)
  1555. {
  1556. static const QITAB qit[] =
  1557. {
  1558. QITABENT(CUserPropertyPages, IShellExtInit), // IID_IShellExtInit
  1559. QITABENT(CUserPropertyPages, IShellPropSheetExt), // IID_IShellPropSheetExt
  1560. {0, 0 },
  1561. };
  1562. return QISearch(this, qit, riid, ppv);
  1563. }
  1564. // IShellExtInit
  1565. HRESULT CUserPropertyPages::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pdo, HKEY hkeyProgID)
  1566. {
  1567. // Request the user's SID from the data object
  1568. FORMATETC fmt = {0};
  1569. fmt.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_USERPROPPAGESSID);
  1570. fmt.dwAspect = DVASPECT_CONTENT;
  1571. fmt.lindex = -1;
  1572. fmt.tymed = TYMED_HGLOBAL;
  1573. STGMEDIUM medium = { 0 };
  1574. HRESULT hr = pdo->GetData(&fmt, &medium);
  1575. if (SUCCEEDED(hr))
  1576. {
  1577. // medium.hGlobal is the user's SID; make sure it isn't null and that
  1578. // we haven't already set our copy of the SID
  1579. if ((medium.hGlobal != NULL) && (_pUserInfo == NULL))
  1580. {
  1581. PSID psid = (PSID) GlobalLock(medium.hGlobal);
  1582. if (IsValidSid(psid))
  1583. {
  1584. // Create a user info structure to party on
  1585. _pUserInfo = new CUserInfo;
  1586. if (_pUserInfo)
  1587. {
  1588. hr = _pUserInfo->Load(psid, TRUE);
  1589. if (SUCCEEDED(hr))
  1590. {
  1591. hr = _GroupList.Initialize(); // Get the groups
  1592. }
  1593. }
  1594. else
  1595. {
  1596. hr = E_OUTOFMEMORY;
  1597. }
  1598. }
  1599. else
  1600. {
  1601. hr = E_INVALIDARG;
  1602. }
  1603. GlobalUnlock(medium.hGlobal);
  1604. }
  1605. else
  1606. {
  1607. hr = E_UNEXPECTED; // hGlobal was NULL or prop sheet was already init'ed
  1608. }
  1609. ReleaseStgMedium(&medium);
  1610. }
  1611. return hr;
  1612. }
  1613. // AddPages - handles adding the property pages
  1614. HRESULT CUserPropertyPages::AddPages(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam)
  1615. {
  1616. PROPSHEETPAGE psp = {0};
  1617. psp.dwSize = sizeof (psp);
  1618. psp.hInstance = g_hinst;
  1619. if (_pUserInfo->m_userType == CUserInfo::LOCALUSER)
  1620. {
  1621. // Add the local user prop pages
  1622. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_USERNAME_PROP_PAGE);
  1623. _pUserNamePage = new CUsernamePropertyPage(_pUserInfo);
  1624. if (_pUserNamePage != NULL)
  1625. {
  1626. _pUserNamePage->SetPropSheetPageMembers(&psp);
  1627. lpfnAddPage(CreatePropertySheetPage(&psp), lParam);
  1628. }
  1629. }
  1630. psp.pszTemplate = MAKEINTRESOURCE(IDD_USR_CHOOSEGROUP_PROP_PAGE);
  1631. _pGroupPage = new CGroupPropertyPage(_pUserInfo, &_GroupList);
  1632. if (_pGroupPage != NULL)
  1633. {
  1634. _pGroupPage->SetPropSheetPageMembers(&psp);
  1635. lpfnAddPage(CreatePropertySheetPage(&psp), lParam);
  1636. }
  1637. return S_OK;
  1638. }
  1639. STDAPI CUserPropertyPages_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  1640. {
  1641. CUserPropertyPages *pupp = new CUserPropertyPages();
  1642. if (!pupp)
  1643. {
  1644. *ppunk = NULL; // incase of failure
  1645. return E_OUTOFMEMORY;
  1646. }
  1647. HRESULT hr = pupp->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  1648. pupp->Release();
  1649. return hr;
  1650. }
  1651. // expose the SID for a user via an IDataObject
  1652. class CUserSidDataObject: public IDataObject
  1653. {
  1654. public:
  1655. CUserSidDataObject();
  1656. ~CUserSidDataObject();
  1657. // IUnknown
  1658. STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppv);
  1659. STDMETHODIMP_(ULONG) AddRef();
  1660. STDMETHODIMP_(ULONG) Release();
  1661. // IDataObject
  1662. STDMETHODIMP GetData(FORMATETC* pFormatEtc, STGMEDIUM* pMedium);
  1663. STDMETHODIMP GetDataHere(FORMATETC* pFormatEtc, STGMEDIUM* pMedium)
  1664. { return E_NOTIMPL; }
  1665. STDMETHODIMP QueryGetData(FORMATETC* pFormatEtc)
  1666. { return E_NOTIMPL; }
  1667. STDMETHODIMP GetCanonicalFormatEtc(FORMATETC* pFormatetcIn, FORMATETC* pFormatetcOut)
  1668. { return E_NOTIMPL; }
  1669. STDMETHODIMP SetData(FORMATETC* pFormatetc, STGMEDIUM* pmedium, BOOL fRelease)
  1670. { return E_NOTIMPL; }
  1671. STDMETHODIMP EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC ** ppenumFormatetc)
  1672. { return E_NOTIMPL; }
  1673. STDMETHODIMP DAdvise(FORMATETC* pFormatetc, DWORD advf, IAdviseSink* pAdvSink, DWORD * pdwConnection)
  1674. { return E_NOTIMPL; }
  1675. STDMETHODIMP DUnadvise(DWORD dwConnection)
  1676. { return E_NOTIMPL; }
  1677. STDMETHODIMP EnumDAdvise(IEnumSTATDATA ** ppenumAdvise)
  1678. { return E_NOTIMPL; }
  1679. HRESULT SetSid(PSID psid);
  1680. private:
  1681. LONG _cRef;
  1682. PSID _psid;
  1683. };
  1684. CUserSidDataObject::CUserSidDataObject() :
  1685. _cRef(1)
  1686. {
  1687. DllAddRef();
  1688. }
  1689. CUserSidDataObject::~CUserSidDataObject()
  1690. {
  1691. if (_psid)
  1692. LocalFree(_psid);
  1693. DllRelease();
  1694. }
  1695. ULONG CUserSidDataObject::AddRef()
  1696. {
  1697. return InterlockedIncrement(&_cRef);
  1698. }
  1699. ULONG CUserSidDataObject::Release()
  1700. {
  1701. ASSERT( 0 != _cRef );
  1702. ULONG cRef = InterlockedDecrement(&_cRef);
  1703. if ( 0 == cRef )
  1704. {
  1705. delete this;
  1706. }
  1707. return cRef;
  1708. }
  1709. HRESULT CUserSidDataObject::QueryInterface(REFIID riid, LPVOID* ppv)
  1710. {
  1711. static const QITAB qit[] =
  1712. {
  1713. QITABENT(CUserSidDataObject, IDataObject), // IID_IDataObject
  1714. {0, 0 },
  1715. };
  1716. return QISearch(this, qit, riid, ppv);
  1717. }
  1718. HRESULT CUserSidDataObject::GetData(FORMATETC* pFormatEtc, STGMEDIUM* pMedium)
  1719. {
  1720. HRESULT hr = QueryGetData(pFormatEtc);
  1721. if (SUCCEEDED(hr))
  1722. {
  1723. pMedium->pUnkForRelease = (IDataObject*)this;
  1724. AddRef(); // reference to ourself
  1725. pMedium->tymed = TYMED_HGLOBAL;
  1726. pMedium->hGlobal = (HGLOBAL)_psid;
  1727. }
  1728. return hr;
  1729. }
  1730. HRESULT CUserSidDataObject::SetSid(PSID psid)
  1731. {
  1732. if (!psid)
  1733. return E_INVALIDARG;
  1734. if (_psid == NULL)
  1735. {
  1736. DWORD cbSid = GetLengthSid(psid);
  1737. _psid = (PSID)LocalAlloc(0, cbSid);
  1738. if (!_psid)
  1739. return E_OUTOFMEMORY;
  1740. if (CopySid(cbSid, _psid, psid))
  1741. return S_OK;
  1742. }
  1743. return E_FAIL;
  1744. }
  1745. STDAPI CUserSidDataObject_CreateInstance(PSID psid, IDataObject **ppdo)
  1746. {
  1747. CUserSidDataObject *pusdo = new CUserSidDataObject();
  1748. if (!pusdo)
  1749. return E_OUTOFMEMORY;
  1750. HRESULT hr = pusdo->SetSid(psid);
  1751. if (SUCCEEDED(hr))
  1752. {
  1753. hr = pusdo->QueryInterface(IID_PPV_ARG(IDataObject, ppdo));
  1754. }
  1755. pusdo->Release();
  1756. return hr;
  1757. }