windows-nt/Source/XPSP1/NT/inetsrv/iis/admin/snapin/authent.cpp
2020-09-26 16:20:57 +08:00

489 lines
13 KiB
C++

/*++
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 <initguid.h>
#include <dsclient.h>
#include <wincrui.h>
#include <Dsgetdc.h>
#include <Lm.h>
#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<IDsBrowseDomainTree> spDsDomains;
CError err = ::CoCreateInstance(CLSID_DsDomainTreeBrowser,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsBrowseDomainTree,
reinterpret_cast<void **>(&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();
}
}