//+---------------------------------------------------------------------------- // // 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((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((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((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((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((LPCWSTR)strFilter); ofn.lpstrFile = szFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrTitle = const_cast((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((LPCWSTR)strFilter); ofn.lpstrFile = szFile; ofn.nMaxFile = MAX_PATH; ofn.lpstrTitle = const_cast((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; }