/*++ Copyright (c) 1994-2001 Microsoft Corporation Module Name : authent.cpp Abstract: WWW Authentication Dialog Author: Ronald Meijer (ronaldm) Sergei Antonov (sergeia) Project: Internet Services Manager Revision History: --*/ #include "stdafx.h" #include "resource.h" #include "common.h" #include "inetprop.h" #include "inetmgrapp.h" #include "supdlgs.h" #include "certmap.h" #include "authent.h" #define INITGUID #include #include #include #include #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define HIDD_DOMAINACCTS 0x50334 CAuthenticationDlg::CAuthenticationDlg( IN LPCTSTR lpstrServerName, IN DWORD dwInstance, IN CString & strBasicDomain, IN CString & strRealm, IN DWORD & dwAuthFlags, IN DWORD & dwAccessPermissions, IN CString & strUserName, IN CString & strPassword, IN BOOL & fPasswordSync, IN BOOL fAdminAccess, IN BOOL fHasDigest, IN CWnd * pParent OPTIONAL ) /*++ Routine Description: Authentication dialog constructor Arguments: LPCTSTR lpstrServerName : Server name DWORD dwInstance : Instance number CString & strBasicDomain : Basic domain name DWORD & dwAuthFlags : Authorization flags DWORD & dwAccessPermissions : Access permissions CString & strUserName : Anonymous user name CString & strPassword : Anonymous user pwd BOOL & fPasswordSync : Password sync setting BOOL fAdminAccess : TRUE if user has admin access BOOL fHasDigest : TRUE if machine supports digest auth. CWnd * pParent : Optional parent window Return Value: N/A --*/ : CDialog(CAuthenticationDlg::IDD, pParent), m_strServerName(lpstrServerName), m_strBasicDomain(strBasicDomain), m_strRealm(strRealm), m_strUserName(strUserName), m_strPassword(strPassword), m_dwInstance(dwInstance), m_dwAuthFlags(dwAuthFlags), m_dwAccessPermissions(dwAccessPermissions), m_fAdminAccess(fAdminAccess), m_fHasDigest(fHasDigest), m_fPasswordSync(fPasswordSync), m_fPasswordSyncChanged(FALSE), m_fUserNameChanged(FALSE), m_fPasswordSyncMsgShown(FALSE), m_fChanged(FALSE), m_fInDomain(TRUE) { #if 0 // Class Wizard happy //{{AFX_DATA_INIT(CAuthenticationDlg) m_fClearText = FALSE; m_fDigest = FALSE; m_fChallengeResponse = FALSE; m_fAnonymous = FALSE; //}}AFX_DATA_INIT #endif // 0 m_fClearText = IS_FLAG_SET(m_dwAuthFlags, MD_AUTH_BASIC); m_fDigest = IS_FLAG_SET(m_dwAuthFlags, MD_AUTH_MD5); m_fChallengeResponse = IS_FLAG_SET(m_dwAuthFlags, MD_AUTH_NT); m_fAnonymous = IS_FLAG_SET(m_dwAuthFlags, MD_AUTH_ANONYMOUS); } void CAuthenticationDlg::DoDataExchange( IN CDataExchange * pDX ) { if (pDX->m_bSaveAndValidate && !m_fChanged) { return; } CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAuthenticationDlg) DDX_Control(pDX, IDC_CHECK_ANONYMOUS, m_check_Anonymous); DDX_Check(pDX, IDC_CHECK_ANONYMOUS, m_fAnonymous); DDX_Control(pDX, IDC_EDIT_USERNAME, m_edit_UserName); DDX_Control(pDX, IDC_EDIT_PASSWORD, m_edit_Password); DDX_Check(pDX, IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, m_fPasswordSync); DDX_Control(pDX, IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, m_chk_PasswordSync); DDX_Check(pDX, IDC_CHECK_CLEAR_TEXT, m_fClearText); DDX_Check(pDX, IDC_CHECK_DIGEST, m_fDigest); DDX_Check(pDX, IDC_CHECK_NT_CHALLENGE_RESPONSE, m_fChallengeResponse); DDX_Control(pDX, IDC_CHECK_NT_CHALLENGE_RESPONSE, m_check_ChallengeResponse); DDX_Control(pDX, IDC_CHECK_DIGEST, m_check_Digest); DDX_Control(pDX, IDC_CHECK_CLEAR_TEXT, m_check_ClearText); DDX_Control(pDX, IDC_BASDOM, m_edit_BasicDomain); DDX_Control(pDX, IDC_BASDOM_SELECT, m_btn_SelectDomain); DDX_Control(pDX, IDC_REALM, m_edit_Realm); DDX_Control(pDX, IDC_REALM_SELECT, m_btn_SelectRealm); //}}AFX_DATA_MAP DDX_Text(pDX, IDC_EDIT_USERNAME, m_strUserName); DDV_MinMaxChars(pDX, m_strUserName, 1, UNLEN); DDX_Text(pDX, IDC_BASDOM, m_strBasicDomain); DDX_Text(pDX, IDC_REALM, m_strRealm); // // Some people have a tendency to add "\\" before // the computer name in user accounts. Fix this here. // m_strUserName.TrimLeft(); while (*m_strUserName == '\\') { m_strUserName = m_strUserName.Mid(2); } // // Display the remote password sync message if // password sync is on, the account is not local, // password sync has changed or username has changed // and the message hasn't already be shown. // if (pDX->m_bSaveAndValidate) { BOOL bLocal; CString user, domain; CError err = CredUIParseUserName( m_strUserName, user.GetBuffer(CRED_MAX_USERNAME_LENGTH), CRED_MAX_USERNAME_LENGTH, domain.GetBuffer(MAX_PATH), MAX_PATH); user.ReleaseBuffer(); domain.ReleaseBuffer(); bLocal = domain.IsEmpty() || domain.CompareNoCase(m_strServerName) == 0; if (m_fPasswordSync && !bLocal && (m_fPasswordSyncChanged || m_fUserNameChanged) && !m_fPasswordSyncMsgShown ) { if (::AfxMessageBox(IDS_WRN_PWSYNC, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION ) != IDYES) { pDX->Fail(); } // // Don't show it again // m_fPasswordSyncMsgShown = TRUE; } // Convert to standard domain\user format if (!bLocal) { m_strUserName = domain; m_strUserName += _T('\\'); m_strUserName += user; } } if (!m_fPasswordSync || !pDX->m_bSaveAndValidate) { DDX_Password(pDX, IDC_EDIT_PASSWORD, m_strPassword, g_lpszDummyPassword); } if (!m_fPasswordSync) { DDV_MaxChars(pDX, m_strPassword, PWLEN); } if (pDX->m_bSaveAndValidate) { m_fChanged = FALSE; } } // // Message Map // BEGIN_MESSAGE_MAP(CAuthenticationDlg, CDialog) //{{AFX_MSG_MAP(CAuthenticationDlg) ON_BN_CLICKED(IDC_CHECK_ANONYMOUS, OnCheckAnonymous) ON_BN_CLICKED(IDC_BUTTON_BROWSE_USERS, OnButtonBrowseUsers) ON_BN_CLICKED(IDC_CHECK_ENABLE_PW_SYNCHRONIZATION, OnCheckEnablePwSynchronization) ON_EN_CHANGE(IDC_EDIT_USERNAME, OnChangeEditUsername) ON_BN_CLICKED(IDC_CHECK_CLEAR_TEXT, OnCheckClearText) ON_BN_CLICKED(IDC_CHECK_DIGEST, OnCheckDigest) ON_BN_CLICKED(IDC_CHECK_NT_CHALLENGE_RESPONSE, OnItemChanged) ON_BN_CLICKED(IDC_BASDOM_SELECT, OnButtonSelectDomain) ON_BN_CLICKED(IDC_REALM_SELECT, OnButtonSelectRealm) //}}AFX_MSG_MAP // ON_BN_CLICKED(IDC_BUTTON_EDIT, OnButtonEdit) ON_EN_CHANGE(IDC_EDIT_PASSWORD, OnItemChanged) ON_EN_CHANGE(IDC_EDIT_DOMAIN_NAME, OnItemChanged) ON_EN_CHANGE(IDC_BASDOM, OnItemChanged) ON_EN_CHANGE(IDC_REALM, OnItemChanged) END_MESSAGE_MAP() void CAuthenticationDlg::OnItemChanged() /*++ Routine Description: All EN_CHANGE and BN_CLICKED messages map to this function --*/ { m_fChanged = TRUE; SetControlStates(); } void CAuthenticationDlg::SetControlStates() /*++ Routine Description: Set control states depending on current data in the dialog --*/ { m_edit_UserName.EnableWindow(m_fAnonymous); m_chk_PasswordSync.EnableWindow(m_fAnonymous); m_edit_Password.EnableWindow(!m_fPasswordSync && m_fAnonymous); m_edit_BasicDomain.EnableWindow(m_fClearText); m_btn_SelectDomain.EnableWindow(m_fClearText && m_fInDomain); m_edit_Realm.EnableWindow(m_fDigest || m_fClearText); m_btn_SelectRealm.EnableWindow((m_fDigest || m_fClearText) && m_fInDomain); GetDlgItem(IDC_BUTTON_BROWSE_USERS)->EnableWindow(m_fAnonymous); } BOOL CAuthenticationDlg::OnInitDialog() { CDialog::OnInitDialog(); SetControlStates(); // // Ensure compatibility with downlevel // m_check_Digest.EnableWindow(m_fHasDigest); // Check if computer is joined to domain COMPUTER_NAME_FORMAT fmt = ComputerNamePhysicalDnsDomain; TCHAR buf[MAX_PATH]; DWORD n = MAX_PATH; m_fInDomain = (GetComputerNameEx(fmt, buf, &n) && n > 0); m_btn_SelectDomain.EnableWindow(m_fInDomain); m_btn_SelectRealm.EnableWindow(m_fInDomain); return TRUE; } void CAuthenticationDlg::OnButtonBrowseUsers() { CString str; if (GetIUsrAccount(m_strServerName, this, str)) { // // If the name is non-local (determined by having // a slash in the name, password sync is disabled, // and a password should be entered. // m_edit_UserName.SetWindowText(str); CString user, domain; CError err = CredUIParseUserName(str, user.GetBuffer(CRED_MAX_USERNAME_LENGTH), CRED_MAX_USERNAME_LENGTH, domain.GetBuffer(MAX_PATH), MAX_PATH); user.ReleaseBuffer(); domain.ReleaseBuffer(); m_fPasswordSync = domain.IsEmpty() || domain.CompareNoCase(m_strServerName) == 0; if (!m_fPasswordSync) { m_edit_Password.SetWindowText(_T("")); m_edit_Password.SetFocus(); } m_chk_PasswordSync.SetCheck(m_fPasswordSync); OnItemChanged(); } } //GUID _CLSID_DsDomainTreeBrowser = {0x1698790a, 0xe2b4, 0x11d0, {0xb0, 0xb1, 0x00, 0xc0, 0x4f, 0xd8, 0xdc, 0xa6}}; //GUID _IID_IDsBrowseDomainTree = {0x7cabcf1e, 0x78f5, 0x11d2, {0x96, 0xc, 0x0, 0xc0, 0x4f, 0xa3, 0x1a, 0x86}}; void CAuthenticationDlg::OnButtonSelectDomain() { HRESULT hr = BrowseDomain(m_strBasicDomain); if (SUCCEEDED(hr)) { UpdateData(FALSE); } } void CAuthenticationDlg::OnButtonSelectRealm() { HRESULT hr = BrowseDomain(m_strRealm); if (SUCCEEDED(hr)) { UpdateData(FALSE); } } HRESULT CAuthenticationDlg::BrowseDomain(CString& domain) { CString prev = domain; CComPtr spDsDomains; CError err = ::CoCreateInstance(CLSID_DsDomainTreeBrowser, NULL, CLSCTX_INPROC_SERVER, IID_IDsBrowseDomainTree, reinterpret_cast(&spDsDomains)); if (err.Succeeded()) { err = spDsDomains->SetComputer(m_strServerName, NULL, NULL); // use default credential if (err.Succeeded()) { LPTSTR pDomainPath = NULL; err = spDsDomains->BrowseTo(m_hWnd, &pDomainPath, /*DBDTF_RETURNINOUTBOUND |*/ DBDTF_RETURNEXTERNAL | DBDTF_RETURNMIXEDDOMAINS); if (err.Succeeded() && pDomainPath != NULL) { domain = pDomainPath; if (domain.CompareNoCase(prev) != 0) { OnItemChanged(); } CoTaskMemFree(pDomainPath); } // When user click on Cancel in this browser, it returns 80070001 (Incorrect function). // I am not quite sure what does it mean. We are filtering out the case when domain browser doesn't // work at all (in workgroup), so here we could safely skip error processing. // else // { // err.MessageBox(); // } } } return err; } void CAuthenticationDlg::OnCheckEnablePwSynchronization() { m_fPasswordSyncChanged = TRUE; m_fPasswordSync = !m_fPasswordSync; OnItemChanged(); SetControlStates(); if (!m_fPasswordSync ) { m_edit_Password.SetSel(0,-1); m_edit_Password.SetFocus(); } } void CAuthenticationDlg::OnChangeEditUsername() { m_fUserNameChanged = TRUE; OnItemChanged(); } void CAuthenticationDlg::OnCheckClearText() { if (m_check_ClearText.GetCheck() == 1) { CClearTxtDlg dlg; if (dlg.DoModal() != IDOK) { m_check_ClearText.SetCheck(0); return; } } m_fClearText = !m_fClearText; OnItemChanged(); SetControlStates(); } void CAuthenticationDlg::OnCheckDigest() { ASSERT(m_fHasDigest); if (m_check_Digest.GetCheck() == 1) { CString cap, msg; msg.LoadString(IDS_WRN_DIGEST); cap.LoadString(IDS_ROOT_NODE); if (IDNO == IisMessageBox(m_hWnd, IDS_WRN_DIGEST, MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2, HIDD_DOMAINACCTS)) { m_check_Digest.SetCheck(0); return; } } m_fDigest = !m_fDigest; OnItemChanged(); SetControlStates(); } void CAuthenticationDlg::OnCheckAnonymous() { m_fAnonymous = !m_fAnonymous; OnItemChanged(); SetControlStates(); } void CAuthenticationDlg::OnOK() { if (UpdateData(TRUE)) { SET_FLAG_IF(m_fClearText, m_dwAuthFlags, MD_AUTH_BASIC); SET_FLAG_IF(m_fChallengeResponse, m_dwAuthFlags, MD_AUTH_NT); SET_FLAG_IF(m_fAnonymous, m_dwAuthFlags, MD_AUTH_ANONYMOUS); SET_FLAG_IF(m_fDigest, m_dwAuthFlags, MD_AUTH_MD5); // // Provide warning if no authentication is selected // if (!m_dwAuthFlags && !m_dwAccessPermissions && !NoYesMessageBox(IDS_WRN_NO_AUTH) ) { // // Don't dismiss the dialog // return; } CDialog::OnOK(); } }