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.

488 lines
13 KiB

  1. /*++
  2. Copyright (c) 1994-2001 Microsoft Corporation
  3. Module Name :
  4. authent.cpp
  5. Abstract:
  6. WWW Authentication Dialog
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Sergei Antonov (sergeia)
  10. Project:
  11. Internet Services Manager
  12. Revision History:
  13. --*/
  14. #include "stdafx.h"
  15. #include "resource.h"
  16. #include "common.h"
  17. #include "inetprop.h"
  18. #include "inetmgrapp.h"
  19. #include "supdlgs.h"
  20. #include "certmap.h"
  21. #include "authent.h"
  22. #define INITGUID
  23. #include <initguid.h>
  24. #include <dsclient.h>
  25. #include <wincrui.h>
  26. #include <Dsgetdc.h>
  27. #include <Lm.h>
  28. #ifdef _DEBUG
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33. #define HIDD_DOMAINACCTS 0x50334
  34. CAuthenticationDlg::CAuthenticationDlg(
  35. IN LPCTSTR lpstrServerName,
  36. IN DWORD dwInstance,
  37. IN CString & strBasicDomain,
  38. IN CString & strRealm,
  39. IN DWORD & dwAuthFlags,
  40. IN DWORD & dwAccessPermissions,
  41. IN CString & strUserName,
  42. IN CString & strPassword,
  43. IN BOOL & fPasswordSync,
  44. IN BOOL fAdminAccess,
  45. IN BOOL fHasDigest,
  46. IN CWnd * pParent OPTIONAL
  47. )
  48. /*++
  49. Routine Description:
  50. Authentication dialog constructor
  51. Arguments:
  52. LPCTSTR lpstrServerName : Server name
  53. DWORD dwInstance : Instance number
  54. CString & strBasicDomain : Basic domain name
  55. DWORD & dwAuthFlags : Authorization flags
  56. DWORD & dwAccessPermissions : Access permissions
  57. CString & strUserName : Anonymous user name
  58. CString & strPassword : Anonymous user pwd
  59. BOOL & fPasswordSync : Password sync setting
  60. BOOL fAdminAccess : TRUE if user has admin access
  61. BOOL fHasDigest : TRUE if machine supports digest auth.
  62. CWnd * pParent : Optional parent window
  63. Return Value:
  64. N/A
  65. --*/
  66. : CDialog(CAuthenticationDlg::IDD, pParent),
  67. m_strServerName(lpstrServerName),
  68. m_strBasicDomain(strBasicDomain),
  69. m_strRealm(strRealm),
  70. m_strUserName(strUserName),
  71. m_strPassword(strPassword),
  72. m_dwInstance(dwInstance),
  73. m_dwAuthFlags(dwAuthFlags),
  74. m_dwAccessPermissions(dwAccessPermissions),
  75. m_fAdminAccess(fAdminAccess),
  76. m_fHasDigest(fHasDigest),
  77. m_fPasswordSync(fPasswordSync),
  78. m_fPasswordSyncChanged(FALSE),
  79. m_fUserNameChanged(FALSE),
  80. m_fPasswordSyncMsgShown(FALSE),
  81. m_fChanged(FALSE),
  82. m_fInDomain(TRUE)
  83. {
  84. #if 0 // Class Wizard happy
  85. //{{AFX_DATA_INIT(CAuthenticationDlg)
  86. m_fClearText = FALSE;
  87. m_fDigest = FALSE;
  88. m_fChallengeResponse = FALSE;
  89. m_fAnonymous = FALSE;
  90. //}}AFX_DATA_INIT
  91. #endif // 0
  92. m_fClearText = IS_FLAG_SET(m_dwAuthFlags, MD_AUTH_BASIC);
  93. m_fDigest = IS_FLAG_SET(m_dwAuthFlags, MD_AUTH_MD5);
  94. m_fChallengeResponse = IS_FLAG_SET(m_dwAuthFlags, MD_AUTH_NT);
  95. m_fAnonymous = IS_FLAG_SET(m_dwAuthFlags, MD_AUTH_ANONYMOUS);
  96. }
  97. void
  98. CAuthenticationDlg::DoDataExchange(
  99. IN CDataExchange * pDX
  100. )
  101. {
  102. if (pDX->m_bSaveAndValidate && !m_fChanged)
  103. {
  104. return;
  105. }
  106. CDialog::DoDataExchange(pDX);
  107. //{{AFX_DATA_MAP(CAuthenticationDlg)
  108. DDX_Control(pDX, IDC_CHECK_ANONYMOUS, m_check_Anonymous);
  109. DDX_Check(pDX, IDC_CHECK_ANONYMOUS, m_fAnonymous);
  110. DDX_Control(pDX, IDC_EDIT_USERNAME, m_edit_UserName);
  111. DDX_Control(pDX, IDC_EDIT_PASSWORD, m_edit_Password);
  112. DDX_Check(pDX, IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, m_fPasswordSync);
  113. DDX_Control(pDX, IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, m_chk_PasswordSync);
  114. DDX_Check(pDX, IDC_CHECK_CLEAR_TEXT, m_fClearText);
  115. DDX_Check(pDX, IDC_CHECK_DIGEST, m_fDigest);
  116. DDX_Check(pDX, IDC_CHECK_NT_CHALLENGE_RESPONSE, m_fChallengeResponse);
  117. DDX_Control(pDX, IDC_CHECK_NT_CHALLENGE_RESPONSE, m_check_ChallengeResponse);
  118. DDX_Control(pDX, IDC_CHECK_DIGEST, m_check_Digest);
  119. DDX_Control(pDX, IDC_CHECK_CLEAR_TEXT, m_check_ClearText);
  120. DDX_Control(pDX, IDC_BASDOM, m_edit_BasicDomain);
  121. DDX_Control(pDX, IDC_BASDOM_SELECT, m_btn_SelectDomain);
  122. DDX_Control(pDX, IDC_REALM, m_edit_Realm);
  123. DDX_Control(pDX, IDC_REALM_SELECT, m_btn_SelectRealm);
  124. //}}AFX_DATA_MAP
  125. DDX_Text(pDX, IDC_EDIT_USERNAME, m_strUserName);
  126. DDV_MinMaxChars(pDX, m_strUserName, 1, UNLEN);
  127. DDX_Text(pDX, IDC_BASDOM, m_strBasicDomain);
  128. DDX_Text(pDX, IDC_REALM, m_strRealm);
  129. //
  130. // Some people have a tendency to add "\\" before
  131. // the computer name in user accounts. Fix this here.
  132. //
  133. m_strUserName.TrimLeft();
  134. while (*m_strUserName == '\\')
  135. {
  136. m_strUserName = m_strUserName.Mid(2);
  137. }
  138. //
  139. // Display the remote password sync message if
  140. // password sync is on, the account is not local,
  141. // password sync has changed or username has changed
  142. // and the message hasn't already be shown.
  143. //
  144. if (pDX->m_bSaveAndValidate)
  145. {
  146. BOOL bLocal;
  147. CString user, domain;
  148. CError err = CredUIParseUserName(
  149. m_strUserName,
  150. user.GetBuffer(CRED_MAX_USERNAME_LENGTH), CRED_MAX_USERNAME_LENGTH,
  151. domain.GetBuffer(MAX_PATH), MAX_PATH);
  152. user.ReleaseBuffer();
  153. domain.ReleaseBuffer();
  154. bLocal = domain.IsEmpty() || domain.CompareNoCase(m_strServerName) == 0;
  155. if (m_fPasswordSync
  156. && !bLocal
  157. && (m_fPasswordSyncChanged || m_fUserNameChanged)
  158. && !m_fPasswordSyncMsgShown
  159. )
  160. {
  161. if (::AfxMessageBox(IDS_WRN_PWSYNC, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION ) != IDYES)
  162. {
  163. pDX->Fail();
  164. }
  165. //
  166. // Don't show it again
  167. //
  168. m_fPasswordSyncMsgShown = TRUE;
  169. }
  170. // Convert to standard domain\user format
  171. if (!bLocal)
  172. {
  173. m_strUserName = domain;
  174. m_strUserName += _T('\\');
  175. m_strUserName += user;
  176. }
  177. }
  178. if (!m_fPasswordSync || !pDX->m_bSaveAndValidate)
  179. {
  180. DDX_Password(pDX, IDC_EDIT_PASSWORD, m_strPassword, g_lpszDummyPassword);
  181. }
  182. if (!m_fPasswordSync)
  183. {
  184. DDV_MaxChars(pDX, m_strPassword, PWLEN);
  185. }
  186. if (pDX->m_bSaveAndValidate)
  187. {
  188. m_fChanged = FALSE;
  189. }
  190. }
  191. //
  192. // Message Map
  193. //
  194. BEGIN_MESSAGE_MAP(CAuthenticationDlg, CDialog)
  195. //{{AFX_MSG_MAP(CAuthenticationDlg)
  196. ON_BN_CLICKED(IDC_CHECK_ANONYMOUS, OnCheckAnonymous)
  197. ON_BN_CLICKED(IDC_BUTTON_BROWSE_USERS, OnButtonBrowseUsers)
  198. ON_BN_CLICKED(IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, OnCheckEnablePwSynchronization)
  199. ON_EN_CHANGE(IDC_EDIT_USERNAME, OnChangeEditUsername)
  200. ON_BN_CLICKED(IDC_CHECK_CLEAR_TEXT, OnCheckClearText)
  201. ON_BN_CLICKED(IDC_CHECK_DIGEST, OnCheckDigest)
  202. ON_BN_CLICKED(IDC_CHECK_NT_CHALLENGE_RESPONSE, OnItemChanged)
  203. ON_BN_CLICKED(IDC_BASDOM_SELECT, OnButtonSelectDomain)
  204. ON_BN_CLICKED(IDC_REALM_SELECT, OnButtonSelectRealm)
  205. //}}AFX_MSG_MAP
  206. // ON_BN_CLICKED(IDC_BUTTON_EDIT, OnButtonEdit)
  207. ON_EN_CHANGE(IDC_EDIT_PASSWORD, OnItemChanged)
  208. ON_EN_CHANGE(IDC_EDIT_DOMAIN_NAME, OnItemChanged)
  209. ON_EN_CHANGE(IDC_BASDOM, OnItemChanged)
  210. ON_EN_CHANGE(IDC_REALM, OnItemChanged)
  211. END_MESSAGE_MAP()
  212. void
  213. CAuthenticationDlg::OnItemChanged()
  214. /*++
  215. Routine Description:
  216. All EN_CHANGE and BN_CLICKED messages map to this function
  217. --*/
  218. {
  219. m_fChanged = TRUE;
  220. SetControlStates();
  221. }
  222. void
  223. CAuthenticationDlg::SetControlStates()
  224. /*++
  225. Routine Description:
  226. Set control states depending on current data in the dialog
  227. --*/
  228. {
  229. m_edit_UserName.EnableWindow(m_fAnonymous);
  230. m_chk_PasswordSync.EnableWindow(m_fAnonymous);
  231. m_edit_Password.EnableWindow(!m_fPasswordSync && m_fAnonymous);
  232. m_edit_BasicDomain.EnableWindow(m_fClearText);
  233. m_btn_SelectDomain.EnableWindow(m_fClearText && m_fInDomain);
  234. m_edit_Realm.EnableWindow(m_fDigest || m_fClearText);
  235. m_btn_SelectRealm.EnableWindow((m_fDigest || m_fClearText) && m_fInDomain);
  236. GetDlgItem(IDC_BUTTON_BROWSE_USERS)->EnableWindow(m_fAnonymous);
  237. }
  238. BOOL
  239. CAuthenticationDlg::OnInitDialog()
  240. {
  241. CDialog::OnInitDialog();
  242. SetControlStates();
  243. //
  244. // Ensure compatibility with downlevel
  245. //
  246. m_check_Digest.EnableWindow(m_fHasDigest);
  247. // Check if computer is joined to domain
  248. COMPUTER_NAME_FORMAT fmt = ComputerNamePhysicalDnsDomain;
  249. TCHAR buf[MAX_PATH];
  250. DWORD n = MAX_PATH;
  251. m_fInDomain = (GetComputerNameEx(fmt, buf, &n) && n > 0);
  252. m_btn_SelectDomain.EnableWindow(m_fInDomain);
  253. m_btn_SelectRealm.EnableWindow(m_fInDomain);
  254. return TRUE;
  255. }
  256. void
  257. CAuthenticationDlg::OnButtonBrowseUsers()
  258. {
  259. CString str;
  260. if (GetIUsrAccount(m_strServerName, this, str))
  261. {
  262. //
  263. // If the name is non-local (determined by having
  264. // a slash in the name, password sync is disabled,
  265. // and a password should be entered.
  266. //
  267. m_edit_UserName.SetWindowText(str);
  268. CString user, domain;
  269. CError err = CredUIParseUserName(str,
  270. user.GetBuffer(CRED_MAX_USERNAME_LENGTH), CRED_MAX_USERNAME_LENGTH,
  271. domain.GetBuffer(MAX_PATH), MAX_PATH);
  272. user.ReleaseBuffer();
  273. domain.ReleaseBuffer();
  274. m_fPasswordSync =
  275. domain.IsEmpty() || domain.CompareNoCase(m_strServerName) == 0;
  276. if (!m_fPasswordSync)
  277. {
  278. m_edit_Password.SetWindowText(_T(""));
  279. m_edit_Password.SetFocus();
  280. }
  281. m_chk_PasswordSync.SetCheck(m_fPasswordSync);
  282. OnItemChanged();
  283. }
  284. }
  285. //GUID _CLSID_DsDomainTreeBrowser = {0x1698790a, 0xe2b4, 0x11d0, {0xb0, 0xb1, 0x00, 0xc0, 0x4f, 0xd8, 0xdc, 0xa6}};
  286. //GUID _IID_IDsBrowseDomainTree = {0x7cabcf1e, 0x78f5, 0x11d2, {0x96, 0xc, 0x0, 0xc0, 0x4f, 0xa3, 0x1a, 0x86}};
  287. void CAuthenticationDlg::OnButtonSelectDomain()
  288. {
  289. HRESULT hr = BrowseDomain(m_strBasicDomain);
  290. if (SUCCEEDED(hr))
  291. {
  292. UpdateData(FALSE);
  293. }
  294. }
  295. void CAuthenticationDlg::OnButtonSelectRealm()
  296. {
  297. HRESULT hr = BrowseDomain(m_strRealm);
  298. if (SUCCEEDED(hr))
  299. {
  300. UpdateData(FALSE);
  301. }
  302. }
  303. HRESULT
  304. CAuthenticationDlg::BrowseDomain(CString& domain)
  305. {
  306. CString prev = domain;
  307. CComPtr<IDsBrowseDomainTree> spDsDomains;
  308. CError err = ::CoCreateInstance(CLSID_DsDomainTreeBrowser,
  309. NULL,
  310. CLSCTX_INPROC_SERVER,
  311. IID_IDsBrowseDomainTree,
  312. reinterpret_cast<void **>(&spDsDomains));
  313. if (err.Succeeded())
  314. {
  315. err = spDsDomains->SetComputer(m_strServerName, NULL, NULL); // use default credential
  316. if (err.Succeeded())
  317. {
  318. LPTSTR pDomainPath = NULL;
  319. err = spDsDomains->BrowseTo(m_hWnd, &pDomainPath,
  320. /*DBDTF_RETURNINOUTBOUND |*/ DBDTF_RETURNEXTERNAL | DBDTF_RETURNMIXEDDOMAINS);
  321. if (err.Succeeded() && pDomainPath != NULL)
  322. {
  323. domain = pDomainPath;
  324. if (domain.CompareNoCase(prev) != 0)
  325. {
  326. OnItemChanged();
  327. }
  328. CoTaskMemFree(pDomainPath);
  329. }
  330. // When user click on Cancel in this browser, it returns 80070001 (Incorrect function).
  331. // I am not quite sure what does it mean. We are filtering out the case when domain browser doesn't
  332. // work at all (in workgroup), so here we could safely skip error processing.
  333. // else
  334. // {
  335. // err.MessageBox();
  336. // }
  337. }
  338. }
  339. return err;
  340. }
  341. void
  342. CAuthenticationDlg::OnCheckEnablePwSynchronization()
  343. {
  344. m_fPasswordSyncChanged = TRUE;
  345. m_fPasswordSync = !m_fPasswordSync;
  346. OnItemChanged();
  347. SetControlStates();
  348. if (!m_fPasswordSync )
  349. {
  350. m_edit_Password.SetSel(0,-1);
  351. m_edit_Password.SetFocus();
  352. }
  353. }
  354. void
  355. CAuthenticationDlg::OnChangeEditUsername()
  356. {
  357. m_fUserNameChanged = TRUE;
  358. OnItemChanged();
  359. }
  360. void
  361. CAuthenticationDlg::OnCheckClearText()
  362. {
  363. if (m_check_ClearText.GetCheck() == 1)
  364. {
  365. CClearTxtDlg dlg;
  366. if (dlg.DoModal() != IDOK)
  367. {
  368. m_check_ClearText.SetCheck(0);
  369. return;
  370. }
  371. }
  372. m_fClearText = !m_fClearText;
  373. OnItemChanged();
  374. SetControlStates();
  375. }
  376. void
  377. CAuthenticationDlg::OnCheckDigest()
  378. {
  379. ASSERT(m_fHasDigest);
  380. if (m_check_Digest.GetCheck() == 1)
  381. {
  382. CString cap, msg;
  383. msg.LoadString(IDS_WRN_DIGEST);
  384. cap.LoadString(IDS_ROOT_NODE);
  385. if (IDNO == IisMessageBox(m_hWnd, IDS_WRN_DIGEST, MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2, HIDD_DOMAINACCTS))
  386. {
  387. m_check_Digest.SetCheck(0);
  388. return;
  389. }
  390. }
  391. m_fDigest = !m_fDigest;
  392. OnItemChanged();
  393. SetControlStates();
  394. }
  395. void
  396. CAuthenticationDlg::OnCheckAnonymous()
  397. {
  398. m_fAnonymous = !m_fAnonymous;
  399. OnItemChanged();
  400. SetControlStates();
  401. }
  402. void
  403. CAuthenticationDlg::OnOK()
  404. {
  405. if (UpdateData(TRUE))
  406. {
  407. SET_FLAG_IF(m_fClearText, m_dwAuthFlags, MD_AUTH_BASIC);
  408. SET_FLAG_IF(m_fChallengeResponse, m_dwAuthFlags, MD_AUTH_NT);
  409. SET_FLAG_IF(m_fAnonymous, m_dwAuthFlags, MD_AUTH_ANONYMOUS);
  410. SET_FLAG_IF(m_fDigest, m_dwAuthFlags, MD_AUTH_MD5);
  411. //
  412. // Provide warning if no authentication is selected
  413. //
  414. if (!m_dwAuthFlags
  415. && !m_dwAccessPermissions
  416. && !NoYesMessageBox(IDS_WRN_NO_AUTH)
  417. )
  418. {
  419. //
  420. // Don't dismiss the dialog
  421. //
  422. return;
  423. }
  424. CDialog::OnOK();
  425. }
  426. }