Source code of Windows XP (NT5)
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.

1097 lines
20 KiB

  1. /*++
  2. Copyright (c) 1994-2001 Microsoft Corporation
  3. Module Name :
  4. usersess.cpp
  5. Abstract:
  6. FTP User Sessions Dialog
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Sergei Antonov (sergeia)
  10. Project:
  11. Internet Services Manager
  12. Revision History:
  13. --*/
  14. //
  15. // Include Files
  16. //
  17. #include "stdafx.h"
  18. #include "resource.h"
  19. #include "common.h"
  20. #include "inetprop.h"
  21. #include "ftpsht.h"
  22. #include "fservic.h"
  23. #include "usersess.h"
  24. #include <lmerr.h>
  25. HRESULT ImpersonateUser(LPCTSTR pszUserName,
  26. LPCTSTR pszDomain,
  27. LPCTSTR pszPassword,
  28. HANDLE *pCurImpToken,
  29. HANDLE *pLoggedOnUserToken);
  30. HRESULT UnImpersonateUser(HANDLE hSavedImpToken,
  31. HANDLE hLoggedOnUser);
  32. #ifdef _DEBUG
  33. #undef THIS_FILE
  34. static char BASED_CODE THIS_FILE[] = __FILE__;
  35. #endif
  36. //
  37. // Registry key name for this dialog
  38. //
  39. const TCHAR g_szRegKey[] = _T("User Sessions");
  40. //
  41. // User Sessions Listbox Column Definitions
  42. //
  43. static const ODL_COLUMN_DEF_EX BASED_CODE g_aColumns[] =
  44. {
  45. // ==================================================================================================
  46. // Weight Label Sort Helper Function
  47. // ==================================================================================================
  48. { 2, IDS_CONNECTED_USERS, (CObjectPlus::PCOBJPLUS_ORDER_FUNC)&CFtpUserInfo::OrderByName },
  49. { 1, IDS_FROM, (CObjectPlus::PCOBJPLUS_ORDER_FUNC)&CFtpUserInfo::OrderByHostAddress },
  50. { 1, IDS_TIME, (CObjectPlus::PCOBJPLUS_ORDER_FUNC)&CFtpUserInfo::OrderByTime },
  51. };
  52. #define NUM_COLUMNS (sizeof(g_aColumns) / sizeof(g_aColumns[0]))
  53. CFtpUserInfo::CFtpUserInfo(LPIIS_USER_INFO_1 lpUserInfo)
  54. /*++
  55. Routine Description:
  56. Constructor
  57. Arguments:
  58. LPIIS_USER_INFO_1 lpUserInfo : User info structure
  59. Return Value:
  60. N/A
  61. --*/
  62. : m_idUser(lpUserInfo->idUser),
  63. m_strUser(lpUserInfo->pszUser),
  64. m_fAnonymous(lpUserInfo->fAnonymous),
  65. // Network Byte Order
  66. // ||
  67. // \/
  68. m_iaHost(lpUserInfo->inetHost, TRUE),
  69. m_tConnect(lpUserInfo->tConnect)
  70. {
  71. }
  72. int
  73. CFtpUserInfo::OrderByName(
  74. const CObjectPlus * pobFtpUser
  75. ) const
  76. /*++
  77. Routine Description:
  78. Sorting helper function to sort by user name. The CObjectPlus pointer
  79. really refers to another CFtpUserInfo object
  80. Arguments:
  81. LPIIS_USER_INFO_1 lpUserInfo : User info structure
  82. Return Value:
  83. Sort return code (-1, 0, +1)
  84. --*/
  85. {
  86. const CFtpUserInfo * pob = (CFtpUserInfo *)pobFtpUser;
  87. ASSERT(pob != NULL);
  88. return ::lstrcmpi(QueryUserName(), pob->QueryUserName());
  89. }
  90. int
  91. CFtpUserInfo::OrderByTime(
  92. const CObjectPlus * pobFtpUser
  93. ) const
  94. /*++
  95. Routine Description:
  96. Sorting helper function to sort by user connect time. The CObjectPlus
  97. pointer really refers to another CFtpUserInfo object
  98. Arguments:
  99. LPIIS_USER_INFO_1 lpUserInfo : User info structure
  100. Return Value:
  101. Sort return code (-1, 0, +1)
  102. --*/
  103. {
  104. const CFtpUserInfo * pob = (CFtpUserInfo *)pobFtpUser;
  105. ASSERT(pob != NULL);
  106. return QueryConnectTime() > pob->QueryConnectTime()
  107. ? +1
  108. : QueryConnectTime() == pob->QueryConnectTime()
  109. ? 0
  110. : -1;
  111. }
  112. int
  113. CFtpUserInfo::OrderByHostAddress(
  114. const CObjectPlus * pobFtpUser
  115. ) const
  116. /*++
  117. Routine Description:
  118. Sorting helper function to sort by host address. The CObjectPlus
  119. pointer really refers to another CFtpUserInfo object
  120. Arguments:
  121. LPIIS_USER_INFO_1 lpUserInfo : User info structure
  122. Return Value:
  123. Sort return code (-1, 0, +1)
  124. --*/
  125. {
  126. const CFtpUserInfo * pob = (CFtpUserInfo *)pobFtpUser;
  127. ASSERT(pob != NULL);
  128. return QueryHostAddress().CompareItem(pob->QueryHostAddress());
  129. }
  130. IMPLEMENT_DYNAMIC(CFtpUsersListBox, CHeaderListBox);
  131. //
  132. // User listbox bitmaps
  133. //
  134. enum
  135. {
  136. BMP_USER = 0,
  137. BMP_ANONYMOUS,
  138. //
  139. // Don't move this one
  140. //
  141. BMP_TOTAL
  142. };
  143. const int CFtpUsersListBox::nBitmaps = BMP_TOTAL;
  144. CFtpUsersListBox::CFtpUsersListBox()
  145. : m_strTimeSep(_T(":")),
  146. CHeaderListBox(HLS_DEFAULT, g_szRegKey)
  147. {
  148. //
  149. // Get intl time seperator
  150. //
  151. VERIFY(::GetLocaleInfo(
  152. ::GetUserDefaultLCID(), LOCALE_STIME,
  153. m_strTimeSep.GetBuffer(10), 10));
  154. }
  155. void
  156. CFtpUsersListBox::DrawItemEx(
  157. IN CRMCListBoxDrawStruct & ds
  158. )
  159. /*++
  160. Routine Description:
  161. Draw item. This is called from the CRMCListBox base class
  162. Arguments:
  163. CRMCListBoxDrawStruct & ds : Drawing structure
  164. Return Value:
  165. None
  166. --*/
  167. {
  168. CFtpUserInfo * pFTPUser = (CFtpUserInfo *)ds.m_ItemData;
  169. ASSERT(pFTPUser != NULL);
  170. //
  171. // Display a user bitmap
  172. //
  173. DrawBitmap(ds, 0, pFTPUser->QueryAnonymous() ? BMP_ANONYMOUS : BMP_USER);
  174. ColumnText(ds, 0, TRUE, pFTPUser->QueryUserName());
  175. ColumnText(ds, 1, FALSE, pFTPUser->QueryHostAddress());
  176. DWORD dwTime = pFTPUser->QueryConnectTime();
  177. DWORD dwHours = dwTime / (60L * 60L);
  178. DWORD dwMinutes = (dwTime / 60L) % 60L;
  179. DWORD dwSeconds = dwTime % 60L;
  180. CString strTime;
  181. strTime.Format(
  182. _T("%d%s%02d%s%02d"),
  183. dwHours, (LPCTSTR)m_strTimeSep,
  184. dwMinutes, (LPCTSTR)m_strTimeSep,
  185. dwSeconds);
  186. ColumnText(ds, 2, FALSE, strTime);
  187. }
  188. /* virtual */
  189. BOOL
  190. CFtpUsersListBox::Initialize()
  191. /*++
  192. Routine Description:
  193. Initialize the listbox. Insert the columns as requested, and lay
  194. them out appropriately
  195. Arguments:
  196. None
  197. Return Value:
  198. TRUE for succesful initialisation, FALSE otherwise
  199. --*/
  200. {
  201. if (!CHeaderListBox::Initialize())
  202. {
  203. return FALSE;
  204. }
  205. //
  206. // Build all columns
  207. //
  208. HINSTANCE hInst = AfxGetResourceHandle();
  209. for (int nCol = 0; nCol < NUM_COLUMNS; ++nCol)
  210. {
  211. InsertColumn(
  212. nCol,
  213. g_aColumns[nCol].cd.nWeight,
  214. g_aColumns[nCol].cd.nLabelID,
  215. hInst
  216. );
  217. }
  218. //
  219. // Try to set the widths from the stored registry value,
  220. // otherwise distribute according to column weights specified
  221. //
  222. // if (!SetWidthsFromReg())
  223. // {
  224. DistributeColumns();
  225. // }
  226. return TRUE;
  227. }
  228. CUserSessionsDlg::CUserSessionsDlg(
  229. LPCTSTR lpstrServerName,
  230. DWORD dwInstance,
  231. LPCTSTR pAdminName,
  232. LPCTSTR pAdminPassword,
  233. CWnd * pParent
  234. )
  235. /*++
  236. Routine Description:
  237. Constructor for FTP user sessions dialog
  238. Arguments:
  239. LPCTSTR lpstrServerName : Server name to connect to
  240. CWnd * pParent : Pointer to parent window
  241. Return Value:
  242. N/A
  243. --*/
  244. : m_list_Users(),
  245. m_ListBoxRes(IDB_USERS, m_list_Users.nBitmaps),
  246. m_oblFtpUsers(),
  247. m_strServerName(lpstrServerName),
  248. m_strAdminName(pAdminName),
  249. m_strAdminPassword(pAdminPassword),
  250. m_nSortColumn(0),
  251. m_dwInstance(dwInstance),
  252. m_hImpToken(INVALID_HANDLE_VALUE),
  253. m_hLogToken(INVALID_HANDLE_VALUE),
  254. CDialog(CUserSessionsDlg::IDD, pParent)
  255. {
  256. //{{AFX_DATA_INIT(CUserSessionsDlg)
  257. //}}AFX_DATA_INIT
  258. m_list_Users.AttachResources(&m_ListBoxRes);
  259. VERIFY(m_strTotalConnected.LoadString(IDS_USERS_TOTAL));
  260. }
  261. void
  262. CUserSessionsDlg::DoDataExchange(CDataExchange * pDX)
  263. {
  264. CDialog::DoDataExchange(pDX);
  265. //{{AFX_DATA_MAP(CUserSessionsDlg)
  266. DDX_Control(pDX, IDC_STATIC_NUM_CONNECTED, m_static_Total);
  267. DDX_Control(pDX, IDC_BUTTON_DISCONNECT_ALL, m_button_DisconnectAll);
  268. DDX_Control(pDX, IDC_BUTTON_DISCONNECT, m_button_Disconnect);
  269. //}}AFX_DATA_MAP
  270. DDX_Control(pDX, IDC_LIST_USERS, m_list_Users);
  271. }
  272. //
  273. // Message Map
  274. //
  275. BEGIN_MESSAGE_MAP(CUserSessionsDlg, CDialog)
  276. //{{AFX_MSG_MAP(CUserSessionsDlg)
  277. ON_BN_CLICKED(IDC_BUTTON_DISCONNECT, OnButtonDisconnect)
  278. ON_BN_CLICKED(IDC_BUTTON_DISCONNECT_ALL, OnButtonDisconnectAll)
  279. ON_BN_CLICKED(IDC_BUTTON_REFRESH, OnButtonRefresh)
  280. ON_LBN_SELCHANGE(IDC_LIST_USERS, OnSelchangeListUsers)
  281. //}}AFX_MSG_MAP
  282. ON_NOTIFY_RANGE(HDN_ITEMCLICK, 0, 0xFFFF, OnHeaderItemClick)
  283. END_MESSAGE_MAP()
  284. DWORD
  285. CUserSessionsDlg::SortUsersList()
  286. /*++
  287. Routine Description:
  288. Sort the list of ftp users on the current sorting key
  289. Arguments:
  290. None
  291. Return Value:
  292. ERROR return code
  293. --*/
  294. {
  295. ASSERT(m_nSortColumn >= 0 && m_nSortColumn < NUM_COLUMNS);
  296. BeginWaitCursor();
  297. DWORD err = m_oblFtpUsers.Sort(
  298. (CObjectPlus::PCOBJPLUS_ORDER_FUNC)g_aColumns[m_nSortColumn].pSortFn);
  299. EndWaitCursor();
  300. return err;
  301. }
  302. HRESULT
  303. CUserSessionsDlg::BuildUserList()
  304. /*++
  305. Routine Description:
  306. Call the FtpEnum api and build the list of currently connected users.
  307. Arguments:
  308. None
  309. Return Value:
  310. ERROR return code
  311. --*/
  312. {
  313. CError err;
  314. LPIIS_USER_INFO_1 lpUserInfo = NULL;
  315. DWORD dwCount = 0L;
  316. m_oblFtpUsers.RemoveAll();
  317. BeginWaitCursor();
  318. err = ::IISEnumerateUsers(
  319. (LPTSTR)(LPCTSTR)m_strServerName,
  320. 1,
  321. INET_FTP_SVC_ID,
  322. m_dwInstance,
  323. &dwCount,
  324. (LPBYTE *)&lpUserInfo
  325. );
  326. EndWaitCursor();
  327. TRACEEOLID("IISEnumerateUsers returned " << err);
  328. if (err.Failed())
  329. {
  330. return err;
  331. }
  332. try
  333. {
  334. for (DWORD i = 0; i < dwCount; ++i)
  335. {
  336. m_oblFtpUsers.AddTail(new CFtpUserInfo(lpUserInfo++));
  337. }
  338. }
  339. catch(CMemoryException * e)
  340. {
  341. err = ERROR_NOT_ENOUGH_MEMORY;
  342. e->Delete();
  343. }
  344. SortUsersList();
  345. return err;
  346. }
  347. HRESULT
  348. CUserSessionsDlg::DisconnectUser(CFtpUserInfo * pUserInfo)
  349. /*++
  350. Routine Description:
  351. Disconnect a single user
  352. Arguments:
  353. CFtpUserInfo * pUserInfo : User to disconnect
  354. Return Value:
  355. ERROR return code
  356. --*/
  357. {
  358. CError err(::IISDisconnectUser(
  359. (LPTSTR)(LPCTSTR)m_strServerName,
  360. INET_FTP_SVC_ID,
  361. m_dwInstance,
  362. pUserInfo->QueryUserID()
  363. ));
  364. if (err.Win32Error() == NERR_UserNotFound)
  365. {
  366. //
  367. // As long as he's gone now, that's alright
  368. //
  369. err.Reset();
  370. }
  371. return err;
  372. }
  373. void
  374. CUserSessionsDlg::UpdateTotalCount()
  375. /*++
  376. Routine Description:
  377. Update the count of total users
  378. Arguments:
  379. None
  380. Return Value:
  381. None
  382. --*/
  383. {
  384. CString str;
  385. str.Format(m_strTotalConnected, m_oblFtpUsers.GetCount() );
  386. m_static_Total.SetWindowText(str);
  387. }
  388. void
  389. CUserSessionsDlg::FillListBox(CFtpUserInfo * pSelection)
  390. /*++
  391. Routine Description:
  392. Show the users in the listbox
  393. Arguments:
  394. CFtpUserInfo * pSelection : Item to be selected or NULL
  395. Return Value:
  396. None
  397. --*/
  398. {
  399. CObListIter obli(m_oblFtpUsers);
  400. const CFtpUserInfo * pUserEntry = NULL;
  401. m_list_Users.SetRedraw(FALSE);
  402. m_list_Users.ResetContent();
  403. int cItems = 0;
  404. for ( /**/ ; pUserEntry = (CFtpUserInfo *)obli.Next(); ++cItems)
  405. {
  406. m_list_Users.AddItem(pUserEntry);
  407. }
  408. if (pSelection)
  409. {
  410. //
  411. // Select the desired entry
  412. //
  413. m_list_Users.SelectItem(pSelection);
  414. }
  415. m_list_Users.SetRedraw(TRUE);
  416. //
  417. // Update the count text on the dialog
  418. //
  419. UpdateTotalCount();
  420. }
  421. HRESULT
  422. CUserSessionsDlg::RefreshUsersList()
  423. /*++
  424. Routine Description:
  425. Rebuild the user list
  426. Arguments:
  427. None
  428. Return Value:
  429. Error return code
  430. --*/
  431. {
  432. CError err;
  433. //
  434. // Add some friendly error message overrides
  435. //
  436. err.AddOverride(EPT_S_NOT_REGISTERED, IDS_ERR_RPC_NA);
  437. err.AddOverride(RPC_S_SERVER_UNAVAILABLE, IDS_FTP_SERVICE_NOT_STARTED);
  438. err.AddOverride(RPC_S_UNKNOWN_IF, IDS_FTP_SERVICE_NOT_STARTED);
  439. err.AddOverride(RPC_S_PROCNUM_OUT_OF_RANGE, IDS_ERR_INTERFACE);
  440. err = BuildUserList();
  441. if (!err.MessageBoxOnFailure())
  442. {
  443. FillListBox();
  444. SetControlStates();
  445. }
  446. return err;
  447. }
  448. void
  449. CUserSessionsDlg::SetControlStates()
  450. /*++
  451. Routine Description:
  452. Set the connect/disconnect buttons depending on the selection state
  453. in the listbox.
  454. Arguments:
  455. None
  456. Return Value:
  457. None
  458. --*/
  459. {
  460. m_button_Disconnect.EnableWindow(m_list_Users.GetSelCount() > 0);
  461. m_button_DisconnectAll.EnableWindow(m_list_Users.GetCount() > 0);
  462. }
  463. //
  464. // Message Handlers
  465. //
  466. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  467. void
  468. CUserSessionsDlg::OnButtonDisconnect()
  469. /*++
  470. Routine Description:
  471. 'Disconnect User' button has been pressed. Disconnect the currently
  472. selected user.
  473. Arguments:
  474. None
  475. Return Value:
  476. None
  477. --*/
  478. {
  479. //
  480. // Ask for confirmation
  481. //
  482. if (!NoYesMessageBox(IDS_CONFIRM_DISCONNECT_USER))
  483. {
  484. //
  485. // Changed his mind
  486. //
  487. return;
  488. }
  489. CError err;
  490. m_list_Users.SetRedraw(FALSE);
  491. CWaitCursor wait;
  492. CFtpUserInfo * pUserEntry;
  493. int nSel = 0;
  494. BOOL fProblems = FALSE;
  495. while((pUserEntry = GetNextSelectedItem(&nSel)) != NULL)
  496. {
  497. err = DisconnectUser(pUserEntry);
  498. if (err.Failed())
  499. {
  500. ++fProblems;
  501. if (err.MessageBoxFormat(
  502. IDS_DISCONNECT_ERR,
  503. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2,
  504. NO_HELP_CONTEXT,
  505. (LPCTSTR)pUserEntry->QueryUserName()
  506. ) == IDYES)
  507. {
  508. //
  509. // Continue trying to delete
  510. //
  511. ++nSel;
  512. continue;
  513. }
  514. else
  515. {
  516. break;
  517. }
  518. }
  519. m_oblFtpUsers.RemoveIndex(nSel);
  520. m_list_Users.DeleteString(nSel);
  521. //
  522. // Don't advance counter to account for offset
  523. //
  524. }
  525. m_list_Users.SetRedraw(TRUE);
  526. UpdateTotalCount();
  527. SetControlStates();
  528. if (!fProblems)
  529. {
  530. //
  531. // Ensure button not disabled
  532. //
  533. GetDlgItem(IDC_BUTTON_REFRESH)->SetFocus();
  534. }
  535. }
  536. void
  537. CUserSessionsDlg::OnButtonDisconnectAll()
  538. /*++
  539. Routine Description:
  540. 'Disconnect All Users' button has been pressed. Disconnect all users
  541. Arguments:
  542. None
  543. Return Value:
  544. None
  545. --*/
  546. {
  547. //
  548. // Ask for confirmation
  549. //
  550. if (!NoYesMessageBox(IDS_CONFIRM_DISCONNECT_ALL))
  551. {
  552. //
  553. // Changed his mind
  554. //
  555. return;
  556. }
  557. CObListIter obli(m_oblFtpUsers);
  558. CFtpUserInfo * pUserEntry;
  559. m_list_Users.SetRedraw(FALSE);
  560. CWaitCursor wait;
  561. int cItems = 0;
  562. CError err;
  563. int nSel = 0;
  564. BOOL fProblems = FALSE;
  565. for ( /**/; pUserEntry = (CFtpUserInfo *)obli.Next(); ++cItems)
  566. {
  567. err = DisconnectUser(pUserEntry);
  568. if (err.Failed())
  569. {
  570. ++fProblems;
  571. if (err.MessageBoxFormat(
  572. IDS_DISCONNECT_ERR,
  573. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2,
  574. NO_HELP_CONTEXT,
  575. (LPCTSTR)pUserEntry->QueryUserName()
  576. ) == IDYES)
  577. {
  578. //
  579. // Continue trying to delete
  580. //
  581. ++nSel;
  582. continue;
  583. }
  584. else
  585. {
  586. break;
  587. }
  588. }
  589. m_oblFtpUsers.RemoveIndex(nSel);
  590. m_list_Users.DeleteString(nSel);
  591. }
  592. m_list_Users.SetRedraw(TRUE);
  593. UpdateTotalCount();
  594. SetControlStates();
  595. if (!fProblems)
  596. {
  597. //
  598. // Ensure button not disabled
  599. //
  600. GetDlgItem(IDC_BUTTON_REFRESH)->SetFocus();
  601. }
  602. }
  603. void
  604. CUserSessionsDlg::OnButtonRefresh()
  605. /*++
  606. Routine Description:
  607. 'Refresh' Button has been pressed. Refresh the user list
  608. Arguments:
  609. None
  610. Return Value:
  611. None
  612. --*/
  613. {
  614. RefreshUsersList();
  615. }
  616. void
  617. CUserSessionsDlg::OnSelchangeListUsers()
  618. /*++
  619. Routine Description:
  620. Respond to a change in selection in the user listbox
  621. Arguments:
  622. None
  623. Return Value:
  624. None
  625. --*/
  626. {
  627. SetControlStates();
  628. }
  629. void
  630. CUserSessionsDlg::OnHeaderItemClick(
  631. IN UINT nID,
  632. IN NMHDR * pNMHDR,
  633. OUT LRESULT * plResult
  634. )
  635. /*++
  636. Routine Description:
  637. Header item has been clicked in the listbox. Change the sort key
  638. as appropriate.
  639. Arguments:
  640. None
  641. Return Value:
  642. None
  643. --*/
  644. {
  645. HD_NOTIFY * pNotify = (HD_NOTIFY *)pNMHDR;
  646. TRACEEOLID("Header Button clicked.");
  647. //
  648. // Can't press a button out of range, surely...
  649. //
  650. ASSERT(pNotify->iItem < m_list_Users.QueryNumColumns());
  651. int nOldSortColumn = m_nSortColumn;
  652. m_nSortColumn = pNotify->iItem;
  653. if(m_nSortColumn != nOldSortColumn)
  654. {
  655. //
  656. // Rebuild the list
  657. //
  658. SortUsersList();
  659. CFtpUserInfo * pSelector = GetSelectedListItem();
  660. FillListBox(pSelector);
  661. SetControlStates();
  662. }
  663. //
  664. // Message Fully Handled
  665. //
  666. *plResult = 0;
  667. }
  668. BOOL
  669. CUserSessionsDlg::OnInitDialog()
  670. /*++
  671. Routine Description:
  672. WM_INITDIALOG handler. Initialize the dialog.
  673. Arguments:
  674. None.
  675. Return Value:
  676. TRUE if no focus is to be set automatically, FALSE if the focus
  677. is already set.
  678. --*/
  679. {
  680. CDialog::OnInitDialog();
  681. if (!m_strAdminName.IsEmpty())
  682. {
  683. CError err = ImpersonateUser(m_strAdminName, _T(""), m_strAdminPassword, &m_hImpToken, &m_hLogToken);
  684. }
  685. m_list_Users.Initialize();
  686. if (RefreshUsersList() != ERROR_SUCCESS)
  687. {
  688. EndDialog(IDCANCEL);
  689. return FALSE;
  690. }
  691. return TRUE;
  692. }
  693. void
  694. CUserSessionsDlg::OnDestroy()
  695. {
  696. if (m_hImpToken != INVALID_HANDLE_VALUE || m_hLogToken != INVALID_HANDLE_VALUE)
  697. {
  698. UnImpersonateUser(m_hImpToken, m_hLogToken);
  699. }
  700. }
  701. HRESULT ImpersonateUser(LPCTSTR pszUserName,
  702. LPCTSTR pszDomain,
  703. LPCTSTR pszPassword,
  704. HANDLE *pCurImpToken,
  705. HANDLE *pLoggedOnUserToken)
  706. {
  707. HRESULT hr = S_OK;
  708. ASSERT(pCurImpToken);
  709. ASSERT(pLoggedOnUserToken);
  710. *pCurImpToken = INVALID_HANDLE_VALUE;
  711. *pLoggedOnUserToken = INVALID_HANDLE_VALUE;
  712. // logon the user. This creates an primary impersonation
  713. // token. If this fails, an error will be returned.
  714. if (!LogonUser((LPTSTR)pszUserName,
  715. (LPTSTR)pszDomain,
  716. (LPTSTR)pszPassword,
  717. LOGON32_LOGON_BATCH,
  718. LOGON32_PROVIDER_DEFAULT,
  719. pLoggedOnUserToken)) {
  720. hr = HRESULT_FROM_WIN32(GetLastError());
  721. }
  722. // get the current impersonation token. If an error occurs,
  723. // that is OK. This just means that no impersonation on the
  724. // thread is occurring, so there is no need to do the RevertToSelf.
  725. else if (OpenThreadToken( GetCurrentThread(),
  726. TOKEN_READ | TOKEN_IMPERSONATE,
  727. TRUE,
  728. pCurImpToken)) {
  729. RevertToSelf();
  730. }
  731. // if everything's been successful so far, than call
  732. // ImpersonateLoggedOnUser with the token created above.
  733. if (SUCCEEDED(hr)) {
  734. if (!ImpersonateLoggedOnUser(*pLoggedOnUserToken)) {
  735. hr = HRESULT_FROM_WIN32(GetLastError());
  736. }
  737. }
  738. // if there were failures, clean up any tokens that we created
  739. // or hold.
  740. if (FAILED(hr)) {
  741. // cleanup the LogonUser token
  742. if (*pLoggedOnUserToken != INVALID_HANDLE_VALUE) {
  743. CloseHandle(*pLoggedOnUserToken);
  744. *pLoggedOnUserToken = INVALID_HANDLE_VALUE;
  745. }
  746. // cleanup the token from the OpenThreadToken call
  747. if (*pCurImpToken != INVALID_HANDLE_VALUE) {
  748. HANDLE hThread = GetCurrentThread();
  749. SetThreadToken(&hThread,
  750. *pCurImpToken);
  751. CloseHandle(*pCurImpToken);
  752. *pCurImpToken = INVALID_HANDLE_VALUE;
  753. }
  754. }
  755. return hr;
  756. }
  757. HRESULT UnImpersonateUser(HANDLE hSavedImpToken, HANDLE hLoggedOnUser)
  758. {
  759. // if there is an hSavedImpToken, then call SetThreadToken to
  760. // restore it.
  761. if (hSavedImpToken != INVALID_HANDLE_VALUE)
  762. {
  763. HANDLE hThread = GetCurrentThread();
  764. SetThreadToken(&hThread, hSavedImpToken);
  765. CloseHandle(hSavedImpToken);
  766. }
  767. // cleanup the LogonUser token
  768. if (hLoggedOnUser != INVALID_HANDLE_VALUE)
  769. {
  770. CloseHandle(hLoggedOnUser);
  771. }
  772. return S_OK;
  773. }