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.
 
 
 
 
 
 

1615 lines
37 KiB

//+----------------------------------------------------------------------------
//
// Windows NT Directory Service Property Pages
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: UserCert.cxx
//
// Contents:
//
// History: 12-November-97 BryanWal created
//
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "certca.h"
#include "tfcprop.h"
#include "genpage.h"
#include "commdlg.h"
#include "caprop.h"
#define ByteOffset(base, offset) (((LPBYTE)base)+offset)
//+----------------------------------------------------------------------------
//
// Member: CDsCACertPage::CDsCACertPage
//
//-----------------------------------------------------------------------------
CDsCACertPage::CDsCACertPage(LPWSTR wszObjectDN, UINT uIDD) : CAutoDeletePropPage(uIDD),
m_strObjectDN(wszObjectDN),
m_hCertStore (0),
m_hImageList (0),
m_hbmCert (0),
m_nCertImageIndex (0)
{
::ZeroMemory (&m_selCertStruct, sizeof (m_selCertStruct));
}
//+----------------------------------------------------------------------------
//
// Member: CDsCACertPage::~CDsCACertPage
//
//-----------------------------------------------------------------------------
CDsCACertPage::~CDsCACertPage()
{
// Clean up enumerated store list
for (DWORD dwIndex = 0; dwIndex < m_selCertStruct.cDisplayStores; dwIndex++)
{
ASSERT (m_selCertStruct.rghDisplayStores);
::CertCloseStore (m_selCertStruct.rghDisplayStores[dwIndex], CERT_CLOSE_STORE_FORCE_FLAG);
}
if ( m_selCertStruct.rghDisplayStores )
delete [] m_selCertStruct.rghDisplayStores;
if ( m_hImageList )
ImageList_Destroy (m_hImageList);
if ( m_hbmCert )
DeleteObject (m_hbmCert);
}
typedef struct _ENUM_ARG {
DWORD dwFlags;
DWORD* pcDisplayStores;
HCERTSTORE ** prghDisplayStores;
} ENUM_ARG, *PENUM_ARG;
static BOOL WINAPI EnumStoresSysCallback(
IN const void* pwszSystemStore,
IN DWORD dwFlags,
IN PCERT_SYSTEM_STORE_INFO pStoreInfo,
IN OPTIONAL void *pvReserved,
IN OPTIONAL void *pvArg
)
{
PENUM_ARG pEnumArg = (PENUM_ARG) pvArg;
void* pvPara = (void*)pwszSystemStore;
HCERTSTORE hNewStore = ::CertOpenStore (CERT_STORE_PROV_SYSTEM,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL,
CERT_SYSTEM_STORE_CURRENT_USER, pvPara);
if ( !hNewStore )
{
hNewStore = ::CertOpenStore (CERT_STORE_PROV_SYSTEM,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL,
CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG, pvPara);
}
if ( hNewStore )
{
DWORD dwCnt = *(pEnumArg->pcDisplayStores);
HCERTSTORE* phStores = 0;
phStores = new HCERTSTORE[dwCnt+1];
if ( phStores )
{
DWORD dwIndex = 0;
if ( *(pEnumArg->prghDisplayStores) )
{
for (; dwIndex < dwCnt; dwIndex++)
{
phStores[dwIndex] = (*(pEnumArg->prghDisplayStores))[dwIndex];
}
delete [] (*(pEnumArg->prghDisplayStores));
}
(*(pEnumArg->pcDisplayStores))++;
(*(pEnumArg->prghDisplayStores)) = phStores;
(*(pEnumArg->prghDisplayStores))[dwIndex] = hNewStore;
}
else
{
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Method: CDsCACertPage::OnInitDialog
//
// Synopsis: Set the initial control values from the corresponding DS
// attributes.
//
//-----------------------------------------------------------------------------
BOOL CDsCACertPage::OnInitDialog(void)
{
HRESULT hResult = S_OK;
CWaitCursor WaitCursor;
const LPWSTR CERT_PROPERTY_EXT = L"?cACertificate?base?objectclass=certificationAuthority";
// Get the object name and open its Published Certificate store
ASSERT (m_strObjectDN);
if ( m_strObjectDN )
{
LPWSTR pvPara = new WCHAR[wcslen (m_strObjectDN) +
wcslen (CERT_PROPERTY_EXT) + 1];
if ( pvPara )
{
wcscpy (pvPara, m_strObjectDN);
wcscat (pvPara, CERT_PROPERTY_EXT);
m_hCertStore = ::CertOpenStore ("LDAP",
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL,
0,
(void*) pvPara);
if ( !m_hCertStore )
{
MessageBox (IDS_USER_TITLE_PUBLISHED_CERTS, IDS_CANT_OPEN_STORE,
MB_ICONINFORMATION | MB_OK);
hResult = E_FAIL;
::EnableWindow (GetDlgItem (m_hWnd, IDC_ADD_FROM_STORE), FALSE);
::EnableWindow (GetDlgItem (m_hWnd, IDC_ADD_FROM_FILE), FALSE);
}
}
}
// Set up result list view
COLORREF crMask = RGB (255, 0, 255);
m_hImageList = ImageList_Create (16, 16, ILC_MASK, 10, 10);
ASSERT (m_hImageList);
if ( m_hImageList )
{
m_hbmCert = ::LoadBitmap (g_hInstance, MAKEINTRESOURCE (IDB_CERTIFICATE));
ASSERT (m_hbmCert);
if ( m_hbmCert )
{
m_nCertImageIndex = ImageList_AddMasked (m_hImageList, m_hbmCert,
crMask);
ASSERT (m_nCertImageIndex != -1);
if ( m_nCertImageIndex != -1 )
{
ListView_SetImageList (::GetDlgItem (m_hWnd, IDC_CERT_LIST),
m_hImageList, LVSIL_SMALL);
}
}
}
hResult = AddListViewColumns ();
if ( SUCCEEDED (hResult) && m_hCertStore )
hResult = PopulateListView ();
EnableControls ();
// Enumerate User's certificate stores for use in selecting certificates
// from stores.
ENUM_ARG EnumArg;
m_selCertStruct.dwSize = sizeof (CRYPTUI_SELECTCERTIFICATE_STRUCT);
m_selCertStruct.hwndParent = m_hWnd;
EnumArg.pcDisplayStores = &m_selCertStruct.cDisplayStores;
EnumArg.prghDisplayStores = &m_selCertStruct.rghDisplayStores;
::CertEnumSystemStore (CERT_SYSTEM_STORE_CURRENT_USER, 0, &EnumArg,
EnumStoresSysCallback);
return (hResult == S_OK);
}
//+----------------------------------------------------------------------------
//
// Method: CDsCACertPage::OnApply
//
// Synopsis: Handles the Apply notification.
//
//-----------------------------------------------------------------------------
BOOL CDsCACertPage::OnApply(void)
{
HRESULT hResult = S_OK;
CWaitCursor WaitCursor;
if ( m_hCertStore )
{
BOOL bResult = ::CertControlStore (m_hCertStore, 0,
CERT_STORE_CTRL_COMMIT, NULL);
if ( !bResult )
{
DWORD dwErr = GetLastError ();
ASSERT (dwErr == ERROR_NOT_SUPPORTED);
if ( dwErr != ERROR_NOT_SUPPORTED )
{
MessageBox (IDS_USER_TITLE_PUBLISHED_CERTS, IDS_CANT_SAVE_STORE,
MB_ICONINFORMATION | MB_OK);
hResult = E_FAIL;
}
}
}
if(SUCCEEDED(hResult))
{
return CAutoDeletePropPage::OnApply();
}
else
{
return FALSE;
}
}
//+----------------------------------------------------------------------------
//
// Method: CDsCACertPage::OnCommand
//
// Synopsis: Handle control notifications.
//
//-----------------------------------------------------------------------------
BOOL CDsCACertPage::OnCommand(WPARAM wParam, LPARAM lParam)
{
switch (HIWORD(wParam))
{
case BN_CLICKED:
switch (LOWORD(wParam))
{
case IDC_VIEW_CERT:
return S_OK == OnClickedViewCert ();
break;
case IDC_ADD_FROM_STORE:
return S_OK == OnClickedAddFromStore ();
break;
case IDC_ADD_FROM_FILE:
return S_OK == OnClickedAddFromFile ();
break;
case IDC_REMOVE:
return S_OK == OnClickedRemove ();
break;
case IDC_COPY_TO_FILE:
return S_OK == OnClickedCopyToFile ();
break;
default:
_ASSERT (0);
return FALSE;
break;
}
break;
default:
break;
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Method: CDsCACertPage::OnNotify
//
// Synopsis:
//
//-----------------------------------------------------------------------------
BOOL
CDsCACertPage::OnNotify(UINT idCtrl, NMHDR* pNMHdr)
{
if ( !pNMHdr )
return FALSE;
switch (pNMHdr->code)
{
case NM_DBLCLK:
if ( idCtrl == IDC_CERT_LIST )
return S_OK == OnDblClkCertList (pNMHdr);
break;
case LVN_COLUMNCLICK:
if ( idCtrl == IDC_CERT_LIST )
return S_OK == OnColumnClickCertList (pNMHdr);
break;
case LVN_DELETEALLITEMS:
if ( idCtrl == IDC_CERT_LIST )
return FALSE; // Do not suppress LVN_DELETEITEM messages
break;
case LVN_DELETEITEM:
if ( idCtrl == IDC_CERT_LIST )
return S_OK == OnDeleteItemCertList ((LPNMLISTVIEW)pNMHdr);
break;
case LVN_ODSTATECHANGED:
OnNotifyStateChanged ((LPNMLVODSTATECHANGE)pNMHdr);
return TRUE;
case LVN_ITEMCHANGED:
OnNotifyItemChanged ((LPNMLISTVIEW)pNMHdr);
return TRUE;
default:
return FALSE;
break;
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Method: CDsCACertPage::OnDestroy
//
// Synopsis: Exit cleanup
//
//-----------------------------------------------------------------------------
void CDsCACertPage::OnDestroy(void)
{
ListView_DeleteAllItems (::GetDlgItem (m_hWnd, IDC_CERT_LIST));
if ( m_hCertStore )
{
// Back out of uncommitted changes before closing the store.
BOOL bResult = ::CertControlStore (m_hCertStore,
CERT_STORE_CTRL_COMMIT_CLEAR_FLAG,
CERT_STORE_CTRL_COMMIT, NULL);
if ( !bResult )
{
DWORD dwErr = GetLastError ();
ASSERT (dwErr != ERROR_NOT_SUPPORTED && dwErr != ERROR_CALL_NOT_IMPLEMENTED);
}
::CertCloseStore (m_hCertStore, 0);
m_hCertStore = 0;
}
// If an application processes this message, it should return zero.
CAutoDeletePropPage::OnDestroy();
}
HRESULT CDsCACertPage::AddListViewColumns()
{
// Add list view columns
LVCOLUMN lvCol;
::ZeroMemory (&lvCol, sizeof (lvCol));
CString strTemp;
VERIFY(strTemp.LoadString (IDS_CERTCOL_ISSUED_TO) );
lvCol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvCol.fmt = LVCFMT_LEFT;
lvCol.cx = 90;
lvCol.pszText = const_cast<LPWSTR>((LPCWSTR)strTemp);
lvCol.iSubItem = CERTCOL_ISSUED_TO;
HWND hWndList = ::GetDlgItem (m_hWnd, IDC_CERT_LIST);
int nIndex = ListView_InsertColumn (hWndList, CERTCOL_ISSUED_TO, &lvCol);
_ASSERT (nIndex != -1);
if ( nIndex == -1 )
return E_UNEXPECTED;
VERIFY(strTemp.LoadString (IDS_CERTCOL_ISSUED_BY) );
lvCol.cx = 90;
lvCol.pszText = const_cast<LPWSTR>((LPCWSTR)strTemp);
lvCol.iSubItem = CERTCOL_ISSUED_BY;
nIndex = ListView_InsertColumn (hWndList, IDS_CERTCOL_ISSUED_BY, &lvCol);
_ASSERT (nIndex != -1);
if ( nIndex == -1 )
return E_UNEXPECTED;
VERIFY(strTemp.LoadString (IDS_CERTCOL_PURPOSES) );
lvCol.cx = 125;
lvCol.pszText = const_cast<LPWSTR>((LPCWSTR)strTemp);
lvCol.iSubItem = CERTCOL_PURPOSES;
nIndex = ListView_InsertColumn (hWndList, IDS_CERTCOL_PURPOSES, &lvCol);
_ASSERT (nIndex != -1);
if ( nIndex == -1 )
return E_UNEXPECTED;
VERIFY(strTemp.LoadString (IDS_CERTCOL_EXP_DATE) );
lvCol.cx = 125;
lvCol.pszText = const_cast<LPWSTR>((LPCWSTR)strTemp);
lvCol.iSubItem = CERTCOL_EXP_DATE;
nIndex = ListView_InsertColumn (hWndList, IDS_CERTCOL_EXP_DATE, &lvCol);
_ASSERT (nIndex != -1);
if ( nIndex == -1 )
return E_UNEXPECTED;
return S_OK;
}
HRESULT CDsCACertPage::OnClickedViewCert()
{
HRESULT hResult = S_OK;
int nSelItem = -1;
CCertificate* pCert = GetSelectedCertificate (nSelItem);
if ( pCert )
{
CRYPTUI_VIEWCERTIFICATE_STRUCT vcs;
HCERTSTORE hCertStore = ::CertDuplicateStore (pCert->GetCertStore ());
::ZeroMemory (&vcs, sizeof (vcs));
vcs.dwSize = sizeof (vcs);
vcs.hwndParent = m_hWnd;
vcs.dwFlags = 0;
vcs.cStores = 1;
vcs.rghStores = &hCertStore;
vcs.pCertContext = pCert->GetCertContext ();
BOOL fPropertiesChanged = FALSE;
BOOL bResult = ::CryptUIDlgViewCertificate (&vcs, &fPropertiesChanged);
if ( bResult )
{
if ( fPropertiesChanged )
{
pCert->Refresh ();
RefreshItemInList (pCert, nSelItem);
}
}
::CertCloseStore (hCertStore, 0);
}
::SetFocus (::GetDlgItem (m_hWnd, IDC_CERT_LIST));
return hResult;
}
HRESULT CDsCACertPage::OnClickedAddFromStore()
{
HRESULT hResult = S_OK;
PCCERT_CONTEXT pCertContext = ::CryptUIDlgSelectCertificate (&m_selCertStruct);
if ( pCertContext )
{
hResult = AddCertToStore (pCertContext);
SetModified();
}
::SetFocus (::GetDlgItem (m_hWnd, IDC_CERT_LIST));
return hResult;
}
HRESULT CDsCACertPage::OnClickedAddFromFile()
{
HRESULT hResult = S_OK;
HWND hwndList = ::GetDlgItem (m_hWnd, IDC_CERT_LIST);
CString strFilter;
CString strDlgTitle;
VERIFY(strFilter.LoadString (IDS_CERT_SAVE_FILTER));
VERIFY(strDlgTitle.LoadString (IDS_OPEN_FILE_DLG_TITLE));
{
LPWSTR pszDefExt = _T("cer");
OPENFILENAME ofn;
WCHAR szFile[MAX_PATH];
::ZeroMemory (szFile, MAX_PATH * sizeof (WCHAR));
::ZeroMemory (&ofn, sizeof (ofn));
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner = m_hWnd;
ofn.lpstrFilter = const_cast<LPWSTR>((LPCWSTR)strFilter);
ofn.lpstrFile = szFile;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrTitle = const_cast<LPWSTR>((LPCWSTR)strDlgTitle);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
ofn.lpstrDefExt = pszDefExt;
BOOL bResult = GetOpenFileName (&ofn);
if ( bResult )
{
DWORD dwMsgAndCertEncodingType = 0;
DWORD dwContentType = 0;
DWORD dwFormatType = 0;
PCERT_CONTEXT pCertContext = 0;
bResult = ::CryptQueryObject (
CERT_QUERY_OBJECT_FILE,
(void *) ofn.lpstrFile,
CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT |
CERT_QUERY_CONTENT_FLAG_CERT |
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED |
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
CERT_QUERY_FORMAT_FLAG_ALL,
0,
&dwMsgAndCertEncodingType,
&dwContentType,
&dwFormatType,
NULL,
NULL,
(const void **) &pCertContext);
if ( bResult && pCertContext )
{
hResult = AddCertToStore (pCertContext);
// ::CertFreeCertificateContext (pCertContext);
SetModified();
}
else
{
MessageBox (IDS_UNKNOWN_CERT_FILE_TYPE, IDS_OPEN_FILE_DLG_TITLE, MB_ICONWARNING | MB_OK);
}
}
}
::SetFocus (hwndList);
return hResult;
}
HRESULT CDsCACertPage::OnClickedRemove()
{
HRESULT hResult = S_OK;
int nSelItem = -1;
HWND hwndList = ::GetDlgItem (m_hWnd, IDC_CERT_LIST);
bool bConfirmationRequested = false;
int iResult = 0;
int nSelCnt = ListView_GetSelectedCount (hwndList);
if ( nSelCnt < 1 )
return E_FAIL;
while (1)
{
CCertificate* pCert = GetSelectedCertificate (nSelItem);
if ( pCert )
{
if ( !bConfirmationRequested )
{
CString strCaption;
CString strMsg;
int textId = 0;
iResult = MessageBox (( 1 == nSelCnt )?IDS_CONFIRM_DELETE_CERT:IDS_CONFIRM_DELETE_CERTS, IDS_REMOVE_CERT,
MB_YESNO);
bConfirmationRequested = true;
if ( IDYES != iResult )
break;
}
BOOL bResult = pCert->DeleteFromStore ();
ASSERT (bResult);
if ( bResult )
{
bResult = ListView_DeleteItem (
hwndList,
nSelItem);
ASSERT (bResult);
if ( bResult )
SetModified();
else
hResult = E_FAIL;
}
else
{
DWORD dwErr = GetLastError ();
DisplaySystemError (dwErr, IDS_REMOVE_CERT);
hResult = HRESULT_FROM_WIN32 (dwErr);
break;
}
}
else
break;
}
::SetFocus (hwndList);
EnableControls ();
return hResult;
}
HRESULT CDsCACertPage::OnClickedCopyToFile()
{
HRESULT hResult = S_OK;
CString strFilter;
CString strDlgTitle;
VERIFY(strFilter.LoadString (IDS_CERT_SAVE_FILTER));
VERIFY(strDlgTitle.LoadString (IDS_SAVE_FILE_DLG_TITLE));
{
LPWSTR pszDefExt = _T("cer");
OPENFILENAME ofn;
WCHAR szFile[MAX_PATH];
::ZeroMemory (szFile, MAX_PATH * sizeof (WCHAR));
::ZeroMemory (&ofn, sizeof (ofn));
ofn.lStructSize = sizeof (OPENFILENAME);
ofn.hwndOwner = m_hWnd;
ofn.lpstrFilter = const_cast<LPWSTR>((LPCWSTR)strFilter);
ofn.lpstrFile = szFile;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrTitle = const_cast<LPWSTR>((LPCWSTR)strDlgTitle);
ofn.Flags = OFN_PATHMUSTEXIST | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
ofn.lpstrDefExt = pszDefExt;
BOOL bResult = ::GetSaveFileName (&ofn);
if ( bResult )
{
if ( wcsstr (_wcsupr (ofn.lpstrFile), _T(".CER")) )
{
HANDLE hFile = ::CreateFile (ofn.lpstrFile, // pointer to name of the file
GENERIC_READ | GENERIC_WRITE, // access (read-write) mode
0, // share mode
NULL, // pointer to security attributes
CREATE_ALWAYS, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL); // handle to file with attributes to copy
ASSERT (hFile != INVALID_HANDLE_VALUE);
if ( hFile != INVALID_HANDLE_VALUE )
{
int iSelItem = -1;
CCertificate* pCert = GetSelectedCertificate (iSelItem);
ASSERT (pCert);
if ( pCert )
{
// To cer file -> put out encoded blob
// pbEncodedCert
hResult = pCert->WriteToFile (hFile);
if ( !SUCCEEDED (hResult) )
DisplaySystemError (GetLastError (), IDS_COPY_TO_FILE);
}
if ( !CloseHandle (hFile) )
{
ASSERT (0);
DisplaySystemError (GetLastError (), IDS_COPY_TO_FILE);
}
}
else
DisplaySystemError (GetLastError (), IDS_COPY_TO_FILE);
}
else
{
void* pvSaveToPara = (void*) ofn.lpstrFile;
HCERTSTORE hCertStore = ::CertOpenStore (CERT_STORE_PROV_MEMORY,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL,
CERT_FILE_STORE_COMMIT_ENABLE_FLAG, 0);
if ( hCertStore )
{
int iSelItem = -1;
CCertificate* pCert = GetSelectedCertificate (iSelItem);
ASSERT (pCert);
if ( pCert )
{
bResult = ::CertAddCertificateContextToStore (
hCertStore,
::CertDuplicateCertificateContext (pCert->GetCertContext ()),
CERT_STORE_ADD_ALWAYS,
NULL);
ASSERT (bResult);
if ( bResult )
{
bResult = ::CertSaveStore (
hCertStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CERT_STORE_SAVE_AS_PKCS7,
CERT_STORE_SAVE_TO_FILENAME,
pvSaveToPara,
0);
ASSERT (bResult);
if ( !bResult )
DisplaySystemError (GetLastError (), IDS_COPY_TO_FILE);
}
else
DisplaySystemError (GetLastError (), IDS_COPY_TO_FILE);
}
::CertCloseStore (hCertStore, 0);
}
}
}
}
::SetFocus (::GetDlgItem (m_hWnd, IDC_CERT_LIST));
return hResult;
}
HRESULT CDsCACertPage::OnDblClkCertList(LPNMHDR pNMHdr)
{
HRESULT hResult = S_OK;
hResult = OnClickedViewCert ();
return hResult;
}
HRESULT CDsCACertPage::OnColumnClickCertList(LPNMHDR pNMHdr)
{
HRESULT hResult = S_OK;
return hResult;
}
HRESULT CDsCACertPage::OnDeleteItemCertList (LPNMLISTVIEW pNMListView)
{
HRESULT hResult = S_OK;
ASSERT (pNMListView);
if ( pNMListView )
{
LVITEM lvItem;
::ZeroMemory (&lvItem, sizeof (lvItem));
lvItem.mask = LVIF_PARAM;
lvItem.iItem = pNMListView->iItem;
if ( ListView_GetItem (::GetDlgItem (m_hWnd, IDC_CERT_LIST), &lvItem) )
{
CCertificate* pCert = (CCertificate*) lvItem.lParam;
ASSERT (pCert);
if ( pCert )
{
delete pCert;
}
else
hResult = E_UNEXPECTED;
}
else
hResult = E_UNEXPECTED;
}
else
hResult = E_POINTER;
return hResult;
}
HRESULT CDsCACertPage::PopulateListView()
{
CWaitCursor cursor;
PCCERT_CONTEXT pCertContext = 0;
HRESULT hResult = S_OK;
CCertificate* pCert = 0;
// Iterate through the list of certificates in the system store,
// allocate new certificates with the CERT_CONTEXT returned,
// and store them in the certificate list.
int nIndex = 0;
int nItem = -1;
while ( SUCCEEDED (hResult) )
{
pCertContext = ::CertEnumCertificatesInStore (m_hCertStore, pCertContext);
if ( !pCertContext )
break;
pCert = new CCertificate (pCertContext, m_hCertStore);
if ( pCert )
{
nItem++;
hResult = InsertCertInList (pCert, nItem);
if ( !SUCCEEDED (hResult) )
delete pCert;
}
else
{
hResult = E_OUTOFMEMORY;
}
}
return hResult;
}
// Get the first selected certificate, starting at the end of the list
// and previous to the passed in nSelItem. Pass in a -1 to search
// the entire list
CCertificate* CDsCACertPage::GetSelectedCertificate (int& nSelItem)
{
HWND hWndList = ::GetDlgItem (m_hWnd, IDC_CERT_LIST);
int nCnt = ListView_GetItemCount (hWndList);
CCertificate* pCert = 0;
PCCERT_CONTEXT pCertContext = 0;
int nSelCnt = ListView_GetSelectedCount (hWndList);
LVITEM lvItem;
::ZeroMemory (&lvItem, sizeof (lvItem));
lvItem.mask = LVIF_PARAM;
if ( nSelCnt >= 1 )
{
if ( -1 != nSelItem )
nCnt = nSelItem;
while (--nCnt >= 0)
{
UINT flag = ListView_GetItemState (hWndList,
nCnt, LVIS_SELECTED);
if ( flag & LVNI_SELECTED )
{
lvItem.iItem = nCnt;
if ( ListView_GetItem (::GetDlgItem (m_hWnd,
IDC_CERT_LIST),
&lvItem) )
{
pCert = (CCertificate*) lvItem.lParam;
ASSERT (pCert);
if ( pCert )
{
nSelItem = nCnt;
}
}
else
{
ASSERT (0);
}
break;
}
}
}
return pCert;
}
void CDsCACertPage::RefreshItemInList (CCertificate * pCert, int nItem)
{
HWND hWndList = ::GetDlgItem (m_hWnd, IDC_CERT_LIST);
BOOL bResult = (BOOL)::SendMessage (hWndList, LVM_DELETEITEM, nItem, 0);
ASSERT (bResult);
HRESULT hResult = InsertCertInList (pCert, nItem);
if ( SUCCEEDED (hResult) )
{
bResult = ListView_Update (hWndList, nItem);
ASSERT (bResult);
}
else
delete pCert;
}
HRESULT CDsCACertPage::InsertCertInList(CCertificate * pCert, int nItem)
{
HRESULT hResult = S_OK;
HWND hWndList = ::GetDlgItem (m_hWnd, IDC_CERT_LIST);
LVITEM lvItem;
PWSTR pszText = 0;
BOOL bResult = FALSE;
int nIndex = 0;
// Insert icon and subject name
::ZeroMemory (&lvItem, sizeof (lvItem));
lvItem.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
lvItem.iItem = nItem;
lvItem.iSubItem = CERTCOL_ISSUED_TO;
lvItem.iImage = m_nCertImageIndex;
lvItem.lParam = (LPARAM) pCert;
hResult = pCert->GetSubjectName (&pszText);
if ( SUCCEEDED (hResult) )
lvItem.pszText = pszText;
else
{
hResult = pCert->GetAlternateSubjectName (&pszText);
if ( SUCCEEDED (hResult) )
lvItem.pszText = pszText;
}
if ( SUCCEEDED (hResult) )
{
nIndex = ListView_InsertItem (hWndList, &lvItem);
_ASSERT (nIndex != -1);
if ( nIndex == -1 )
{
delete pCert;
hResult = E_UNEXPECTED;
}
}
else
{
delete pCert;
hResult = E_UNEXPECTED;
}
if ( SUCCEEDED (hResult) )
{
// Insert issuer name
::ZeroMemory (&lvItem, sizeof (lvItem));
HRESULT hResult1 = pCert->GetIssuerName (&pszText);
if ( !SUCCEEDED (hResult1) )
{
hResult1 = pCert->GetAlternateIssuerName (&pszText);
}
if ( SUCCEEDED (hResult1) )
{
ListView_SetItemText (hWndList, nIndex, CERTCOL_ISSUED_BY, pszText);
}
}
// Insert intended purpose
if ( SUCCEEDED (hResult) )
{
HRESULT hResult1 = pCert->GetEnhancedKeyUsage (&pszText);
if ( SUCCEEDED (hResult1) && pszText )
{
ListView_SetItemText (hWndList, nIndex, CERTCOL_PURPOSES, pszText);
}
}
// Insert expiration date
if ( SUCCEEDED (hResult) )
{
HRESULT hResult1 = pCert->GetValidNotAfter (&pszText);
if ( SUCCEEDED (hResult1) )
{
ListView_SetItemText (hWndList, nIndex, CERTCOL_EXP_DATE, pszText);
}
}
if ( pszText )
delete [] pszText;
return hResult;
}
void CDsCACertPage::DisplaySystemError(DWORD dwErr, int iCaptionText)
{
LPVOID lpMsgBuf = 0;
if (0 != FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwErr,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf, 0, NULL))
{
// Display the string.
CString strCaption;
VERIFY(strCaption.LoadString(iCaptionText));
::MessageBox (m_hWnd, (LPWSTR) lpMsgBuf, strCaption, MB_ICONWARNING | MB_OK);
// Free the buffer.
LocalFree (lpMsgBuf);
}
}
void CDsCACertPage::EnableControls()
{
HWND hWndDlg = m_hWnd;
HWND hWndList = ::GetDlgItem (hWndDlg, IDC_CERT_LIST);
int nSelCnt = ListView_GetSelectedCount (hWndList);
int nSelItem = -1;
bool bCanDelete = true;
while (bCanDelete)
{
CCertificate* pCert = GetSelectedCertificate (nSelItem);
if ( pCert )
bCanDelete = pCert->CanDelete ();
else
break;
}
::EnableWindow (::GetDlgItem (hWndDlg, IDC_REMOVE), bCanDelete && nSelCnt > 0);
::EnableWindow (::GetDlgItem (hWndDlg, IDC_COPY_TO_FILE), nSelCnt == 1);
::EnableWindow (::GetDlgItem (hWndDlg, IDC_VIEW_CERT), nSelCnt == 1);
}
void CDsCACertPage::OnNotifyStateChanged(LPNMLVODSTATECHANGE pStateChange)
{
EnableControls ();
}
void CDsCACertPage::OnNotifyItemChanged (LPNMLISTVIEW pnmv)
{
EnableControls ();
}
HRESULT CDsCACertPage::AddCertToStore(PCCERT_CONTEXT pCertContext)
{
HRESULT hResult = S_OK;
BOOL bResult = ::CertAddCertificateContextToStore (
m_hCertStore,
pCertContext,
CERT_STORE_ADD_NEW,
0);
if ( bResult )
{
CCertificate* pCert = new CCertificate (pCertContext, m_hCertStore);
if ( pCert )
{
hResult = InsertCertInList (pCert,
ListView_GetItemCount (
::GetDlgItem (m_hWnd, IDC_CERT_LIST)));
if ( !SUCCEEDED (hResult) )
delete pCert;
}
else
{
hResult = E_OUTOFMEMORY;
}
}
else
{
DWORD dwErr = GetLastError ();
if ( dwErr == CRYPT_E_EXISTS )
{
MessageBox (IDS_DUPLICATE_CERT, IDS_ADD_FROM_STORE,
MB_ICONINFORMATION | MB_OK);
hResult = E_FAIL;
}
else
{
DisplaySystemError (dwErr, IDS_ADD_FROM_STORE);
hResult = HRESULT_FROM_WIN32 (dwErr);
}
}
return hResult;
}
int CDsCACertPage::MessageBox(int caption, int text, UINT flags)
{
int iReturn = -1;
CString strCaption;
CString strMsg;
VERIFY(strCaption.LoadString (caption));
VERIFY(strMsg.LoadString (text));
iReturn = ::MessageBox (m_hWnd, strMsg, strCaption, flags);
return iReturn;
}
/*----------------------------------------------------------------------
IShellExtInit Implementation.
------------------------------------------------------------------------*/
STDMETHODIMP CCAShellExt::Initialize
(
IN LPCITEMIDLIST pidlFolder, // Points to an ITEMIDLIST structure
IN LPDATAOBJECT pDataObj, // Points to an IDataObject interface
IN HKEY hkeyProgID // Registry key for the file object or folder type
)
{
HRESULT hr = 0;
FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
STGMEDIUM medium = { TYMED_NULL };
CString csClass, csPath;
USES_CONVERSION;
LPWSTR wszTypeDN = NULL, wszType = NULL;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// if we have a pDataObj then try and get the first name from it
if ( pDataObj )
{
// get path and class
fmte.cfFormat = (CLIPFORMAT) RegisterClipboardFormat(CFSTR_DSOBJECTNAMES);
if ( SUCCEEDED(pDataObj->GetData(&fmte, &medium)) )
{
// Note: We take ownership of the HGLOBAL, so it needs to be freed with a GlobalFree.
m_Names = (LPDSOBJECTNAMES)medium.hGlobal;
}
}
hr = S_OK; // success
return hr;
}
STDMETHODIMP CCAShellExt::AddPages
(
IN LPFNADDPROPSHEETPAGE lpfnAddPage,
IN LPARAM lParam
)
{
PropertyPage* pBasePage;
LPWSTR wszClassType = NULL;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if(m_Names->cItems != 1)
{
// Don't add the properties page if we have no or many objects selected
return S_OK;
}
if(m_Names->aObjects[0].offsetName == 0)
{
return E_UNEXPECTED;
}
if(m_Names->aObjects[0].offsetClass)
{
wszClassType = (LPWSTR)ByteOffset(m_Names, m_Names->aObjects[0].offsetClass);
}
if(wszClassType == NULL)
{
return S_OK;
}
if(_wcsicmp(wszClassType, L"certificationAuthority") == 0)
{
CDsCACertPage* pControlPage = new CDsCACertPage((LPWSTR)ByteOffset(m_Names, m_Names->aObjects[0].offsetName));
if(pControlPage)
{
pBasePage = pControlPage;
HPROPSHEETPAGE hPage = CreatePropertySheetPage(&pBasePage->m_psp);
if (hPage == NULL)
{
delete (pControlPage);
return E_UNEXPECTED;
}
lpfnAddPage(hPage, lParam);
}
}
return S_OK;
}
STDMETHODIMP CCAShellExt::ReplacePage
(
IN UINT uPageID,
IN LPFNADDPROPSHEETPAGE lpfnReplaceWith,
IN LPARAM lParam
)
{
return E_FAIL;
}
// IContextMenu methods
STDMETHODIMP CCAShellExt::GetCommandString
(
UINT_PTR idCmd,
UINT uFlags,
UINT *pwReserved,
LPSTR pszName,
UINT cchMax
)
{
return E_NOTIMPL;
}
STDMETHODIMP CCAShellExt::InvokeCommand
(
LPCMINVOKECOMMANDINFO lpici
)
{
HRESULT hr = S_OK;
LPWSTR wszClassType = NULL;
if(m_Names->cItems != 1)
{
// Don't add the properties page if we have no or many objects selected
return S_OK;
}
if(m_Names->aObjects[0].offsetName == 0)
{
return E_UNEXPECTED;
}
if(m_Names->aObjects[0].offsetClass)
{
wszClassType = (LPWSTR)ByteOffset(m_Names, m_Names->aObjects[0].offsetClass);
}
if(wszClassType == NULL)
{
return S_OK;
}
if (!HIWORD(lpici->lpVerb))
{
UINT idCmd = LOWORD(lpici->lpVerb);
if(_wcsicmp(wszClassType, L"pKIEnrollmentService") == 0)
{
if(idCmd == m_idManage)
{
return _SpawnCertServerSnapin((LPWSTR)ByteOffset(m_Names, m_Names->aObjects[0].offsetName));
}
}
else if(_wcsicmp(wszClassType, L"cRLDistributionPoint") == 0)
{
PCCRL_CONTEXT pCRL = NULL;
_CRLFromDN((LPWSTR)ByteOffset(m_Names, m_Names->aObjects[0].offsetName),
&pCRL);
if(pCRL)
{
if(idCmd == m_idOpen)
{
hr = _LaunchCRLDialog(pCRL);
}
else if(idCmd == m_idExport)
{
hr = _OnExportCRL(pCRL);
}
CertFreeCRLContext(pCRL);
return hr;
}
}
}
return E_NOTIMPL;
}
STDMETHODIMP CCAShellExt::_SpawnCertServerSnapin(LPWSTR wszServiceDN)
{
// Determine the config string. Strinp the CN out of the service DN, look it up via certca.h api's.
HRESULT hr = S_OK;
HCAINFO hCAInfo = NULL;
LPWSTR wszTypeDN;
LPWSTR *awszDNSName = NULL;
LPWSTR wszArgs = NULL;
LPWSTR wszCN= NULL;
wszTypeDN = wcsstr(wszServiceDN, L"CN=");
if(wszTypeDN == NULL)
{
return E_UNEXPECTED;
}
wszTypeDN += 3;
wszCN = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(wcslen(wszTypeDN)+1));
if(wszCN == NULL)
{
return E_OUTOFMEMORY;
}
wcscpy(wszCN, wszTypeDN);
wszTypeDN = wcschr(wszCN, L',');
if(wszTypeDN)
{
*wszTypeDN = 0;
}
hr = CAFindByName(
wszCN,
NULL,
CA_FIND_INCLUDE_UNTRUSTED | CA_FIND_INCLUDE_NON_TEMPLATE_CA,
&hCAInfo);
if(hr != S_OK)
{
goto error;
}
hr = CAGetCAProperty(hCAInfo, CA_PROP_DNSNAME, &awszDNSName);
if(hr != S_OK)
{
goto error;
}
if((awszDNSName == NULL) || (awszDNSName[0] == NULL))
{
hr = E_UNEXPECTED;
goto error;
}
wszArgs = (LPWSTR) LocalAlloc (LMEM_FIXED, (wcslen (awszDNSName[0]) + wcslen(wszCN) + 30) * sizeof(WCHAR));
if (!wszArgs)
{
hr = E_OUTOFMEMORY;
goto error;
}
//
// Build the command line arguments
//
wsprintf (wszArgs, L"/s /machine:%s", awszDNSName[0]);
ShellExecute (NULL, TEXT("open"), TEXT("certsrv.msc"), wszArgs,
NULL, SW_SHOWNORMAL);
error:
if(wszArgs)
{
LocalFree(wszArgs);
}
if(wszCN)
{
LocalFree(wszCN);
}
if(hCAInfo)
{
if(awszDNSName)
{
CAFreeCAProperty(hCAInfo, awszDNSName);
}
CACloseCA(hCAInfo);
}
return hr;
}
STDMETHODIMP CCAShellExt::_CRLFromDN(LPWSTR wszCDPDN, PCCRL_CONTEXT *ppCRL)
{
HCERTSTORE hStore = NULL;
HRESULT hResult = S_OK;
const LPWSTR CDP_PROPERTY_EXT = L"?certificateRevocationList?base?objectclass=cRLDistributionPoint";
LPWSTR pvPara = NULL;
ASSERT (wszCDPDN);
*ppCRL = NULL;
if ( wszCDPDN )
{
pvPara = new WCHAR[wcslen (wszCDPDN) +
wcslen (CDP_PROPERTY_EXT) + 1];
if ( pvPara )
{
wcscpy (pvPara, wszCDPDN);
wcscat (pvPara, CDP_PROPERTY_EXT);
hStore = ::CertOpenStore ("LDAP",
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, NULL,
0,
(void*) pvPara);
if ( !hStore )
{
hResult = E_FAIL;
goto error;
}
}
}
if (NULL != hStore)
{
*ppCRL = CertFindCRLInStore(hStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CRL_FIND_ANY,
NULL,
NULL);
}
error:
if(hStore)
{
CertCloseStore(hStore, 0);
}
if(pvPara)
{
LocalFree(pvPara);
}
return hResult;
}
STDMETHODIMP CCAShellExt::_LaunchCRLDialog(PCCRL_CONTEXT pCRL)
{
CRYPTUI_VIEWCRL_STRUCT vcs;
HWND hwndParent = NULL;
HRESULT hr = S_OK;
::ZeroMemory (&vcs, sizeof (vcs));
vcs.dwSize = sizeof (vcs);
vcs.hwndParent = hwndParent;
vcs.dwFlags = 0;
vcs.pCRLContext = pCRL;
if(!::CryptUIDlgViewCRL (&vcs))
{
hr = GetLastError();
hr = HRESULT_FROM_WIN32(hr);
}
return hr;
}
HRESULT CCAShellExt::_OnExportCRL (PCCRL_CONTEXT pCRL)
{
AFX_MANAGE_STATE (AfxGetStaticModuleState ());
HRESULT hr = S_OK;
CRYPTUI_WIZ_EXPORT_INFO cwi;
HWND hwndParent = 0;
::ZeroMemory (&cwi, sizeof (cwi));
cwi.dwSize = sizeof (cwi);
cwi.dwSubjectChoice = CRYPTUI_WIZ_EXPORT_CRL_CONTEXT;
ASSERT (pCRL);
if ( pCRL )
cwi.pCRLContext = pCRL;
else
return E_UNEXPECTED;
if(!::CryptUIWizExport (
0,
hwndParent,
0,
&cwi,
NULL))
{
hr = GetLastError();
hr = HRESULT_FROM_WIN32(hr);
}
return hr;
}
STDMETHODIMP CCAShellExt::QueryContextMenu
(
HMENU hmenu,
UINT indexMenu,
UINT idCmdFirst,
UINT idCmdLast,
UINT uFlags
)
{
LPWSTR wszClassType = NULL;
if(m_Names->cItems != 1)
{
// Don't add the properties page if we have no or many objects selected
return S_OK;
}
if(m_Names->aObjects[0].offsetName == 0)
{
return E_UNEXPECTED;
}
if(m_Names->aObjects[0].offsetClass)
{
wszClassType = (LPWSTR)ByteOffset(m_Names, m_Names->aObjects[0].offsetClass);
}
if(wszClassType == NULL)
{
return S_OK;
}
if(((m_Names->aObjects[0].dwProviderFlags & DSPROVIDER_ADVANCED) != 0) &&
(_wcsicmp(wszClassType, L"pKIEnrollmentService") == 0))
{
// Add a "manage" option
CString szEdit;
MENUITEMINFO mii;
UINT idLastUsedCmd = idCmdFirst;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.fType = MFT_STRING;
mii.wID = idLastUsedCmd;
szEdit.LoadString(IDS_MANAGE);
mii.dwTypeData = (LPTSTR)(LPCTSTR)szEdit;
mii.cch = szEdit.GetLength();
m_idManage = indexMenu;
// Add new menu items to the context menu. //
::InsertMenuItem(hmenu,
indexMenu++,
TRUE,
&mii);
idLastUsedCmd++;
return ResultFromScode (MAKE_SCODE (SEVERITY_SUCCESS, 0,
USHORT (idLastUsedCmd )));
}
else if(((m_Names->aObjects[0].dwProviderFlags & DSPROVIDER_ADVANCED) != 0) &&
(_wcsicmp(wszClassType, L"cRLDistributionPoint") == 0))
{
// Add a "manage" option
CString szName;
MENUITEMINFO mii;
UINT idLastUsedCmd = idCmdFirst;
AFX_MANAGE_STATE(AfxGetStaticModuleState());
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.fType = MFT_STRING;
mii.wID = idLastUsedCmd;
szName.LoadString(IDS_OPEN);
mii.dwTypeData = (LPTSTR)(LPCTSTR)szName;
mii.cch = szName.GetLength();
m_idOpen = indexMenu;
// Add new menu items to the context menu. //
::InsertMenuItem(hmenu,
indexMenu++,
TRUE,
&mii);
idLastUsedCmd++;
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.fType = MFT_STRING;
mii.wID = idLastUsedCmd;
szName.LoadString(IDS_EXPORT);
mii.dwTypeData = (LPTSTR)(LPCTSTR)szName;
mii.cch = szName.GetLength();
m_idExport = indexMenu;
// Add new menu items to the context menu. //
::InsertMenuItem(hmenu,
indexMenu++,
TRUE,
&mii);
idLastUsedCmd++;
return ResultFromScode (MAKE_SCODE (SEVERITY_SUCCESS, 0,
USHORT (idLastUsedCmd)));
}
return S_OK;
}