windows-nt/Source/XPSP1/NT/ds/security/cryptoapi/ui/cryptui/selcert.cpp
2020-09-26 16:20:57 +08:00

1390 lines
43 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: selcert.cpp
//
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
extern HINSTANCE HinstDll;
extern HMODULE HmodRichEdit;
#define MAX_SIZE_OF_COLUMNS 400
static const HELPMAP helpmap[] = {
{IDC_SELECTCERT_VIEWCERT_BUTTON,IDH_SELECTCERTIFICATE_VIEWCERT_BUTTON},
{IDC_SELECTCERT_CERTLIST, IDH_SELECTCERTIFICATE_CERTIFICATE_LIST}
};
class CertContextList {
public:
CertContextList() : m_head(NULL) { }
~CertContextList();
HRESULT Add(IN PCCERT_CONTEXT pCertContext,
OUT BOOL *pfReplacedExisting) ;
HRESULT SyncWithStore(HCERTSTORE hStore, DWORD dwFlags);
private:
typedef struct _CertContextListEle {
PCCERT_CONTEXT pCertContext;
struct _CertContextListEle * pNext;
} CertContextListEle;
CertContextListEle * m_head;
};
typedef struct _CERT_SELECT_HELPER
{
PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc;
PCCERT_CONTEXT pSelectedCert;
DWORD rgdwSortParam[6];
BOOL fCertListDblClick;
CertContextList *pCertsFromDS;
} CERT_SELECT_HELPER, *PCERT_SELECT_HELPER;
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
static void AddCertToList(HWND hWndListView, PCERT_SELECT_HELPER pviewhelp, PCCERT_CONTEXT pCertContext, int itemIndex)
{
LPWSTR pwszText;
DWORD cbText;
WCHAR szText[CRYPTUI_MAX_STRING_SIZE];
int subItemIndex;
LV_ITEMW lvI;
PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc;
pcsc = pviewhelp->pcsc;
//
// set up the fields in the list view item
//
lvI.mask = LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
lvI.state = 0;
lvI.stateMask = 0;
lvI.iSubItem = 0;
lvI.iImage = 0;
lvI.lParam = (LPARAM) CertDuplicateCertificateContext(pCertContext);
lvI.iItem = itemIndex;
ListView_InsertItemU(hWndListView, &lvI);
subItemIndex = 0;
//
// issued to
//
if (!(pcsc->dwDontUseColumn & CRYPTUI_SELECT_ISSUEDTO_COLUMN))
{
CertGetNameStringW(
pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
0,//CERT_NAME_ISSUER_FLAG,
NULL,
szText,
ARRAYSIZE(szText));
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex++, szText);
}
//
// issued by
//
if (!(pcsc->dwDontUseColumn & CRYPTUI_SELECT_ISSUEDBY_COLUMN))
{
CertGetNameStringW(
pCertContext,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
CERT_NAME_ISSUER_FLAG,
NULL,
szText,
ARRAYSIZE(szText));
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex++, szText);
}
//
// intended use
//
if (!(pcsc->dwDontUseColumn & CRYPTUI_SELECT_INTENDEDUSE_COLUMN))
{
if (FormatEnhancedKeyUsageString(&pwszText, pCertContext, FALSE, FALSE))
{
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex, pwszText);
free(pwszText);
}
subItemIndex++;
}
//
// friendly name
//
if (!(pcsc->dwDontUseColumn & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN))
{
cbText = 0;
if (CertGetCertificateContextProperty( pCertContext,
CERT_FRIENDLY_NAME_PROP_ID,
NULL,
&cbText) &&
(NULL != (pwszText = (LPWSTR) malloc(cbText))))
{
CertGetCertificateContextProperty( pCertContext,
CERT_FRIENDLY_NAME_PROP_ID,
pwszText,
&cbText);
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex++, pwszText);
free(pwszText);
}
else
{
LoadStringU(HinstDll, IDS_FRIENDLYNAME_NONE, szText, ARRAYSIZE(szText));
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex++, szText);
}
}
//
// expiration
//
if (!(pcsc->dwDontUseColumn & CRYPTUI_SELECT_EXPIRATION_COLUMN))
{
if (!FormatDateString(&pwszText, pCertContext->pCertInfo->NotAfter, FALSE, FALSE, hWndListView))
{
LoadStringU(HinstDll, IDS_NOTAVAILABLE, szText, ARRAYSIZE(szText));
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex++, szText);
}
else
{
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex++, pwszText);
free(pwszText);
}
}
//
// location
//
if (!(pcsc->dwDontUseColumn & CRYPTUI_SELECT_LOCATION_COLUMN))
{
pwszText = (LPWSTR) GetStoreName(pCertContext->hCertStore, TRUE);
if (pwszText == NULL)
{
LoadStringU(HinstDll, IDS_NOTAVAILABLE, szText, ARRAYSIZE(szText));
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex++, szText);
}
else
{
ListView_SetItemTextU(hWndListView, itemIndex , subItemIndex++, pwszText);
free(pwszText);
}
}
}
static int ReplaceCertInList(HWND hWndListView, PCERT_SELECT_HELPER pviewhelp, PCCERT_CONTEXT pCertContext)
{
int nIndex = -1;
LV_ITEM lvitem;
while (-1 != (nIndex = ListView_GetNextItem(hWndListView, nIndex, LVNI_ALL)))
{
//DSIE: Bug 420717
memset(&lvitem, 0, sizeof(lvitem));
lvitem.iItem = nIndex;
lvitem.mask = LVIF_PARAM;
if (ListView_GetItem(hWndListView, &lvitem))
{
PCCERT_CONTEXT pCurrent = (PCCERT_CONTEXT)lvitem.lParam;
if (pCurrent->dwCertEncodingType == pCertContext->dwCertEncodingType)
{
if (CertCompareCertificate(pCertContext->dwCertEncodingType,
pCertContext->pCertInfo,
pCurrent->pCertInfo))
{
// Found a match, replace the certificate.
CertFreeCertificateContext(pCurrent);
ListView_DeleteItem(hWndListView, nIndex);
// Now, add our new certificate at this index.
AddCertToList(hWndListView, pviewhelp, pCertContext, nIndex);
goto CommonReturn;
}
}
}
}
// No match, nothing to replace, just append to the list.
AddCertToList(hWndListView, pviewhelp, pCertContext, ListView_GetItemCount(hWndListView));
CommonReturn:
return nIndex;
}
// DSIE: Bug 207106
BOOL SupportEncryptedFileSystem(PCCERT_CONTEXT pCertContext)
{
BOOL fSuccess = FALSE;
DWORD cbUsage = 0;
PCERT_ENHKEY_USAGE pUsage = NULL;
if (!pCertContext)
return FALSE;
if (!CertGetEnhancedKeyUsage(pCertContext, 0, NULL, &cbUsage))
goto CleanUp;
if (NULL == (pUsage = (PCERT_ENHKEY_USAGE) malloc(cbUsage)))
goto CleanUp;
if (!CertGetEnhancedKeyUsage(pCertContext, 0, pUsage, &cbUsage))
goto CleanUp;
if (0 == pUsage->cUsageIdentifier)
{
if (CRYPT_E_NOT_FOUND == GetLastError())
{
fSuccess = TRUE;
}
}
else
{
for (DWORD i = 0; i < pUsage->cUsageIdentifier; i++)
{
if (0 == strcmp(szOID_ENHANCED_KEY_USAGE, pUsage->rgpszUsageIdentifier[i]))
{
fSuccess = TRUE;
goto CleanUp;
}
}
}
CleanUp:
if (pUsage)
free(pUsage);
return fSuccess;
}
//DSIE: Bug 314005. Major change to switch over to use Object Picker.
HRESULT AddFromDS(HWND hwndDlg, PCERT_SELECT_HELPER pviewhelp)
{
static const int SCOPE_INIT_COUNT = 1;
IDsObjectPicker * pDsObjectPicker = NULL;
IDataObject * pdo = NULL;
DSOP_SCOPE_INIT_INFO aScopeInit[SCOPE_INIT_COUNT];
DSOP_INIT_INFO InitInfo;
UINT cfDsObjectPicker = RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
HWND hWndListView = NULL;
BOOL fGotStgMedium = FALSE;
PDS_SELECTION_LIST pDsSelList = NULL;
STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL, NULL};
FORMATETC formatetc = {(CLIPFORMAT) cfDsObjectPicker, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
HRESULT hr;
HCERTSTORE hDSCertStore = NULL;
PCCERT_CONTEXT pCertContext = NULL;
PCCERT_CONTEXT pCertContextPrev = NULL;
CertContextList * pCertContextList = NULL;
WCHAR errorString[512];
WCHAR errorTitle[512];
BOOL fInitialSelectedCert = FALSE;
PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc = NULL;
// Input validation:
if (NULL == hwndDlg ||
NULL == pviewhelp ||
NULL == pviewhelp->pcsc ||
NULL == pviewhelp->pCertsFromDS)
return E_INVALIDARG;
// Init:
pcsc = pviewhelp->pcsc;
pCertContextList = pviewhelp->pCertsFromDS;
hWndListView = GetDlgItem(hwndDlg, IDC_SELECTCERT_CERTLIST);
CoInitialize(NULL);
hr = CoCreateInstance(CLSID_DsObjectPicker,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDsObjectPicker,
(void **) &pDsObjectPicker);
if (FAILED(hr) || NULL == pDsObjectPicker)
goto ComError;
// Initialize the DSOP_SCOPE_INIT_INFO array.
ZeroMemory(aScopeInit, sizeof(DSOP_SCOPE_INIT_INFO) * SCOPE_INIT_COUNT);
// Combine multiple scope types in a single array entry.
aScopeInit[0].cbSize = sizeof(DSOP_SCOPE_INIT_INFO);
aScopeInit[0].flType = DSOP_SCOPE_TYPE_UPLEVEL_JOINED_DOMAIN
| DSOP_SCOPE_TYPE_DOWNLEVEL_JOINED_DOMAIN;
// Set uplevel and downlevel filters to include only computer objects.
// Uplevel filters apply to both mixed and native modes.
// Notice that the uplevel and downlevel flags are different.
aScopeInit[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_USERS;
aScopeInit[0].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_USERS;
// Initialize the DSOP_INIT_INFO structure.
ZeroMemory(&InitInfo, sizeof(InitInfo));
InitInfo.cbSize = sizeof(InitInfo);
InitInfo.pwzTargetComputer = NULL; // Target is the local computer.
InitInfo.cDsScopeInfos = SCOPE_INIT_COUNT;
InitInfo.aDsScopeInfos = aScopeInit;
//InitInfo.flOptions = DSOP_FLAG_MULTISELECT;
// You can call Initialize multiple times; last call wins.
// Note that object picker makes its own copy of InitInfo.
hr = pDsObjectPicker->Initialize(&InitInfo);
if (FAILED(hr))
goto ComError;
// Invoke the modal dialog.
hr = pDsObjectPicker->InvokeDialog(hwndDlg, &pdo);
if (FAILED(hr))
goto ComError;
// User pressed Cancel.
if (hr == S_FALSE)
{
hr = E_ABORT;
goto cleanup;
}
// Get the global memory block containing the user's selections.
hr = pdo->GetData(&formatetc, &stgmedium);
if (FAILED(hr))
goto ComError;
fGotStgMedium = TRUE;
// Retrieve pointer to DS_SELECTION_LIST structure.
pDsSelList = (PDS_SELECTION_LIST) GlobalLock(stgmedium.hGlobal);
if (!pDsSelList)
goto ComError;
// Loop through DS_SELECTION array of selected objects.
for (ULONG i = 0; i < pDsSelList->cItems; i++)
{
WCHAR pwszLdapUrl[2048];
LPWSTR pTemp = pDsSelList->aDsSelection[i].pwzADsPath;
BOOL fReplacedExisting;
BOOL fHasEFSCerts = FALSE;
// Now is the time to get the certificate
LPCWSTR szCertAttr = L"?userCertificate";
// Check if our buffer is too small to hold the query.
if (wcslen(pTemp) + wcslen(szCertAttr) + 1 > (sizeof(pwszLdapUrl) / sizeof(pwszLdapUrl[0])))
goto UnexpectedErr;
wcscpy(pwszLdapUrl, pTemp);
wcscat(pwszLdapUrl, szCertAttr);
// Now open the DS store using LDAP provider.
hDSCertStore = CertOpenStore(sz_CERT_STORE_PROV_LDAP,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
NULL,
CERT_STORE_READONLY_FLAG,
(void*) pwszLdapUrl);
if (NULL == hDSCertStore)
goto CertCliError;
// We get the certificate store
pCertContext = NULL;
pCertContextPrev = NULL;
int nItemIndex;
while (NULL != (pCertContext = CertEnumCertificatesInStore(hDSCertStore, pCertContextPrev)))
{
// Apply our filter callback function to see if we should display this certificate.
BOOL fAllowCert = FALSE;
if (pcsc->pFilterCallback)
fAllowCert = (*(pcsc->pFilterCallback))(pCertContext, &fInitialSelectedCert, pcsc->pvCallbackData);
fAllowCert |= SupportEncryptedFileSystem(pCertContext);
if (fAllowCert)
{
fHasEFSCerts = TRUE;
if (S_OK != (hr = pCertContextList->Add(pCertContext, &fReplacedExisting)))
goto ErrorReturn;
nItemIndex = ReplaceCertInList(hWndListView, pviewhelp, pCertContext);
// if the select cert dialog caller said that this should be the initially
// selected cert then make it so.
if (fInitialSelectedCert)
ListView_SetItemState(hWndListView, nItemIndex, LVIS_SELECTED, LVIS_SELECTED);
}
pCertContextPrev = pCertContext;
}
// We didn't reach the end of the enumeration. This is an error.
if (GetLastError() != CRYPT_E_NOT_FOUND)
goto CertCliError;
// We didn't find any EFS certs: display an error message and pop up the window again.
if (!fHasEFSCerts)
goto NoEfsError;
}
hr = S_OK;
cleanup:
if (hDSCertStore)
{
CertCloseStore(hDSCertStore, 0);
}
if (NULL != pCertContext)
{
CertFreeCertificateContext(pCertContext);
}
if (pDsSelList)
{
GlobalUnlock(stgmedium.hGlobal);
}
if (fGotStgMedium)
{
ReleaseStgMedium(&stgmedium);
}
if (pdo)
{
pdo->Release();
}
if (pDsObjectPicker)
{
pDsObjectPicker->Release();
}
CoUninitialize();
return hr;
ErrorReturn:
{
WCHAR wszText[MAX_STRING_SIZE];
WCHAR errorTitle2[MAX_STRING_SIZE];
LPWSTR pwszErrorMsg = NULL;
//get the text string
if(LoadStringU(HinstDll, IDS_INTERNAL_ERROR, wszText, sizeof(wszText) / sizeof(wszText[0])))
{
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR) &pwszErrorMsg,
0,
NULL))
{
if (LoadStringU(HinstDll, IDS_SELECT_CERTIFICATE_TITLE, errorTitle2, ARRAYSIZE(errorTitle2))) {
MessageBoxU(hwndDlg, pwszErrorMsg, errorTitle2, MB_ICONERROR|MB_OK|MB_APPLMODAL);
}
}
}
if (NULL != pwszErrorMsg) { LocalFree(pwszErrorMsg); }
}
goto cleanup;
CertCliError:
hr = HRESULT_FROM_WIN32(GetLastError());
goto ErrorReturn;
ComError:
goto ErrorReturn;
NoEfsError:
LoadStringU(HinstDll, IDS_SELECT_CERT_NO_CERT_ERROR, errorString, ARRAYSIZE(errorString));
if (pcsc->szTitle != NULL)
{
MessageBoxU(hwndDlg, errorString, pcsc->szTitle, MB_OK | MB_ICONWARNING);
}
else
{
LoadStringU(HinstDll, IDS_SELECT_CERTIFICATE_TITLE, errorTitle, ARRAYSIZE(errorTitle));
MessageBoxU(hwndDlg, errorString, errorTitle, MB_OK | MB_ICONWARNING);
}
hr = AddFromDS(hwndDlg, pviewhelp);
goto cleanup;
UnexpectedErr:
hr = E_UNEXPECTED;
goto ErrorReturn;
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
static void AddCertsToList(HWND hWndListView, PCERT_SELECT_HELPER pviewhelp)
{
DWORD i;
PCCERT_CONTEXT pCertContext;
int itemIndex = 0;
PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc;
BOOL fInitialSelectedCert = FALSE;
pcsc = pviewhelp->pcsc;
//
// loop for each store and display the certs in each store
//
for (i=0; i<pcsc->cDisplayStores; i++)
{
//
// loop for each cert in the store
//
pCertContext = NULL;
while (NULL != (pCertContext = CertEnumCertificatesInStore(pcsc->rghDisplayStores[i], pCertContext)))
{
fInitialSelectedCert = FALSE;
if ((pcsc->pFilterCallback == NULL) ||
((*(pcsc->pFilterCallback))(pCertContext, &fInitialSelectedCert, pcsc->pvCallbackData) == TRUE))
{
AddCertToList(hWndListView, pviewhelp, pCertContext, itemIndex);
//
// if the select cert dialog caller said that this should be the initially
// selected cert then make it so.
//
if (fInitialSelectedCert)
{
ListView_SetItemState(hWndListView, itemIndex, LVIS_SELECTED, LVIS_SELECTED);
}
itemIndex++;
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
static int CalculateColumnWidth(DWORD dwDontUseColumn)
{
int numColumns = 0;
if (!(dwDontUseColumn & CRYPTUI_SELECT_ISSUEDTO_COLUMN))
{
numColumns++;
}
if (!(dwDontUseColumn & CRYPTUI_SELECT_ISSUEDBY_COLUMN))
{
numColumns++;
}
if (!(dwDontUseColumn & CRYPTUI_SELECT_INTENDEDUSE_COLUMN))
{
numColumns++;
}
if (!(dwDontUseColumn & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN))
{
numColumns++;
}
if (!(dwDontUseColumn & CRYPTUI_SELECT_EXPIRATION_COLUMN))
{
numColumns++;
}
if (!(dwDontUseColumn & CRYPTUI_SELECT_LOCATION_COLUMN))
{
numColumns++;
}
if (numColumns >= 2)
{
return (MAX_SIZE_OF_COLUMNS / numColumns);
}
else
{
return MAX_SIZE_OF_COLUMNS;
}
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
INT_PTR APIENTRY SelectCertDialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
WCHAR szText[CRYPTUI_MAX_STRING_SIZE];
HWND hWndListView;
LV_COLUMNW lvC;
int iCol = 0;
LV_ITEMW lvI;
int listIndex;
LPNMLISTVIEW pnmv;
PCERT_SELECT_HELPER pviewhelp;
PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc;
WCHAR errorString[CRYPTUI_MAX_STRING_SIZE];
WCHAR errorTitle[CRYPTUI_MAX_STRING_SIZE];
HWND hwnd;
HIMAGELIST hIml;
DWORD dwSortParam;
int SortParamIndex;
switch ( msg ) {
case WM_INITDIALOG:
pviewhelp = (PCERT_SELECT_HELPER) lParam;
SetWindowLongPtr(hwndDlg, DWLP_USER, (DWORD_PTR) pviewhelp);
pcsc = pviewhelp->pcsc;
//
// set the dialog title and the display string
//
if (pcsc->szTitle != NULL)
{
SetWindowTextU(hwndDlg, pcsc->szTitle);
}
if (pcsc->szDisplayString != NULL)
{
SetDlgItemTextU(hwndDlg, IDC_SELECTCERT_DISPLAYSTRING, pcsc->szDisplayString);
}
else
{
if (pcsc->dwFlags & CRYPTUI_SELECTCERT_MULTISELECT)
{
LoadStringU(HinstDll, IDS_SELECT_MULTIPLE_CERT_DEFAULT, szText, ARRAYSIZE(szText));
}
else
{
LoadStringU(HinstDll, IDS_SELECT_CERT_DEFAULT, szText, ARRAYSIZE(szText));
}
SetDlgItemTextU(hwndDlg, IDC_SELECTCERT_DISPLAYSTRING, szText);
}
hWndListView = GetDlgItem(hwndDlg, IDC_SELECTCERT_CERTLIST);
//
// initialize the image list for the list view
//
hIml = ImageList_LoadImage(HinstDll, MAKEINTRESOURCE(IDB_CERT), 0, 1, RGB(255,0,255), IMAGE_BITMAP, 0);
ListView_SetImageList(hWndListView, hIml, LVSIL_SMALL);
//
// add the colums to the list view
//
lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;// | LVCF_SUBITEM;
lvC.fmt = LVCFMT_LEFT; // Left-align the column.
lvC.pszText = szText; // The text for the column.
lvC.cx = CalculateColumnWidth(pviewhelp->pcsc->dwDontUseColumn);
memset(&(pviewhelp->rgdwSortParam[0]), 0, ARRAYSIZE(pviewhelp->rgdwSortParam));
SortParamIndex = 0;
if (!(pviewhelp->pcsc->dwDontUseColumn & CRYPTUI_SELECT_ISSUEDTO_COLUMN))
{
LoadStringU(HinstDll, IDS_ISSUEDTO2, szText, ARRAYSIZE(szText));
if (ListView_InsertColumnU(hWndListView, iCol++, &lvC) == -1)
{
// error
}
pviewhelp->rgdwSortParam[SortParamIndex++] = SORT_COLUMN_SUBJECT | SORT_COLUMN_ASCEND;
}
if (!(pviewhelp->pcsc->dwDontUseColumn & CRYPTUI_SELECT_ISSUEDBY_COLUMN))
{
LoadStringU(HinstDll, IDS_ISSUEDBY2, szText, ARRAYSIZE(szText));
if (ListView_InsertColumnU(hWndListView, iCol++, &lvC) == -1)
{
// error
}
pviewhelp->rgdwSortParam[SortParamIndex++] = SORT_COLUMN_ISSUER | SORT_COLUMN_DESCEND;
}
if (!(pviewhelp->pcsc->dwDontUseColumn & CRYPTUI_SELECT_INTENDEDUSE_COLUMN))
{
LoadStringU(HinstDll, IDS_INTENDED_PURPOSE, szText, ARRAYSIZE(szText));
if (ListView_InsertColumnU(hWndListView, iCol++, &lvC) == -1)
{
// error
}
pviewhelp->rgdwSortParam[SortParamIndex++] =SORT_COLUMN_PURPOSE | SORT_COLUMN_DESCEND;
}
if (!(pviewhelp->pcsc->dwDontUseColumn & CRYPTUI_SELECT_FRIENDLYNAME_COLUMN))
{
LoadStringU(HinstDll, IDS_CERTIFICATE_NAME, szText, ARRAYSIZE(szText));
if (ListView_InsertColumnU(hWndListView, iCol++, &lvC) == -1)
{
// error
}
pviewhelp->rgdwSortParam[SortParamIndex++] = SORT_COLUMN_NAME | SORT_COLUMN_DESCEND;
}
if (!(pviewhelp->pcsc->dwDontUseColumn & CRYPTUI_SELECT_EXPIRATION_COLUMN))
{
LoadStringU(HinstDll, IDS_EXPIRATION_DATE, szText, ARRAYSIZE(szText));
if (ListView_InsertColumnU(hWndListView, iCol++, &lvC) == -1)
{
// error
}
pviewhelp->rgdwSortParam[SortParamIndex++] = SORT_COLUMN_EXPIRATION | SORT_COLUMN_DESCEND;
}
if (!(pviewhelp->pcsc->dwDontUseColumn & CRYPTUI_SELECT_LOCATION_COLUMN))
{
LoadStringU(HinstDll, IDS_LOCATION, szText, ARRAYSIZE(szText));
if (ListView_InsertColumnU(hWndListView, iCol++, &lvC) == -1)
{
// error
}
pviewhelp->rgdwSortParam[SortParamIndex++] = SORT_COLUMN_LOCATION | SORT_COLUMN_DESCEND;
}
AddCertsToList(hWndListView, pviewhelp);
//
// if there is no cert selected initially disable the "view cert button"
//
if (ListView_GetSelectedCount(hWndListView) == 0)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_SELECTCERT_VIEWCERT_BUTTON), FALSE);
}
//
// set the style in the list view so that it highlights an entire line
//
SendMessageA(hWndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
#if (1) // DSIE: bug 338852.
HWND hwndFindUser;
if (hwndFindUser = GetDlgItem(hwndDlg, IDC_SELECTCERT_ADDFROMDS_BUTTON))
{
LPBYTE pDCName = NULL;
DWORD dwError = NetGetDCName(NULL, NULL, &pDCName);
if (NERR_Success == dwError)
{
NetApiBufferFree(pDCName);
}
else
{
EnableWindow(hwndFindUser, FALSE);
}
}
#endif
ListView_SetItemState(hWndListView,
0,
LVIS_FOCUSED | LVIS_SELECTED,
LVIS_FOCUSED | LVIS_SELECTED);
SetFocus(hWndListView);
break;
case WM_NOTIFY:
pviewhelp = (PCERT_SELECT_HELPER) GetWindowLongPtr(hwndDlg, DWLP_USER);
pcsc = pviewhelp->pcsc;
hWndListView = GetDlgItem(hwndDlg, IDC_SELECTCERT_CERTLIST);
switch (((NMHDR FAR *) lParam)->code)
{
case NM_DBLCLK:
switch (((NMHDR FAR *) lParam)->idFrom)
{
case IDC_SELECTCERT_CERTLIST:
if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SELECTCERT_VIEWCERT_BUTTON)))
{
pviewhelp->fCertListDblClick = TRUE;
SendMessage(
hwndDlg,
WM_COMMAND,
MAKELONG(IDC_SELECTCERT_VIEWCERT_BUTTON, BN_CLICKED),
(LPARAM) GetDlgItem(hwndDlg, IDC_SELECTCERT_VIEWCERT_BUTTON));
}
break;
}
break;
case LVN_ITEMCHANGING:
pnmv = (LPNMLISTVIEW) lParam;
switch (((NMHDR FAR *) lParam)->idFrom)
{
case IDC_SELECTCERT_CERTLIST:
if (!(pcsc->dwFlags & CRYPTUI_SELECTCERT_MULTISELECT))
{
if (pnmv->uNewState & LVIS_SELECTED)
{
ListView_SetItemState(
hWndListView,
ListView_GetNextItem(hWndListView, -1, LVNI_SELECTED),
~LVIS_SELECTED,
LVIS_SELECTED);
EnableWindow(GetDlgItem(hwndDlg, IDC_SELECTCERT_VIEWCERT_BUTTON), TRUE);
}
}
break;
}
break;
case LVN_ITEMCHANGED:
pnmv = (LPNMLISTVIEW) lParam;
switch (((NMHDR FAR *) lParam)->idFrom)
{
case IDC_SELECTCERT_CERTLIST:
if (ListView_GetSelectedCount(hWndListView) == 1)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_SELECTCERT_VIEWCERT_BUTTON), TRUE);
}
else
{
EnableWindow(GetDlgItem(hwndDlg, IDC_SELECTCERT_VIEWCERT_BUTTON), FALSE);
}
}
break;
case NM_SETFOCUS:
switch (((NMHDR FAR *) lParam)->idFrom)
{
case IDC_SELECTCERT_CERTLIST:
hWndListView = GetDlgItem(hwndDlg, IDC_SELECTCERT_CERTLIST);
if ((ListView_GetItemCount(hWndListView) != 0) &&
(ListView_GetNextItem(hWndListView, -1, LVNI_SELECTED) == -1))
{
memset(&lvI, 0, sizeof(lvI));
lvI.mask = LVIF_STATE;
lvI.iItem = 0;
lvI.state = LVIS_FOCUSED;
lvI.stateMask = LVIS_FOCUSED;
ListView_SetItem(hWndListView, &lvI);
}
break;
}
break;
case LVN_COLUMNCLICK:
pnmv = (NM_LISTVIEW FAR *) lParam;
//
// get the column number
//
dwSortParam = 0;
switch (pnmv->iSubItem)
{
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
dwSortParam = pviewhelp->rgdwSortParam[pnmv->iSubItem];
break;
default:
dwSortParam = 0;
break;
}
if (0 != dwSortParam)
{
//
// flip the ascend ording
//
if (dwSortParam & SORT_COLUMN_ASCEND)
{
dwSortParam &= 0x0000FFFF;
dwSortParam |= SORT_COLUMN_DESCEND;
}
else
{
if (dwSortParam & SORT_COLUMN_DESCEND)
{
dwSortParam &= 0x0000FFFF;
dwSortParam |= SORT_COLUMN_ASCEND;
}
}
//
// sort the column
//
SendDlgItemMessage(hwndDlg,
IDC_SELECTCERT_CERTLIST,
LVM_SORTITEMS,
(WPARAM) (LPARAM) dwSortParam,
(LPARAM) (PFNLVCOMPARE)CompareCertificate);
pviewhelp->rgdwSortParam[pnmv->iSubItem] = dwSortParam;
}
break;
}
break;
case WM_COMMAND:
pviewhelp = (PCERT_SELECT_HELPER) GetWindowLongPtr(hwndDlg, DWLP_USER);
pcsc = pviewhelp->pcsc;
hWndListView = GetDlgItem(hwndDlg, IDC_SELECTCERT_CERTLIST);
switch (LOWORD(wParam))
{
case IDC_SELECTCERT_ADDFROMDS_BUTTON:
{
HRESULT hr = AddFromDS(hwndDlg, pviewhelp);
if (FAILED(hr))
{
// Error
}
break;
}
case IDC_SELECTCERT_VIEWCERT_BUTTON:
CRYPTUI_VIEWCERTIFICATE_STRUCTW cvps;
BOOL fPropertiesChanged;
listIndex = ListView_GetNextItem(
hWndListView,
-1,
LVNI_SELECTED
);
if (listIndex != -1)
{
memset(&lvI, 0, sizeof(lvI));
lvI.iItem = listIndex;
lvI.mask = LVIF_PARAM;
if (ListView_GetItemU(hWndListView, &lvI))
{
//
// if the caller handed in a callback call them to see if they
// want to handle the display of the cert, otherwise display the cert
//
if ((pcsc->pDisplayCallback != NULL) &&
((*(pcsc->pDisplayCallback))((PCCERT_CONTEXT) lvI.lParam, hwndDlg, pcsc->pvCallbackData) == TRUE))
{
//
// set the fPropertiesChanged bool to true so that the cert will
// get refreshed in the display. this doesn't hurt anything even
// if the cert didn't change
//
fPropertiesChanged = TRUE;
}
else
{
memset(&cvps, 0, sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW));
cvps.dwSize = sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCTW);
cvps.hwndParent = hwndDlg;
cvps.pCertContext = (PCCERT_CONTEXT) lvI.lParam;
cvps.cStores = pviewhelp->pcsc->cStores;
cvps.rghStores = pviewhelp->pcsc->rghStores;
cvps.cPropSheetPages = pviewhelp->pcsc->cPropSheetPages;
cvps.rgPropSheetPages = pviewhelp->pcsc->rgPropSheetPages;
CryptUIDlgViewCertificateW(&cvps, &fPropertiesChanged);
}
//
// if the properties changed then refresh the cert in the list
//
if (fPropertiesChanged)
{
ListView_DeleteItem(hWndListView, listIndex);
AddCertToList(hWndListView, pviewhelp, (PCCERT_CONTEXT) lvI.lParam, listIndex);
ListView_SetItemState(hWndListView, listIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
}
if (!pviewhelp->fCertListDblClick)
{
SetFocus(GetDlgItem(hwndDlg, IDC_SELECTCERT_VIEWCERT_BUTTON));
}
pviewhelp->fCertListDblClick = FALSE;
}
}
break;
case IDOK:
listIndex = ListView_GetNextItem(
hWndListView,
-1,
LVNI_SELECTED
);
if (listIndex != -1)
{
memset(&lvI, 0, sizeof(lvI));
lvI.iItem = listIndex;
lvI.mask = LVIF_PARAM;
if (!(pcsc->dwFlags & CRYPTUI_SELECTCERT_MULTISELECT))
{
if (ListView_GetItemU(hWndListView, &lvI))
{
pviewhelp->pSelectedCert = CertDuplicateCertificateContext((PCCERT_CONTEXT) lvI.lParam);
}
}
else
{
if (ListView_GetItemU(hWndListView, &lvI))
{
CertAddCertificateContextToStore(
pcsc->hSelectedCertStore,
(PCCERT_CONTEXT) lvI.lParam,
CERT_STORE_ADD_ALWAYS,
NULL);
}
while (-1 != (listIndex = ListView_GetNextItem(
hWndListView,
listIndex,
LVNI_SELECTED
)))
{
lvI.iItem = listIndex;
if (ListView_GetItemU(hWndListView, &lvI))
{
CertAddCertificateContextToStore(
pcsc->hSelectedCertStore,
(PCCERT_CONTEXT) lvI.lParam,
CERT_STORE_ADD_ALWAYS,
NULL);
}
}
}
}
else
{
LoadStringU(HinstDll, IDS_SELECT_CERT_ERROR, errorString, ARRAYSIZE(errorString));
if (pcsc->szTitle != NULL)
{
MessageBoxU(hwndDlg, errorString, pcsc->szTitle, MB_OK | MB_ICONWARNING);
}
else
{
LoadStringU(HinstDll, IDS_SELECT_CERTIFICATE_TITLE, errorTitle, ARRAYSIZE(errorTitle));
MessageBoxU(hwndDlg, errorString, errorTitle, MB_OK | MB_ICONWARNING);
}
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LRESULT)TRUE);
return TRUE;
}
EndDialog(hwndDlg, NULL);
break;
case IDCANCEL:
EndDialog(hwndDlg, NULL);
break;
}
break;
case WM_DESTROY:
pviewhelp = (PCERT_SELECT_HELPER) GetWindowLongPtr(hwndDlg, DWLP_USER);
hWndListView = GetDlgItem(hwndDlg, IDC_SELECTCERT_CERTLIST);
memset(&lvI, 0, sizeof(lvI));
lvI.iItem = ListView_GetItemCount(hWndListView) - 1;
lvI.mask = LVIF_PARAM;
while (lvI.iItem >= 0)
{
if (ListView_GetItemU(hWndListView, &lvI))
{
CertFreeCertificateContext((PCCERT_CONTEXT) lvI.lParam);
}
lvI.iItem--;
}
break;
case WM_HELP:
case WM_CONTEXTMENU:
if (msg == WM_HELP)
{
hwnd = GetDlgItem(hwndDlg, ((LPHELPINFO)lParam)->iCtrlId);
}
else
{
hwnd = (HWND) wParam;
}
if ((hwnd != GetDlgItem(hwndDlg, IDOK)) &&
(hwnd != GetDlgItem(hwndDlg, IDCANCEL)) &&
(hwnd != GetDlgItem(hwndDlg, IDC_SELECTCERT_VIEWCERT_BUTTON)) &&
(hwnd != GetDlgItem(hwndDlg, IDC_SELECTCERT_CERTLIST)))
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LRESULT)TRUE);
return TRUE;
}
else
{
return OnContextHelp(hwndDlg, msg, wParam, lParam, helpmap);
}
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
PCCERT_CONTEXT
WINAPI
CryptUIDlgSelectCertificateW(
PCCRYPTUI_SELECTCERTIFICATE_STRUCTW pcsc
)
{
CERT_SELECT_HELPER viewhelper;
WORD wDialogID;
if (CommonInit() == FALSE)
{
return NULL;
}
if ((pcsc->dwSize != sizeof(CRYPTUI_SELECTCERTIFICATE_STRUCTW)) &&
(pcsc->dwSize != offsetof(CRYPTUI_SELECTCERTIFICATE_STRUCTW, hSelectedCertStore))) {
SetLastError(E_INVALIDARG);
return FALSE;
}
wDialogID =
pcsc->dwFlags & CRYPTUI_SELECTCERT_ADDFROMDS ?
IDD_SELECTCERT_DIALOG_WITH_DSPICKER :
IDD_SELECTCERT_DIALOG;
viewhelper.pcsc = pcsc;
viewhelper.pSelectedCert = NULL;
viewhelper.fCertListDblClick = FALSE;
viewhelper.pCertsFromDS = new CertContextList;
if (NULL == viewhelper.pCertsFromDS)
{
SetLastError(E_OUTOFMEMORY);
return FALSE;
}
if (DialogBoxParamU(
HinstDll,
(LPWSTR) MAKEINTRESOURCE(wDialogID),
(pcsc->hwndParent != NULL) ? pcsc->hwndParent : GetDesktopWindow(),
SelectCertDialogProc,
(LPARAM) &viewhelper) != -1)
{
SetLastError(0);
}
delete viewhelper.pCertsFromDS;
if (pcsc->dwFlags & CRYPTUI_SELECTCERT_MULTISELECT)
{
return NULL;
}
else
{
return(viewhelper.pSelectedCert);
}
}
//////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
PCCERT_CONTEXT
WINAPI
CryptUIDlgSelectCertificateA(
PCCRYPTUI_SELECTCERTIFICATE_STRUCTA pcsc
)
{
CRYPTUI_SELECTCERTIFICATE_STRUCTW cscW;
PCCERT_CONTEXT pReturnCert = NULL;
memcpy(&cscW, pcsc, sizeof(cscW));
if (!ConvertToPropPageW(
pcsc->rgPropSheetPages,
pcsc->cPropSheetPages,
&(cscW.rgPropSheetPages)))
{
return NULL;
}
if (pcsc->szTitle)
{
cscW.szTitle = CertUIMkWStr(pcsc->szTitle);
}
if (pcsc->szDisplayString)
{
cscW.szDisplayString = CertUIMkWStr(pcsc->szDisplayString);
}
pReturnCert = CryptUIDlgSelectCertificateW(&cscW);
FreePropSheetPagesW((LPPROPSHEETPAGEW) cscW.rgPropSheetPages, cscW.cPropSheetPages);
if (cscW.szTitle)
{
free((void *) cscW.szTitle);
}
if (cscW.szDisplayString)
{
free((void *) cscW.szDisplayString);
}
return(pReturnCert);
}
////////////////////////////////////////////////////////////
//
// Implementation of utility class: CertContextList
//
////////////////////////////////////////////////////////////
CertContextList::~CertContextList()
{
CertContextListEle *pListEle;
CertContextListEle *pListEleNext;
for (pListEle = m_head; pListEle != NULL; pListEle = pListEleNext)
{
pListEleNext = pListEle->pNext;
if (pListEle->pCertContext != NULL) { CertFreeCertificateContext(pListEle->pCertContext); }
delete pListEle;
}
}
HRESULT CertContextList::Add(IN PCCERT_CONTEXT pCertContext,
OUT BOOL *pfReplacedExisting)
{
HRESULT hr = S_OK;
CertContextListEle *pListEle = NULL;
CertContextListEle *pListElePrev = NULL;
if (pCertContext == NULL || pfReplacedExisting == NULL)
return E_INVALIDARG;
for (pListEle = m_head; pListEle != NULL; pListEle = pListEle->pNext)
{
PCCERT_CONTEXT pCurrent = pListEle->pCertContext;
if (pCurrent->dwCertEncodingType == pCertContext->dwCertEncodingType)
{
if (CertCompareCertificate
(pCertContext->dwCertEncodingType,
pCertContext->pCertInfo,
pCurrent->pCertInfo))
{
// We're replacing an existing element.
*pfReplacedExisting = TRUE;
CertFreeCertificateContext(pListEle->pCertContext);
pListEle->pCertContext = CertDuplicateCertificateContext(pCertContext);
goto CommonReturn;
}
}
pListElePrev = pListEle;
}
// Didn't find the cert in the list, append it.
if (pListElePrev == NULL)
{
// Special case: this is the first cert we've added.
pListElePrev = new CertContextListEle;
if (pListElePrev == NULL)
goto MemoryErr;
pListEle = pListElePrev;
m_head = pListEle;
}
else
{
pListElePrev->pNext = new CertContextListEle;
if (pListElePrev->pNext == NULL)
goto MemoryErr;
pListEle = pListElePrev->pNext;
}
pListEle->pCertContext = CertDuplicateCertificateContext(pCertContext);
pListEle->pNext = NULL;
CommonReturn:
return hr;
MemoryErr:
hr = E_OUTOFMEMORY;
goto CommonReturn;
}
HRESULT CertContextList::SyncWithStore(HCERTSTORE hStore, DWORD dwFlags)
{
CertContextListEle * pListEle;
for (pListEle = m_head; pListEle != NULL; pListEle = pListEle->pNext)
{
if (!CertAddCertificateContextToStore
(hStore,
pListEle->pCertContext,
dwFlags,
NULL))
return HRESULT_FROM_WIN32(GetLastError());
}
return S_OK;
}