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.

1208 lines
24 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. BOOL fLocal
  235. )
  236. /*++
  237. Routine Description:
  238. Constructor for FTP user sessions dialog
  239. Arguments:
  240. LPCTSTR lpstrServerName : Server name to connect to
  241. CWnd * pParent : Pointer to parent window
  242. Return Value:
  243. N/A
  244. --*/
  245. : m_list_Users(),
  246. m_ListBoxRes(IDB_USERS, m_list_Users.nBitmaps),
  247. m_oblFtpUsers(),
  248. m_strServerName(lpstrServerName),
  249. m_strAdminName(pAdminName),
  250. m_strAdminPassword(pAdminPassword),
  251. m_nSortColumn(0),
  252. m_dwInstance(dwInstance),
  253. m_hImpToken(INVALID_HANDLE_VALUE),
  254. m_hLogToken(INVALID_HANDLE_VALUE),
  255. m_NetUseSessionCreated(FALSE),
  256. m_fLocal(fLocal),
  257. CDialog(CUserSessionsDlg::IDD, pParent)
  258. {
  259. //{{AFX_DATA_INIT(CUserSessionsDlg)
  260. //}}AFX_DATA_INIT
  261. m_list_Users.AttachResources(&m_ListBoxRes);
  262. VERIFY(m_strTotalConnected.LoadString(IDS_USERS_TOTAL));
  263. }
  264. void
  265. CUserSessionsDlg::DoDataExchange(CDataExchange * pDX)
  266. {
  267. CDialog::DoDataExchange(pDX);
  268. //{{AFX_DATA_MAP(CUserSessionsDlg)
  269. DDX_Control(pDX, IDC_STATIC_NUM_CONNECTED, m_static_Total);
  270. DDX_Control(pDX, IDC_BUTTON_DISCONNECT_ALL, m_button_DisconnectAll);
  271. DDX_Control(pDX, IDC_BUTTON_DISCONNECT, m_button_Disconnect);
  272. //}}AFX_DATA_MAP
  273. DDX_Control(pDX, IDC_LIST_USERS, m_list_Users);
  274. }
  275. //
  276. // Message Map
  277. //
  278. BEGIN_MESSAGE_MAP(CUserSessionsDlg, CDialog)
  279. //{{AFX_MSG_MAP(CUserSessionsDlg)
  280. ON_BN_CLICKED(IDC_BUTTON_DISCONNECT, OnButtonDisconnect)
  281. ON_BN_CLICKED(IDC_BUTTON_DISCONNECT_ALL, OnButtonDisconnectAll)
  282. ON_BN_CLICKED(IDC_BUTTON_REFRESH, OnButtonRefresh)
  283. ON_LBN_SELCHANGE(IDC_LIST_USERS, OnSelchangeListUsers)
  284. //}}AFX_MSG_MAP
  285. ON_NOTIFY_RANGE(HDN_ITEMCLICK, 0, 0xFFFF, OnHeaderItemClick)
  286. END_MESSAGE_MAP()
  287. DWORD
  288. CUserSessionsDlg::SortUsersList()
  289. /*++
  290. Routine Description:
  291. Sort the list of ftp users on the current sorting key
  292. Arguments:
  293. None
  294. Return Value:
  295. ERROR return code
  296. --*/
  297. {
  298. ASSERT(m_nSortColumn >= 0 && m_nSortColumn < NUM_COLUMNS);
  299. BeginWaitCursor();
  300. DWORD err = m_oblFtpUsers.Sort(
  301. (CObjectPlus::PCOBJPLUS_ORDER_FUNC)g_aColumns[m_nSortColumn].pSortFn);
  302. EndWaitCursor();
  303. return err;
  304. }
  305. HRESULT
  306. CUserSessionsDlg::ConnectToComputer()
  307. {
  308. CError err;
  309. DWORD rc;
  310. BOOL already_connected = FALSE;
  311. CString server, user, password;
  312. server = m_strServerName;
  313. // check if lpMachineName starts with \\
  314. // if it doesn't then make sure it does, or it's null (for local machine)
  315. server = _T("\\\\");
  316. server += PURE_COMPUTER_NAME((LPCTSTR) m_strServerName);
  317. user = m_strAdminName;
  318. password = m_strAdminPassword;
  319. //
  320. // As it turned out in some cases we cannot get access to file system
  321. // even if we are connected to metabase. We will add connection in this
  322. // case also.
  323. //
  324. if (!m_fLocal)
  325. {
  326. BOOL bEmptyPassword = FALSE;
  327. // Add use for this resource
  328. NETRESOURCE nr;
  329. nr.dwType = RESOURCETYPE_DISK;
  330. nr.lpLocalName = NULL;
  331. nr.lpRemoteName = (LPTSTR)(LPCTSTR)server;
  332. nr.lpProvider = NULL;
  333. // We need to close connections that we may have to this resource
  334. rc = WNetCancelConnection2((LPTSTR)(LPCTSTR)server, 0, TRUE);
  335. if (rc == ERROR_OPEN_FILES)
  336. {
  337. already_connected = TRUE;
  338. }
  339. // Empty strings below mean no password, which is wrong. NULLs mean
  340. // default user and default password -- this could work better for local case.
  341. LPCTSTR p1 = password, p2 = user;
  342. // In case when password is really was set empty, passing NULL will fail.
  343. if (password.IsEmpty() && !bEmptyPassword)
  344. {
  345. p1 = NULL;
  346. }
  347. if (user.IsEmpty())
  348. {
  349. p2 = NULL;
  350. }
  351. if (!already_connected)
  352. {
  353. rc = WNetAddConnection2(&nr, p1, p2, 0);
  354. if (NO_ERROR != rc)
  355. {
  356. err = rc;
  357. return err;
  358. }
  359. m_NetUseSessionCreated = TRUE;
  360. }
  361. }
  362. return err;
  363. }
  364. HRESULT
  365. CUserSessionsDlg::BuildUserList()
  366. /*++
  367. Routine Description:
  368. Call the FtpEnum api and build the list of currently connected users.
  369. Arguments:
  370. None
  371. Return Value:
  372. ERROR return code
  373. --*/
  374. {
  375. CError err;
  376. LPIIS_USER_INFO_1 lpUserInfo = NULL;
  377. DWORD dwCount = 0L;
  378. m_oblFtpUsers.RemoveAll();
  379. BeginWaitCursor();
  380. err = ::IISEnumerateUsers(
  381. (LPTSTR)(LPCTSTR)m_strServerName,
  382. 1,
  383. INET_FTP_SVC_ID,
  384. m_dwInstance,
  385. &dwCount,
  386. (LPBYTE *)&lpUserInfo
  387. );
  388. EndWaitCursor();
  389. TRACEEOLID("IISEnumerateUsers returned " << err);
  390. if (err.Failed())
  391. {
  392. // try to net use to the machine if this failed...
  393. if (ERROR_ACCESS_DENIED == err.Win32Error())
  394. {
  395. err = ConnectToComputer();
  396. // try again.
  397. BeginWaitCursor();
  398. err = ::IISEnumerateUsers(
  399. (LPTSTR)(LPCTSTR)m_strServerName,
  400. 1,
  401. INET_FTP_SVC_ID,
  402. m_dwInstance,
  403. &dwCount,
  404. (LPBYTE *)&lpUserInfo
  405. );
  406. EndWaitCursor();
  407. if (err.Failed())
  408. {
  409. return err;
  410. }
  411. }
  412. else
  413. {
  414. return err;
  415. }
  416. }
  417. try
  418. {
  419. for (DWORD i = 0; i < dwCount; ++i)
  420. {
  421. m_oblFtpUsers.AddTail(new CFtpUserInfo(lpUserInfo++));
  422. }
  423. }
  424. catch(CMemoryException * e)
  425. {
  426. err = ERROR_NOT_ENOUGH_MEMORY;
  427. e->Delete();
  428. }
  429. SortUsersList();
  430. return err;
  431. }
  432. HRESULT
  433. CUserSessionsDlg::DisconnectUser(CFtpUserInfo * pUserInfo)
  434. /*++
  435. Routine Description:
  436. Disconnect a single user
  437. Arguments:
  438. CFtpUserInfo * pUserInfo : User to disconnect
  439. Return Value:
  440. ERROR return code
  441. --*/
  442. {
  443. CError err(::IISDisconnectUser(
  444. (LPTSTR)(LPCTSTR)m_strServerName,
  445. INET_FTP_SVC_ID,
  446. m_dwInstance,
  447. pUserInfo->QueryUserID()
  448. ));
  449. if (err.Win32Error() == NERR_UserNotFound)
  450. {
  451. //
  452. // As long as he's gone now, that's alright
  453. //
  454. err.Reset();
  455. }
  456. return err;
  457. }
  458. void
  459. CUserSessionsDlg::UpdateTotalCount()
  460. /*++
  461. Routine Description:
  462. Update the count of total users
  463. Arguments:
  464. None
  465. Return Value:
  466. None
  467. --*/
  468. {
  469. CString str;
  470. str.Format(m_strTotalConnected, m_oblFtpUsers.GetCount() );
  471. m_static_Total.SetWindowText(str);
  472. }
  473. void
  474. CUserSessionsDlg::FillListBox(CFtpUserInfo * pSelection)
  475. /*++
  476. Routine Description:
  477. Show the users in the listbox
  478. Arguments:
  479. CFtpUserInfo * pSelection : Item to be selected or NULL
  480. Return Value:
  481. None
  482. --*/
  483. {
  484. CObListIter obli(m_oblFtpUsers);
  485. const CFtpUserInfo * pUserEntry = NULL;
  486. m_list_Users.SetRedraw(FALSE);
  487. m_list_Users.ResetContent();
  488. int cItems = 0;
  489. for ( /**/ ; pUserEntry = (CFtpUserInfo *)obli.Next(); ++cItems)
  490. {
  491. m_list_Users.AddItem(pUserEntry);
  492. }
  493. if (pSelection)
  494. {
  495. //
  496. // Select the desired entry
  497. //
  498. m_list_Users.SelectItem(pSelection);
  499. }
  500. m_list_Users.SetRedraw(TRUE);
  501. //
  502. // Update the count text on the dialog
  503. //
  504. UpdateTotalCount();
  505. }
  506. HRESULT
  507. CUserSessionsDlg::RefreshUsersList()
  508. /*++
  509. Routine Description:
  510. Rebuild the user list
  511. Arguments:
  512. None
  513. Return Value:
  514. Error return code
  515. --*/
  516. {
  517. CError err;
  518. //
  519. // Add some friendly error message overrides
  520. //
  521. err.AddOverride(EPT_S_NOT_REGISTERED, IDS_ERR_RPC_NA);
  522. err.AddOverride(RPC_S_SERVER_UNAVAILABLE, IDS_FTP_SERVICE_NOT_STARTED);
  523. err.AddOverride(RPC_S_UNKNOWN_IF, IDS_FTP_SERVICE_NOT_STARTED);
  524. err.AddOverride(RPC_S_PROCNUM_OUT_OF_RANGE, IDS_ERR_INTERFACE);
  525. err = BuildUserList();
  526. if (!err.MessageBoxOnFailure(m_hWnd))
  527. {
  528. FillListBox();
  529. SetControlStates();
  530. }
  531. return err;
  532. }
  533. void
  534. CUserSessionsDlg::SetControlStates()
  535. /*++
  536. Routine Description:
  537. Set the connect/disconnect buttons depending on the selection state
  538. in the listbox.
  539. Arguments:
  540. None
  541. Return Value:
  542. None
  543. --*/
  544. {
  545. m_button_Disconnect.EnableWindow(m_list_Users.GetSelCount() > 0);
  546. m_button_DisconnectAll.EnableWindow(m_list_Users.GetCount() > 0);
  547. }
  548. //
  549. // Message Handlers
  550. //
  551. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  552. void
  553. CUserSessionsDlg::OnButtonDisconnect()
  554. /*++
  555. Routine Description:
  556. 'Disconnect User' button has been pressed. Disconnect the currently
  557. selected user.
  558. Arguments:
  559. None
  560. Return Value:
  561. None
  562. --*/
  563. {
  564. //
  565. // Ask for confirmation
  566. //
  567. if (!NoYesMessageBox(IDS_CONFIRM_DISCONNECT_USER))
  568. {
  569. //
  570. // Changed his mind
  571. //
  572. return;
  573. }
  574. CError err;
  575. m_list_Users.SetRedraw(FALSE);
  576. CWaitCursor wait;
  577. CFtpUserInfo * pUserEntry;
  578. int nSel = 0;
  579. BOOL fProblems = FALSE;
  580. while((pUserEntry = GetNextSelectedItem(&nSel)) != NULL)
  581. {
  582. err = DisconnectUser(pUserEntry);
  583. if (err.Failed())
  584. {
  585. ++fProblems;
  586. if (err.MessageBoxFormat(
  587. m_hWnd,
  588. IDS_DISCONNECT_ERR,
  589. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2,
  590. NO_HELP_CONTEXT,
  591. (LPCTSTR)pUserEntry->QueryUserName()
  592. ) == IDYES)
  593. {
  594. //
  595. // Continue trying to delete
  596. //
  597. ++nSel;
  598. continue;
  599. }
  600. else
  601. {
  602. break;
  603. }
  604. }
  605. m_oblFtpUsers.RemoveIndex(nSel);
  606. m_list_Users.DeleteString(nSel);
  607. //
  608. // Don't advance counter to account for offset
  609. //
  610. }
  611. m_list_Users.SetRedraw(TRUE);
  612. UpdateTotalCount();
  613. SetControlStates();
  614. if (!fProblems)
  615. {
  616. //
  617. // Ensure button not disabled
  618. //
  619. GetDlgItem(IDC_BUTTON_REFRESH)->SetFocus();
  620. }
  621. }
  622. void
  623. CUserSessionsDlg::OnButtonDisconnectAll()
  624. /*++
  625. Routine Description:
  626. 'Disconnect All Users' button has been pressed. Disconnect all users
  627. Arguments:
  628. None
  629. Return Value:
  630. None
  631. --*/
  632. {
  633. //
  634. // Ask for confirmation
  635. //
  636. if (!NoYesMessageBox(IDS_CONFIRM_DISCONNECT_ALL))
  637. {
  638. //
  639. // Changed his mind
  640. //
  641. return;
  642. }
  643. CObListIter obli(m_oblFtpUsers);
  644. CFtpUserInfo * pUserEntry;
  645. m_list_Users.SetRedraw(FALSE);
  646. CWaitCursor wait;
  647. int cItems = 0;
  648. CError err;
  649. int nSel = 0;
  650. BOOL fProblems = FALSE;
  651. for ( /**/; pUserEntry = (CFtpUserInfo *)obli.Next(); ++cItems)
  652. {
  653. err = DisconnectUser(pUserEntry);
  654. if (err.Failed())
  655. {
  656. ++fProblems;
  657. if (err.MessageBoxFormat(
  658. m_hWnd,
  659. IDS_DISCONNECT_ERR,
  660. MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2,
  661. NO_HELP_CONTEXT,
  662. (LPCTSTR)pUserEntry->QueryUserName()
  663. ) == IDYES)
  664. {
  665. //
  666. // Continue trying to delete
  667. //
  668. ++nSel;
  669. continue;
  670. }
  671. else
  672. {
  673. break;
  674. }
  675. }
  676. m_oblFtpUsers.RemoveIndex(nSel);
  677. m_list_Users.DeleteString(nSel);
  678. }
  679. m_list_Users.SetRedraw(TRUE);
  680. UpdateTotalCount();
  681. SetControlStates();
  682. if (!fProblems)
  683. {
  684. //
  685. // Ensure button not disabled
  686. //
  687. GetDlgItem(IDC_BUTTON_REFRESH)->SetFocus();
  688. }
  689. }
  690. void
  691. CUserSessionsDlg::OnButtonRefresh()
  692. /*++
  693. Routine Description:
  694. 'Refresh' Button has been pressed. Refresh the user list
  695. Arguments:
  696. None
  697. Return Value:
  698. None
  699. --*/
  700. {
  701. RefreshUsersList();
  702. }
  703. void
  704. CUserSessionsDlg::OnSelchangeListUsers()
  705. /*++
  706. Routine Description:
  707. Respond to a change in selection in the user listbox
  708. Arguments:
  709. None
  710. Return Value:
  711. None
  712. --*/
  713. {
  714. SetControlStates();
  715. }
  716. void
  717. CUserSessionsDlg::OnHeaderItemClick(
  718. IN UINT nID,
  719. IN NMHDR * pNMHDR,
  720. OUT LRESULT * plResult
  721. )
  722. /*++
  723. Routine Description:
  724. Header item has been clicked in the listbox. Change the sort key
  725. as appropriate.
  726. Arguments:
  727. None
  728. Return Value:
  729. None
  730. --*/
  731. {
  732. HD_NOTIFY * pNotify = (HD_NOTIFY *)pNMHDR;
  733. TRACEEOLID("Header Button clicked.");
  734. //
  735. // Can't press a button out of range, surely...
  736. //
  737. ASSERT(pNotify->iItem < m_list_Users.QueryNumColumns());
  738. int nOldSortColumn = m_nSortColumn;
  739. m_nSortColumn = pNotify->iItem;
  740. if(m_nSortColumn != nOldSortColumn)
  741. {
  742. //
  743. // Rebuild the list
  744. //
  745. SortUsersList();
  746. CFtpUserInfo * pSelector = GetSelectedListItem();
  747. FillListBox(pSelector);
  748. SetControlStates();
  749. }
  750. //
  751. // Message Fully Handled
  752. //
  753. *plResult = 0;
  754. }
  755. BOOL
  756. CUserSessionsDlg::OnInitDialog()
  757. /*++
  758. Routine Description:
  759. WM_INITDIALOG handler. Initialize the dialog.
  760. Arguments:
  761. None.
  762. Return Value:
  763. TRUE if no focus is to be set automatically, FALSE if the focus
  764. is already set.
  765. --*/
  766. {
  767. CDialog::OnInitDialog();
  768. if (!m_strAdminName.IsEmpty())
  769. {
  770. CError err = ImpersonateUser(m_strAdminName, _T(""), m_strAdminPassword, &m_hImpToken, &m_hLogToken);
  771. }
  772. m_list_Users.Initialize();
  773. if (RefreshUsersList() != ERROR_SUCCESS)
  774. {
  775. EndDialog(IDCANCEL);
  776. return FALSE;
  777. }
  778. return TRUE;
  779. }
  780. void
  781. CUserSessionsDlg::OnDestroy()
  782. {
  783. if (m_hImpToken != INVALID_HANDLE_VALUE || m_hLogToken != INVALID_HANDLE_VALUE)
  784. {
  785. UnImpersonateUser(m_hImpToken, m_hLogToken);
  786. }
  787. }
  788. CUserSessionsDlg::~CUserSessionsDlg()
  789. {
  790. if (m_NetUseSessionCreated)
  791. {
  792. CString server;
  793. server = m_strServerName;
  794. // check if lpMachineName starts with \\
  795. // if it doesn't then make sure it does, or it's null (for local machine)
  796. server = _T("\\\\");
  797. server += PURE_COMPUTER_NAME((LPCTSTR) m_strServerName);
  798. WNetCancelConnection2((LPTSTR)(LPCTSTR)server, 0, TRUE);
  799. m_NetUseSessionCreated = FALSE;
  800. }
  801. }
  802. HRESULT ImpersonateUser(LPCTSTR pszUserName,
  803. LPCTSTR pszDomain,
  804. LPCTSTR pszPassword,
  805. HANDLE *pCurImpToken,
  806. HANDLE *pLoggedOnUserToken)
  807. {
  808. HRESULT hr = S_OK;
  809. ASSERT(pCurImpToken);
  810. ASSERT(pLoggedOnUserToken);
  811. *pCurImpToken = INVALID_HANDLE_VALUE;
  812. *pLoggedOnUserToken = INVALID_HANDLE_VALUE;
  813. // logon the user. This creates an primary impersonation
  814. // token. If this fails, an error will be returned.
  815. if (!LogonUser((LPTSTR)pszUserName,
  816. (LPTSTR)pszDomain,
  817. (LPTSTR)pszPassword,
  818. LOGON32_LOGON_BATCH,
  819. LOGON32_PROVIDER_DEFAULT,
  820. pLoggedOnUserToken)) {
  821. hr = HRESULT_FROM_WIN32(GetLastError());
  822. }
  823. // get the current impersonation token. If an error occurs,
  824. // that is OK. This just means that no impersonation on the
  825. // thread is occurring, so there is no need to do the RevertToSelf.
  826. else if (OpenThreadToken( GetCurrentThread(),
  827. TOKEN_READ | TOKEN_IMPERSONATE,
  828. TRUE,
  829. pCurImpToken)) {
  830. RevertToSelf();
  831. }
  832. // if everything's been successful so far, than call
  833. // ImpersonateLoggedOnUser with the token created above.
  834. if (SUCCEEDED(hr)) {
  835. if (!ImpersonateLoggedOnUser(*pLoggedOnUserToken)) {
  836. hr = HRESULT_FROM_WIN32(GetLastError());
  837. }
  838. }
  839. // if there were failures, clean up any tokens that we created
  840. // or hold.
  841. if (FAILED(hr)) {
  842. // cleanup the LogonUser token
  843. if (*pLoggedOnUserToken != INVALID_HANDLE_VALUE) {
  844. CloseHandle(*pLoggedOnUserToken);
  845. *pLoggedOnUserToken = INVALID_HANDLE_VALUE;
  846. }
  847. // cleanup the token from the OpenThreadToken call
  848. if (*pCurImpToken != INVALID_HANDLE_VALUE) {
  849. HANDLE hThread = GetCurrentThread();
  850. SetThreadToken(&hThread,
  851. *pCurImpToken);
  852. CloseHandle(*pCurImpToken);
  853. *pCurImpToken = INVALID_HANDLE_VALUE;
  854. }
  855. }
  856. return hr;
  857. }
  858. HRESULT UnImpersonateUser(HANDLE hSavedImpToken, HANDLE hLoggedOnUser)
  859. {
  860. // if there is an hSavedImpToken, then call SetThreadToken to
  861. // restore it.
  862. if (hSavedImpToken != INVALID_HANDLE_VALUE)
  863. {
  864. HANDLE hThread = GetCurrentThread();
  865. SetThreadToken(&hThread, hSavedImpToken);
  866. CloseHandle(hSavedImpToken);
  867. }
  868. // cleanup the LogonUser token
  869. if (hLoggedOnUser != INVALID_HANDLE_VALUE)
  870. {
  871. CloseHandle(hLoggedOnUser);
  872. }
  873. return S_OK;
  874. }