windows-nt/Source/XPSP1/NT/ds/security/services/ca/initlib/certui.cpp
2020-09-26 16:20:57 +08:00

841 lines
20 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: cryptui.cpp
//
// Contents: Cert Server wrapper routines
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include "certmsg.h"
#include "clibres.h"
#include "setupids.h"
#include "tfc.h"
#include "Windowsx.h"
#define __dwFILE__ __dwFILE_INITLIB_CERTUI_CPP__
HRESULT
myGetConfigStringFromPicker(
OPTIONAL IN HWND hwndParent,
OPTIONAL IN WCHAR const *pwszPrompt,
OPTIONAL IN WCHAR const *pwszTitle,
OPTIONAL IN WCHAR const *pwszSharedFolder,
IN BOOL fUseDS,
OUT WCHAR **ppwszConfig)
{
HRESULT hr;
DWORD dwCACount;
CRYPTUI_CA_CONTEXT const *pCAContext = NULL;
hr = myGetConfigFromPicker(
hwndParent,
pwszPrompt,
pwszTitle,
pwszSharedFolder,
fUseDS,
FALSE,
&dwCACount,
&pCAContext);
_JumpIfError(hr, error, "myGetConfigFromPicker");
if (NULL == pCAContext)
{
hr = E_INVALIDARG;
_JumpIfError(hr, error, "Internal error: myGetConfigFromPicker");
}
hr = myFormConfigString(
pCAContext->pwszCAMachineName,
pCAContext->pwszCAName,
ppwszConfig);
_JumpIfError(hr, error, "myFormConfigString");
error:
if (NULL != pCAContext)
{
CryptUIDlgFreeCAContext(pCAContext);
}
return(hr);
}
HRESULT
myUIGetWindowText(
IN HWND hwndCtrl,
OUT WCHAR **ppwszText)
{
HRESULT hr;
LRESULT len;
DWORD i;
WCHAR *pwszBegin;
WCHAR *pwszEnd;
WCHAR *pwszText = NULL;
CSASSERT(NULL != hwndCtrl &&
NULL != ppwszText);
// init
*ppwszText = NULL;
// get text string size
len = SendMessage(hwndCtrl, WM_GETTEXTLENGTH, 0, 0);
if (0 < len)
{
pwszText = (WCHAR*)LocalAlloc(LMEM_FIXED, (UINT)((len+1) * sizeof(WCHAR)));
if (NULL == pwszText)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if (len !=
SendMessage(hwndCtrl, WM_GETTEXT, (WPARAM)len+1, (LPARAM)pwszText))
{
hr = HRESULT_FROM_WIN32(ERROR_BAD_LENGTH);
_JumpError(hr, error, "Internal error");
}
}
else
{
goto done;
}
// trim trailing and heading blank strings
pwszBegin = pwszText;
pwszEnd = &pwszText[wcslen(pwszText) - 1];
while (pwszEnd > pwszBegin && iswspace(*pwszEnd) )
{
*pwszEnd = L'\0';
--pwszEnd;
}
while (pwszBegin <= pwszEnd &&
L'\0' != *pwszBegin &&
iswspace(*pwszBegin) )
{
++pwszBegin;
}
if (pwszEnd >= pwszBegin)
{
MoveMemory(
pwszText,
pwszBegin,
(SAFE_SUBTRACT_POINTERS(pwszEnd, pwszBegin) + 2) * sizeof(WCHAR));
}
else
{
goto done;
}
*ppwszText = pwszText;
pwszText = NULL;
done:
hr = S_OK;
error:
if (NULL != pwszText)
{
LocalFree(pwszText);
}
return hr;
}
// following code for CA selection UI control
HRESULT
UICASelectionUpdateCAList(
HWND hwndList,
WCHAR const *pwszzCAList)
{
HRESULT hr;
int nItem;
WCHAR const *pwszCA = pwszzCAList;
// remove current list
SendMessage(hwndList, CB_RESETCONTENT, (WPARAM) 0, (LPARAM) 0);
// add to list
while (NULL != pwszCA && L'\0' != pwszCA[0])
{
nItem = (INT)SendMessage(
hwndList,
CB_ADDSTRING,
(WPARAM) 0,
(LPARAM) pwszCA);
if (LB_ERR == nItem)
{
hr = myHLastError();
_JumpError(hr, error, "SendMessage");
}
pwszCA += wcslen(pwszCA) + 1;
}
if (NULL != pwszzCAList)
{
// attempt to choose the 1st one as default
SendMessage(hwndList, CB_SETCURSEL, (WPARAM) 0, (LPARAM) 0);
}
hr = S_OK;
error:
return hr;
}
LRESULT CALLBACK
myUICASelectionComputerEditFilterHook(
HWND hwndComputer,
UINT iMsg,
WPARAM wParam,
LPARAM lParam)
{
LRESULT lr;
HRESULT hr;
CERTSRVUICASELECTION *pData = (CERTSRVUICASELECTION*)
GetWindowLongPtr(hwndComputer, GWLP_USERDATA);
CSASSERT(NULL != pData);
switch(iMsg)
{
case WM_CHAR:
// empty ca list
hr = UICASelectionUpdateCAList(pData->hwndCAList, NULL);
_PrintIfError(hr, "UICASelectionUpdateCAList");
break;
}
lr = CallWindowProc(
pData->pfnUICASelectionComputerWndProcs,
hwndComputer,
iMsg,
wParam,
lParam);
//error:
return lr;
}
HRESULT
myUICAConditionallyDisplayEnterpriseWarning(
IN CERTSRVUICASELECTION *pData)
{
HRESULT hr = S_OK;
CAINFO *pCAInfo = NULL;
BOOL fCoInit = FALSE;
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, Ret, "CoInitialize");
}
fCoInit = TRUE;
hr = S_OK; // don't want to return this error
pData->CAType = ENUM_UNKNOWN_CA;
// pinging specific CA is done in both cases -- reselect or new machine pointed at
WCHAR szCA[MAX_PATH];
WCHAR szComputer[MAX_PATH];
szCA[0]=L'\0';
szComputer[0]=L'\0';
int iSel;
iSel = ComboBox_GetCurSel(pData->hwndCAList);
ComboBox_GetLBText(pData->hwndCAList, iSel, szCA);
GetWindowText(pData->hwndComputerEdit, szComputer, MAX_PATH);
if ((szCA[0]==L'\0') || (szComputer[0]==L'\0'))
{
ShowWindow(GetDlgItem(pData->hDlg, IDC_CLIENT_WARN_ENTERPRISE_REQUIREMENTS), SW_HIDE);
goto Ret;
}
hr = myPingCertSrv(
szCA,
szComputer,
NULL,
NULL,
&pCAInfo,
NULL,
NULL);
if ((hr == S_OK) && (pCAInfo != NULL))
{
// copy catype into returned data
pData->CAType = pCAInfo->CAType;
if (IsEnterpriseCA(pCAInfo->CAType))
{
ShowWindow(GetDlgItem(pData->hDlg, IDC_CLIENT_WARN_ENTERPRISE_REQUIREMENTS), SW_SHOW);
}
else
{
ShowWindow(GetDlgItem(pData->hDlg, IDC_CLIENT_WARN_ENTERPRISE_REQUIREMENTS), SW_HIDE);
}
}
Ret:
if (NULL != pCAInfo)
LocalFree(pCAInfo);
if (fCoInit)
CoUninitialize();
return hr;
}
HRESULT
myUICAHandleCAListDropdown(
IN int iNotification,
IN OUT CERTSRVUICASELECTION *pData,
IN OUT BOOL *pfComputerChange)
{
HRESULT hr;
WCHAR *pwszComputer = NULL;
WCHAR *pwszzCAList = NULL;
BOOL fCoInit = FALSE;
WCHAR *pwszDnsName = NULL;
DWORD dwVersion;
CSASSERT(NULL != pData);
// if this isn't a focus or selection change and computer name stayed same, nothing to do
if ((CBN_SELCHANGE != iNotification) && !*pfComputerChange)
{
goto done;
}
ShowWindow(GetDlgItem(pData->hDlg, IDC_CLIENT_WARN_ENTERPRISE_REQUIREMENTS), SW_HIDE);
SetCursor(LoadCursor(NULL, IDC_WAIT));
if (NULL == pData->hwndComputerEdit)
{
// not init
goto done;
}
// make sure computer edit field is not empty
hr = myUIGetWindowText(pData->hwndComputerEdit,
&pwszComputer);
_JumpIfError(hr, error, "myUIGetWindowText");
if (NULL == pwszComputer)
{
goto done;
}
if (*pfComputerChange)
{
// ping to get ca list
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInit = TRUE;
// reset once ca list is updated. Do this now to prevent recursion
*pfComputerChange = FALSE;
hr = myPingCertSrv(
pwszComputer,
NULL,
&pwszzCAList,
NULL,
NULL,
&dwVersion,
&pwszDnsName);
CSILOG(hr, IDS_ILOG_GETCANAME, pwszComputer, NULL, NULL);
if (S_OK != hr)
{
// make sure null
CSASSERT(NULL == pwszzCAList);
// can't ping the ca. Set focus now to prevent recursion
SetFocus(pData->hwndComputerEdit);
SendMessage(pData->hwndComputerEdit, EM_SETSEL, 0, -1);
CertWarningMessageBox(
pData->hInstance,
FALSE,
pData->hDlg,
IDS_WRN_PINGCA_FAIL,
hr,
NULL);
}
else if(dwVersion<2 && pData->fWebProxySetup)
{
//bug 262316: don't allow installing Whistler proxy to an older CA
hr = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION);
if(pwszzCAList)
{
LocalFree(pwszzCAList);
pwszzCAList = NULL;
}
SetFocus(pData->hwndComputerEdit);
SendMessage(pData->hwndComputerEdit, EM_SETSEL, 0, -1);
CertWarningMessageBox(
pData->hInstance,
FALSE,
pData->hDlg,
IDS_WRN_OLD_CA,
hr,
NULL);
}
if (NULL!=pwszDnsName && 0!=wcscmp(pwszComputer, pwszDnsName)) {
// update computer
SendMessage(pData->hwndComputerEdit, WM_SETTEXT,
0, (LPARAM)pwszDnsName);
}
// update ca list
hr = UICASelectionUpdateCAList(pData->hwndCAList, pwszzCAList);
_JumpIfError(hr, error, "UICASelectionUpdateCAList");
}
// pinging specific CA is done in both cases -- reselect or new machine pointed at
hr = myUICAConditionallyDisplayEnterpriseWarning(pData);
_PrintIfError(hr, "myUICAConditionallyDisplayEnterpriseWarning");
done:
hr = S_OK;
error:
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (fCoInit)
{
CoUninitialize();
}
if (NULL != pwszzCAList)
{
LocalFree(pwszzCAList);
}
if (NULL != pwszComputer)
{
LocalFree(pwszComputer);
}
if (NULL != pwszDnsName)
{
LocalFree(pwszDnsName);
}
return hr;
}
HRESULT
myInitUICASelectionControls(
IN OUT CERTSRVUICASELECTION *pUICASelection,
IN HINSTANCE hInstance,
IN HWND hDlg,
IN HWND hwndBrowseButton,
IN HWND hwndComputerEdit,
IN HWND hwndCAList,
IN BOOL fDSCA,
OUT BOOL *pfCAsExist)
{
HRESULT hr;
PCCRYPTUI_CA_CONTEXT pCAContext = NULL;
DWORD dwCACount;
CString cstrText;
SetCursor(LoadCursor(NULL, IDC_WAIT));
hr = myGetConfigFromPicker(
hDlg,
NULL,
NULL,
NULL,
fDSCA,
TRUE, // fCountOnly
&dwCACount,
&pCAContext);
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (S_OK != hr)
{
dwCACount = 0;
_PrintError(hr, "myGetConfigFromPicker");
}
// enable/disable
*pfCAsExist = 0 < dwCACount;
EnableWindow(hwndBrowseButton, *pfCAsExist);
// set computer edit control hook
pUICASelection->pfnUICASelectionComputerWndProcs =
(WNDPROC)SetWindowLongPtr(hwndComputerEdit,
GWLP_WNDPROC, (LPARAM)myUICASelectionComputerEditFilterHook);
pUICASelection->hInstance = hInstance;
pUICASelection->hDlg = hDlg;
pUICASelection->hwndComputerEdit = hwndComputerEdit;
pUICASelection->hwndCAList = hwndCAList;
// pass data to both controls
SetWindowLongPtr(hwndComputerEdit, GWLP_USERDATA, (ULONG_PTR)pUICASelection);
SetWindowLongPtr(hwndCAList, GWLP_USERDATA, (ULONG_PTR)pUICASelection);
// by default, don't show Enterprise CA warning
cstrText.LoadString(IDS_WARN_ENTERPRISE_REQUIREMENTS);
SetWindowText(GetDlgItem(hDlg, IDC_CLIENT_WARN_ENTERPRISE_REQUIREMENTS), cstrText);
ShowWindow(GetDlgItem(hDlg, IDC_CLIENT_WARN_ENTERPRISE_REQUIREMENTS), SW_HIDE);
if (NULL != pCAContext)
{
CryptUIDlgFreeCAContext(pCAContext);
}
hr = S_OK;
//error:
return hr;
}
HRESULT
myUICAHandleCABrowseButton(
CERTSRVUICASELECTION *pData,
IN BOOL fUseDS,
OPTIONAL IN int idsPickerTitle,
OPTIONAL IN int idsPickerSubTitle,
OPTIONAL OUT WCHAR **ppwszSharedFolder)
{
HRESULT hr = S_OK;
PCCRYPTUI_CA_CONTEXT pCAContext = NULL;
WCHAR *pwszSubTitle = NULL;
WCHAR *pwszTitle = NULL;
DWORD dwCACount;
WCHAR *pwszzCAList = NULL;
WCHAR *pwszComputer = NULL;
WCHAR *pwszTemp = NULL;
BOOL fCoInit = FALSE;
DWORD dwVersion;
if (NULL != ppwszSharedFolder)
{
*ppwszSharedFolder = NULL;
}
if (0 != idsPickerTitle)
{
hr = myLoadRCString(pData->hInstance, idsPickerTitle, &pwszTitle);
if (S_OK != hr)
{
pwszTitle = NULL;
_PrintError(hr, "myLoadRCString");
}
}
if (0 != idsPickerSubTitle)
{
hr = myLoadRCString(pData->hInstance, idsPickerSubTitle, &pwszSubTitle);
if (S_OK != hr)
{
pwszSubTitle = NULL;
_PrintError(hr, "myLoadRCString");
}
}
/*
// REMOVED mattt 6/26/00: is this ever wanted: "Browse uses shared folder of machine editbox currently points at"?
// just seems to make changing away from bad machine very very slow
// get remote shared folder if possible
hr = myUIGetWindowText(pData->hwndComputerEdit, &pwszComputer);
_JumpIfError(hr, error, "myUIGetWindowText");
if (NULL != pwszComputer)
{
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInit = TRUE;
// get shared folder path on remote machine here
SetCursor(LoadCursor(NULL, IDC_WAIT));
hr = myPingCertSrv(pwszComputer, NULL, NULL, &pwszTemp, NULL, NULL, NULL);
SetCursor(LoadCursor(NULL, IDC_ARROW));
if (S_OK != hr)
{
CSASSERT(NULL == pwszTemp);
_JumpError(hr, localsharedfolder, "myPingCertSrv");
}
}
localsharedfolder:
*/
hr = myGetConfigFromPicker(
pData->hDlg,
pwszSubTitle,
pwszTitle,
pwszTemp,
fUseDS,
FALSE, // fCountOnly
&dwCACount,
&pCAContext);
if (S_OK != hr && HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
{
CSILOG(hr, IDS_ILOG_SELECTCA, NULL, NULL, NULL);
_JumpError(hr, error, "myGetConfigFromPicker");
}
if (S_OK != hr)
goto done;
if (NULL == pCAContext)
{
CertWarningMessageBox(
pData->hInstance,
FALSE,
pData->hDlg,
IDS_WRN_CALIST_EMPTY,
S_OK,
NULL);
SetWindowText(pData->hwndCAList, L"");
SetFocus(pData->hwndComputerEdit);
SendMessage(pData->hwndComputerEdit, EM_SETSEL, 0, -1);
}
else
{
CSILOG(hr, IDS_ILOG_SELECTCA, pCAContext->pwszCAMachineName, pCAContext->pwszCAName, NULL);
// update computer
SendMessage(pData->hwndComputerEdit, WM_SETTEXT,
0, (LPARAM)pCAContext->pwszCAMachineName);
// construct a single multi string for list update
DWORD len = wcslen(pCAContext->pwszCAName);
pwszzCAList = (WCHAR*)LocalAlloc(LMEM_FIXED, (len+2) * sizeof(WCHAR));
if (NULL == pwszzCAList)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(pwszzCAList, pCAContext->pwszCAName);
pwszzCAList[len+1] = '\0';
hr = UICASelectionUpdateCAList(pData->hwndCAList, pwszzCAList);
_JumpIfError(hr, error, "UICASelectionUpdateCAList");
LocalFree(pwszzCAList);
pwszzCAList = NULL;
// this thread blocks paint message, send it before ping
UpdateWindow(pData->hDlg);
// ping the computer to see if found a matched ca
if (!fCoInit)
{
hr = CoInitialize(NULL);
if (S_OK != hr && S_FALSE != hr)
{
_JumpError(hr, error, "CoInitialize");
}
fCoInit = TRUE;
}
SetCursor(LoadCursor(NULL, IDC_WAIT));
// ping to get ca list
hr = myPingCertSrv(
pCAContext->pwszCAMachineName,
NULL,
&pwszzCAList,
NULL,
NULL,
&dwVersion,
NULL);
SetCursor(LoadCursor(NULL, IDC_ARROW));
CSILOG(hr, IDS_ILOG_GETCANAME, pCAContext->pwszCAMachineName, NULL, NULL);
if (S_OK == hr)
{
//bug 262316: don't allow installing Whistler proxy to an older CA
if(dwVersion<2 && pData->fWebProxySetup)
{
hr = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION);
// focus on the CA list to trigger a verification of the CA
SetFocus(pData->hwndCAList);
} else
{
// ping successful
WCHAR const *pwszPingCA = pwszzCAList;
// go through the list to see if any match
while (NULL != pwszPingCA && L'\0' != pwszPingCA[0])
{
if (0 == wcscmp(pCAContext->pwszCAName, pwszPingCA))
{
// found matched one
goto done;
}
pwszPingCA += wcslen(pwszPingCA) + 1;
}
// if we get here, either the CA is offline or the machine is
// offline and another machine is using the same IP address.
CertWarningMessageBox(
pData->hInstance,
FALSE,
pData->hDlg,
IDS_WRN_CANAME_NOT_MATCH,
0,
NULL);
// only empty combo edit field
SetWindowText(pData->hwndCAList, L"");
SetFocus(pData->hwndCAList);
}
}
else
{
// can't ping the ca, selected an estranged ca
CertWarningMessageBox(
pData->hInstance,
FALSE,
pData->hDlg,
IDS_WRN_PINGCA_FAIL,
hr,
NULL);
// empty list anyway
hr = UICASelectionUpdateCAList(pData->hwndCAList, NULL);
_JumpIfError(hr, error, "UICASelectionUpdateCAList");
SetFocus(pData->hwndComputerEdit);
SendMessage(pData->hwndComputerEdit, EM_SETSEL, 0, -1);
}
}
done:
hr = myUICAConditionallyDisplayEnterpriseWarning(pData);
_PrintIfError(hr, "myUICAConditionallyDisplayEnterpriseWarning");
if (NULL != ppwszSharedFolder)
{
*ppwszSharedFolder = pwszTemp;
pwszTemp = NULL;
}
hr = S_OK;
error:
if (NULL != pwszzCAList)
{
LocalFree(pwszzCAList);
}
if (NULL != pwszSubTitle)
{
LocalFree(pwszSubTitle);
}
if (NULL != pwszTitle)
{
LocalFree(pwszTitle);
}
if (NULL != pwszTemp)
{
LocalFree(pwszTemp);
}
if (NULL != pwszComputer)
{
LocalFree(pwszComputer);
}
if (NULL != pCAContext)
{
CryptUIDlgFreeCAContext(pCAContext);
}
if (fCoInit)
{
CoUninitialize();
}
return hr;
}
HRESULT
myUICASelectionValidation(
CERTSRVUICASELECTION *pData,
BOOL *pfValidate)
{
HRESULT hr;
WCHAR *pwszComputer = NULL;
WCHAR *pwszCA = NULL;
CSASSERT(NULL != pData);
*pfValidate = FALSE;
// first, make sure not empty
hr = myUIGetWindowText(pData->hwndComputerEdit, &pwszComputer);
_JumpIfError(hr, error, "myUIGetWindowText");
if (NULL == pwszComputer)
{
CertWarningMessageBox(
pData->hInstance,
FALSE,
pData->hDlg,
IDS_WRN_COMPUTERNAME_EMPTY,
0,
NULL);
SetFocus(pData->hwndComputerEdit);
goto done;
}
hr = myUIGetWindowText(pData->hwndCAList, &pwszCA);
_JumpIfError(hr, error, "myUIGetWindowText");
if (NULL == pwszCA)
{
CertWarningMessageBox(
pData->hInstance,
FALSE,
pData->hDlg,
IDS_WRN_CANAME_EMPTY,
0,
NULL);
SetFocus(pData->hwndComputerEdit);
SendMessage(pData->hwndComputerEdit, EM_SETSEL, 0, -1);
goto done;
}
CSASSERT(pData->CAType != ENUM_UNKNOWN_CA);
if (pData->CAType == ENUM_UNKNOWN_CA)
{
hr = E_UNEXPECTED;
_JumpIfError(hr, error, "CAType not determined");
}
// if hit here
*pfValidate = TRUE;
done:
hr = S_OK;
error:
if (NULL != pwszComputer)
{
LocalFree(pwszComputer);
}
if (NULL != pwszCA)
{
LocalFree(pwszCA);
}
return hr;
}