// USERLIST.cpp : implementation file // #include "stdafx.h" #include "EFSADU.h" #include "USERLIST.h" #include "cryptui.h" #include "objsel.h" #include #include "efsui.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define OTHERPEOPLE L"AddressBook" #define TRUSTEDPEOPLE L"TrustedPeople" LPSTR EfsOidlpstr = szOID_KP_EFS; ///////////////////////////////////////////////////////////////////////////// // USERLIST dialog USERLIST::USERLIST(CWnd* pParent /*=NULL*/) : CDialog(USERLIST::IDD, pParent) { //{{AFX_DATA_INIT(USERLIST) //}}AFX_DATA_INIT } USERLIST::USERLIST(LPCTSTR FileName, CWnd* pParent /*=NULL*/) : CDialog(USERLIST::IDD, pParent) { m_FileName = FileName; } void USERLIST::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(USERLIST) DDX_Control(pDX, IDC_LISTRA, m_RecoveryListCtrl); DDX_Control(pDX, IDC_LISTUSER, m_UserListCtrl); DDX_Control(pDX, IDC_ADD, m_AddButton); DDX_Control(pDX, IDC_REMOVE, m_RemoveButton); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(USERLIST, CDialog) //{{AFX_MSG_MAP(USERLIST) ON_BN_CLICKED(IDC_REMOVE, OnRemove) ON_BN_CLICKED(IDC_ADD, OnAdd) ON_NOTIFY(NM_SETFOCUS, IDC_LISTUSER, OnSetfocusListuser) ON_NOTIFY(NM_KILLFOCUS, IDC_LISTUSER, OnKillfocusListuser) ON_NOTIFY(LVN_ITEMCHANGED, IDC_LISTUSER, OnItemchangedListuser) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // USERLIST message handlers void USERLIST::OnRemove() { int ItemPos; BOOL NoAction = FALSE; CString NoCertName; try{ NoCertName.LoadString(IDS_NOCERTNAME); } catch(...){ NoAction = TRUE; } if (NoAction){ return; } ItemPos = m_UserListCtrl.GetNextItem( -1, LVNI_SELECTED ); while ( ItemPos != -1 ){ CString CertName; LPTSTR pCertName; CertName = m_UserListCtrl.GetItemText( ItemPos, 0 ); if ( !CertName.Compare(NoCertName) ){ pCertName = NULL; } else { pCertName = CertName.GetBuffer(CertName.GetLength() + 1); } m_Users.Remove( pCertName); m_UserListCtrl.DeleteItem( ItemPos ); if (pCertName){ CertName.ReleaseBuffer(); } // // Because we have deleted the item. We have to start from -1 again. // ItemPos = m_UserListCtrl.GetNextItem( -1, LVNI_SELECTED ); } m_AddButton.SetFocus(); } void USERLIST::OnCancel() { // TODO: Add extra cleanup here CDialog::OnCancel(); } void USERLIST::OnOK() { // TODO: Add extra validation here LONG NoUsersToAdd = m_Users.GetUserAddedCnt(); LONG NoUsersToRemove = m_Users.GetUserRemovedCnt(); if ( (NoUsersToRemove - NoUsersToAdd) >= m_CurrentUsers) { // // All the users are going to be removed from the file. Do not allow. // CString ErrMsg; if (ErrMsg.LoadString(IDS_NOREMOVEALL)){ MessageBox(ErrMsg); } return; } CDialog::OnOK(); } STDAPI_(void) EfsDetail(HWND hwndParent, LPCWSTR FileName) { INT_PTR RetCode; AFX_MANAGE_STATE(AfxGetStaticModuleState()); DWORD FileAttributes = GetFileAttributes(FileName); if ( (-1 != FileAttributes) && ( FileAttributes & FILE_ATTRIBUTE_DIRECTORY)){ CString ErrMsg; if (ErrMsg.LoadString(IDS_NOADDUSERDIR)){ MessageBox(hwndParent, ErrMsg, NULL, MB_OK); } return; } CWnd cwnd; cwnd.FromHandle(hwndParent); USERLIST DetailDialog(FileName, &cwnd); RetCode = DetailDialog.DoModal(); if ( IDOK == RetCode ){ // // Commit the change // DetailDialog.ApplyChanges( FileName ); } else if (IDCANCEL == RetCode) { // // Nothing needs to be done // } } BOOL WINAPI EfsFilter( PCCERT_CONTEXT pCertContext, BOOL *pfInitialSelectedCert, void *pvCallbackData ) { BOOL disp = FALSE; PCERT_ENHKEY_USAGE pUsage = NULL; DWORD cbUsage = 0; if (CertGetEnhancedKeyUsage( pCertContext, 0, NULL, &cbUsage) && 0 != cbUsage){ pUsage = (PCERT_ENHKEY_USAGE) new BYTE[cbUsage]; if (pUsage){ if (CertGetEnhancedKeyUsage( pCertContext, 0, pUsage, &cbUsage)){ // // Search for EFS usage // DWORD cUsages = pUsage->cUsageIdentifier; while (cUsages){ if (!strcmp(szOID_KP_EFS, pUsage->rgpszUsageIdentifier[cUsages-1])){ disp = TRUE; break; } cUsages--; } } delete [] pUsage; } } return disp; } BOOL USERLIST::OnInitDialog() { CDialog::OnInitDialog(); CString WinTitle; RECT ListRect; DWORD ColWidth; CString ColName; CString ColCert; CString RecName; LPTSTR UserCertName = NULL; BOOL EnableAddButton = FALSE; PENCRYPTION_CERTIFICATE_HASH_LIST pUsers = NULL; PENCRYPTION_CERTIFICATE_HASH_LIST pRecs = NULL; try { DWORD RetCode; AfxFormatString1( WinTitle, IDS_DETAILWINTITLE, m_FileName ); SetWindowText( WinTitle ); m_CertChainPara.cbSize = sizeof(CERT_CHAIN_PARA); m_CertChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; // // Check EFS EKU // m_CertChainPara.RequestedUsage.Usage.cUsageIdentifier = 1; m_CertChainPara.RequestedUsage.Usage.rgpszUsageIdentifier=&EfsOidlpstr; m_UserListCtrl.GetClientRect(&ListRect); ColName.LoadString(IDS_USERCOLTITLE); ColCert.LoadString(IDS_CERTCOLTITLE); RecName.LoadString(IDS_RECCOLTITLE); ColWidth = ( ListRect.right - ListRect.left ) / 4; m_UserListCtrl.InsertColumn(0, ColName, LVCFMT_LEFT, ColWidth*3 ); m_UserListCtrl.InsertColumn(1, ColCert, LVCFMT_LEFT, ColWidth ); m_RecoveryListCtrl.GetClientRect(&ListRect); ColWidth = ( ListRect.right - ListRect.left ) / 4; m_RecoveryListCtrl.InsertColumn(0, RecName, LVCFMT_LEFT, ColWidth*3 ); m_RecoveryListCtrl.InsertColumn(1, ColCert, LVCFMT_LEFT, ColWidth ); RetCode = QueryUsersOnEncryptedFile( (LPWSTR)(LPCWSTR) m_FileName, &pUsers); if ( !RetCode ){ RetCode = QueryRecoveryAgentsOnEncryptedFile( (LPWSTR)(LPCWSTR) m_FileName, &pRecs); if ( !RetCode ){ // // Got the info about the encrypted file // DWORD NUsers = pUsers->nCert_Hash; BOOL RecDone = FALSE; PENCRYPTION_CERTIFICATE_HASH_LIST pCertHashList = pUsers; m_CurrentUsers = (LONG) NUsers; // // Get all the users // while ( NUsers > 0 ){ UserCertName = new TCHAR[_tcslen(pCertHashList->pUsers[NUsers - 1]->lpDisplayInformation) + 1]; if (UserCertName){ _tcscpy(UserCertName, pCertHashList->pUsers[NUsers - 1]->lpDisplayInformation); } else { AfxThrowMemoryException( ); } // // We got the user name // if (RecDone){ RetCode = m_Recs.Add( UserCertName, pCertHashList->pUsers[NUsers - 1]->pHash, NULL ); } else { // // Try to get a better name from the cert // LPTSTR UserName; RetCode = TryGetBetterNameInCert(pCertHashList->pUsers[NUsers - 1]->pHash, &UserName); if (ERROR_SUCCESS == RetCode){ // // We get a better name from the certs // delete [] UserCertName; UserCertName = UserName; } RetCode = m_Users.Add( UserCertName, pCertHashList->pUsers[NUsers - 1]->pHash, NULL ); } if ( NO_ERROR != RetCode ) { delete [] UserCertName; UserCertName = NULL; } NUsers--; if (NUsers == 0 && !RecDone){ // // Let's deal with the recovery agents. // RecDone = TRUE; pCertHashList = pRecs; NUsers = pRecs->nCert_Hash; } } if ( pRecs ){ FreeEncryptionCertificateHashList( pRecs ); pRecs = NULL; } // // In memory intial list established // SetUpListBox(&EnableAddButton); } else { // // Cannot get recovery info // CString ErrMsg; if (ErrMsg.LoadString(IDS_NORECINFO)){ MessageBox(ErrMsg); } } if ( pUsers ){ FreeEncryptionCertificateHashList( pUsers ); pUsers = NULL; } } else { // // Cannot get user info // CString ErrMsg; if (ErrMsg.LoadString(IDS_NOINFO)){ MessageBox(ErrMsg); } } } catch (...) { // // The exception mostly is caused by out of memory. // We can not prevent the page to be displayed from this routine, // So we just go ahead with empty list // m_UserListCtrl.DeleteAllItems( ); m_RecoveryListCtrl.DeleteAllItems( ); // // Delete works even if UserCertName == NULL // delete [] UserCertName; if ( pUsers ){ FreeEncryptionCertificateHashList( pUsers ); } if ( pRecs ){ FreeEncryptionCertificateHashList( pRecs ); } } m_RemoveButton.EnableWindow( FALSE ); if ( !EnableAddButton ){ m_AddButton.EnableWindow( FALSE ); } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void USERLIST::ShowRemove() { if (m_UserListCtrl.GetSelectedCount() > 0){ // // Enable the Remove Button // m_RemoveButton.EnableWindow( TRUE ); } else { // // Disable the Remove Button // m_RemoveButton.EnableWindow( FALSE ); } } DWORD USERLIST::ApplyChanges( LPCTSTR FileName ) { DWORD RetCode = NO_ERROR; DWORD NoUsersToRemove; DWORD NoUsersToAdd; DWORD RemoveUserIndex; DWORD AddUserIndex; PENCRYPTION_CERTIFICATE_HASH_LIST RemoveUserList = NULL; PENCRYPTION_CERTIFICATE_LIST AddUserList = NULL; PVOID EnumHandle; // // Get all the users to be added or removed first // NoUsersToAdd = m_Users.GetUserAddedCnt(); NoUsersToRemove = m_Users.GetUserRemovedCnt(); if ( (NoUsersToAdd == 0) && (NoUsersToRemove == 0)){ return NO_ERROR; } if ( NoUsersToAdd ) { // // At least one user is to be added // DWORD BytesToAllocate; BytesToAllocate = sizeof ( ENCRYPTION_CERTIFICATE_LIST ) + NoUsersToAdd * sizeof ( PENCRYPTION_CERTIFICATE ) + NoUsersToAdd * sizeof (ENCRYPTION_CERTIFICATE); AddUserList = (PENCRYPTION_CERTIFICATE_LIST) new BYTE[BytesToAllocate]; if ( NULL == AddUserList ){ // // Out of memory. Try our best to display the error message. // try { CString ErrMsg; if (ErrMsg.LoadString(IDS_ERRORMEM)){ ::MessageBox(NULL, ErrMsg, NULL, MB_OK); } } catch (...) { } return ERROR_NOT_ENOUGH_MEMORY; } AddUserList->nUsers = NoUsersToAdd; AddUserList->pUsers = (PENCRYPTION_CERTIFICATE *)(((PBYTE) AddUserList) + sizeof ( ENCRYPTION_CERTIFICATE_LIST )); } if ( NoUsersToRemove ){ // // At least one user is to be removed // DWORD BytesToAllocate; BytesToAllocate = sizeof ( ENCRYPTION_CERTIFICATE_HASH_LIST ) + NoUsersToRemove * sizeof ( PENCRYPTION_CERTIFICATE_HASH) + NoUsersToRemove * sizeof (ENCRYPTION_CERTIFICATE_HASH); RemoveUserList = (PENCRYPTION_CERTIFICATE_HASH_LIST) new BYTE[BytesToAllocate]; if ( NULL == RemoveUserList ){ // // Out of memory. Try our best to display the error message. // if (AddUserList){ delete [] AddUserList; AddUserList = NULL; } try { CString ErrMsg; if (ErrMsg.LoadString(IDS_ERRORMEM)){ ::MessageBox(NULL, ErrMsg, NULL, MB_OK); } } catch (...) { } return ERROR_NOT_ENOUGH_MEMORY; } RemoveUserList->nCert_Hash = NoUsersToRemove; RemoveUserList->pUsers = (PENCRYPTION_CERTIFICATE_HASH *)(((PBYTE) RemoveUserList) + sizeof ( ENCRYPTION_CERTIFICATE_HASH_LIST )); } EnumHandle = m_Users.StartEnum(); RemoveUserIndex = 0; AddUserIndex = 0; while ( EnumHandle ){ DWORD Flag; PSID UserSid; PVOID CertData; LPTSTR UserName; EnumHandle = m_Users.GetNextChangedUser( EnumHandle, &UserName, &UserSid, &CertData, &Flag ); if ( Flag ){ // // We get our changed user // if ( Flag & USERADDED ){ ASSERT( AddUserList ); // // Add the user to the adding list // PENCRYPTION_CERTIFICATE EfsCert; ASSERT (AddUserIndex < NoUsersToAdd); EfsCert= (PENCRYPTION_CERTIFICATE)(((PBYTE) AddUserList) + sizeof ( ENCRYPTION_CERTIFICATE_LIST ) + NoUsersToAdd * sizeof ( PENCRYPTION_CERTIFICATE) + AddUserIndex * sizeof (ENCRYPTION_CERTIFICATE)); AddUserList->pUsers[AddUserIndex] = EfsCert; EfsCert->pUserSid = (SID *) UserSid; EfsCert->cbTotalLength = sizeof (ENCRYPTION_CERTIFICATE); EfsCert->pCertBlob = (PEFS_CERTIFICATE_BLOB) CertData; AddUserIndex++; } else if ( Flag & USERREMOVED ) { ASSERT (RemoveUserList); // // Add the user to the removing list // PENCRYPTION_CERTIFICATE_HASH EfsCertHash; ASSERT (RemoveUserIndex < NoUsersToRemove); EfsCertHash= (PENCRYPTION_CERTIFICATE_HASH)(((PBYTE) RemoveUserList) + sizeof ( ENCRYPTION_CERTIFICATE_HASH_LIST ) + NoUsersToRemove * sizeof ( PENCRYPTION_CERTIFICATE_HASH) + RemoveUserIndex * sizeof (ENCRYPTION_CERTIFICATE_HASH)); RemoveUserList->pUsers[RemoveUserIndex] = EfsCertHash; EfsCertHash->cbTotalLength = sizeof (ENCRYPTION_CERTIFICATE_HASH); EfsCertHash->pUserSid = (SID *)UserSid; EfsCertHash->pHash = (PEFS_HASH_BLOB) CertData; EfsCertHash->lpDisplayInformation = NULL; RemoveUserIndex++; } else { ASSERT(FALSE); } } } ASSERT(RemoveUserIndex == NoUsersToRemove); ASSERT(AddUserIndex == NoUsersToAdd); if ( AddUserIndex && AddUserList ){ // // Add the user to the file list // RetCode = AddUsersToEncryptedFile(FileName, AddUserList); if ( NO_ERROR != RetCode ){ CString ErrMsg; TCHAR ErrCode[16]; _ltot(RetCode, ErrCode, 10 ); AfxFormatString1( ErrMsg, IDS_ADDUSERERR, ErrCode ); MessageBox(ErrMsg); } } if ( RemoveUserIndex && RemoveUserList){ // // Remove the user from the list // DWORD RetCodeBak = RetCode; RetCode = RemoveUsersFromEncryptedFile(FileName, RemoveUserList); if ( NO_ERROR != RetCode ){ CString ErrMsg; TCHAR ErrCode[16]; _ltot(RetCode, ErrCode, 10 ); AfxFormatString1( ErrMsg, IDS_REMOVEUSERERR, ErrCode ); MessageBox(ErrMsg); } else { // // Reflect the error happened // RetCode = RetCodeBak; } } if (AddUserList){ delete [] AddUserList; } if (RemoveUserList){ delete [] RemoveUserList; } return RetCode; } DWORD USERLIST::AddNewUsers(CUsers &NewUser) { DWORD RetCode = ERROR_SUCCESS; m_UserListCtrl.DeleteAllItems( ); RetCode = m_Users.Add(NewUser); SetUpListBox(NULL); return RetCode; } void USERLIST::SetUpListBox(BOOL *EnableAdd) { PVOID EnumHandle; try{ CString NoCertName; NoCertName.LoadString(IDS_NOCERTNAME); if (EnumHandle = m_Users.StartEnum()){ LV_ITEM fillItem; fillItem.mask = LVIF_TEXT; // // At least one user is available // while ( EnumHandle ){ CString CertName; CString CertHash; fillItem.iItem = 0; fillItem.iSubItem = 0; EnumHandle = m_Users.GetNextUser(EnumHandle, CertName, CertHash); if (!EnumHandle && CertName.IsEmpty() && CertHash.IsEmpty()) { // // No more items. // break; } if (CertName.IsEmpty()){ fillItem.pszText = NoCertName.GetBuffer(NoCertName.GetLength() + 1); } else { fillItem.pszText = CertName.GetBuffer(CertName.GetLength() + 1); } // // Add the user to the list // fillItem.iItem = m_UserListCtrl.InsertItem(&fillItem); if (CertName.IsEmpty()){ NoCertName.ReleaseBuffer(); } else { CertName.ReleaseBuffer(); } if ( fillItem.iItem != -1 ){ if ( EnableAdd ){ *EnableAdd = TRUE; } if (CertHash.IsEmpty()){ fillItem.pszText = NULL; } else { fillItem.pszText = CertHash.GetBuffer(CertHash.GetLength() + 1); } fillItem.iSubItem = 1; m_UserListCtrl.SetItem(&fillItem); if (!CertHash.IsEmpty()){ CertHash.ReleaseBuffer(); } } } } if (EnableAdd){ // // From the dialog init. Do the Rec list as well // if (EnumHandle = m_Recs.StartEnum()){ LV_ITEM fillItem; fillItem.mask = LVIF_TEXT; // // At least one user is available // while ( EnumHandle ){ CString CertName; CString CertHash; fillItem.iItem = 0; fillItem.iSubItem = 0; EnumHandle = m_Recs.GetNextUser(EnumHandle, CertName, CertHash); if (!EnumHandle && CertName.IsEmpty() && CertHash.IsEmpty()) { // // No more items. // break; } // // Add the agent to the list // if (CertName.IsEmpty()){ fillItem.pszText = NoCertName.GetBuffer(NoCertName.GetLength() + 1); } else { fillItem.pszText = CertName.GetBuffer(CertName.GetLength() + 1); } fillItem.iItem = m_RecoveryListCtrl.InsertItem(&fillItem); if (CertName.IsEmpty()){ NoCertName.ReleaseBuffer(); } else { CertName.ReleaseBuffer(); } if ( fillItem.iItem != -1 ){ if (CertHash.IsEmpty()){ fillItem.pszText = NULL; } else { fillItem.pszText = CertHash.GetBuffer(CertHash.GetLength() + 1); } fillItem.iSubItem = 1; m_RecoveryListCtrl.SetItem(&fillItem); if (!CertHash.IsEmpty()){ CertHash.ReleaseBuffer(); } } } } } } catch(...){ m_UserListCtrl.DeleteAllItems( ); m_RecoveryListCtrl.DeleteAllItems( ); if ( EnableAdd ){ *EnableAdd = FALSE; } } } DWORD USERLIST::GetCertNameFromCertContext( PCCERT_CONTEXT CertContext, LPTSTR * UserDispName ) ////////////////////////////////////////////////////////////////////// // Routine Description: // Get the user name from the certificate // Arguments: // CertContext -- Cert Context // UserCertName -- User Common Name // ( Caller is responsible to delete this memory using delete [] ) // Return Value: // ERROR_SUCCESS if succeed. // If No Name found. "USER_UNKNOWN is returned". // ////////////////////////////////////////////////////////////////////// { DWORD NameLength; DWORD UserNameBufLen = 0; DWORD BlobLen = 0; PCERT_EXTENSION AlterNameExt = NULL; BOOL b; LPTSTR DNSName = NULL; LPTSTR UPNName = NULL; LPTSTR CommonName = NULL; if ( NULL == UserDispName ){ return ERROR_SUCCESS; } *UserDispName = NULL; AlterNameExt = CertFindExtension( szOID_SUBJECT_ALT_NAME2, CertContext->pCertInfo->cExtension, CertContext->pCertInfo->rgExtension ); if (AlterNameExt){ // // Find the alternative name // b = CryptDecodeObject( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME , AlterNameExt->Value.pbData, AlterNameExt->Value.cbData, 0, NULL, &BlobLen ); if (b){ // // Let's decode it // CERT_ALT_NAME_INFO *AltNameInfo = NULL; AltNameInfo = (CERT_ALT_NAME_INFO *) new BYTE[BlobLen]; if (AltNameInfo){ b = CryptDecodeObject( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, szOID_SUBJECT_ALT_NAME, AlterNameExt->Value.pbData, AlterNameExt->Value.cbData, 0, AltNameInfo, &BlobLen ); if (b){ // // Now search for the UPN, SPN, DNS, EFS name // DWORD cAltEntry = AltNameInfo->cAltEntry; DWORD ii = 0; while (ii < cAltEntry){ if ((AltNameInfo->rgAltEntry[ii].dwAltNameChoice == CERT_ALT_NAME_OTHER_NAME ) && !strcmp(szOID_NT_PRINCIPAL_NAME, AltNameInfo->rgAltEntry[ii].pOtherName->pszObjId) ){ // // We found the UPN name // CERT_NAME_VALUE* CertUPNName = NULL; b = CryptDecodeObject( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_UNICODE_ANY_STRING, AltNameInfo->rgAltEntry[ii].pOtherName->Value.pbData, AltNameInfo->rgAltEntry[ii].pOtherName->Value.cbData, 0, NULL, &BlobLen ); if (b){ CertUPNName = (CERT_NAME_VALUE *) new BYTE[BlobLen]; if (CertUPNName){ b = CryptDecodeObject( X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_UNICODE_ANY_STRING, AltNameInfo->rgAltEntry[ii].pOtherName->Value.pbData, AltNameInfo->rgAltEntry[ii].pOtherName->Value.cbData, 0, CertUPNName, &BlobLen ); if (b){ UPNName = (LPTSTR)new BYTE[CertUPNName->Value.cbData + sizeof(WCHAR)]; if (UPNName){ wcscpy(UPNName, (LPCTSTR) CertUPNName->Value.pbData); } } delete [] CertUPNName; if (UPNName){ // // Got the UPN name. Stop searching. // break; } } } } else { // // Check for other alternative name // if (AltNameInfo->rgAltEntry[ii].dwAltNameChoice == CERT_ALT_NAME_DNS_NAME){ DNSName = AltNameInfo->rgAltEntry[ii].pwszDNSName; } } ii++; } if ( NULL == UPNName ){ // // No UPN name, let's get the other option // if (DNSName){ UPNName = (LPTSTR)new TCHAR[wcslen( DNSName ) + 1]; if (UPNName){ wcscpy(UPNName, DNSName); } } } } delete [] AltNameInfo; } } } NameLength = CertGetNameString( CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0 ); if ( NameLength > 1){ // // The display name exist. Go get the display name. // CommonName = new TCHAR[NameLength]; if ( NULL == CommonName ){ if (UPNName){ delete [] UPNName; } return ERROR_NOT_ENOUGH_MEMORY; } UserNameBufLen = NameLength; NameLength = CertGetNameString( CertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, CommonName, UserNameBufLen ); ASSERT (NameLength == UserNameBufLen); } if (CommonName || UPNName){ NameLength = 3; if (CommonName){ NameLength += wcslen(CommonName); } if (UPNName){ NameLength += wcslen(UPNName); } *UserDispName = new TCHAR[NameLength]; if (CommonName){ wcscpy(*UserDispName, CommonName); if (UPNName){ wcscat(*UserDispName, L"("); wcscat(*UserDispName, UPNName); wcscat(*UserDispName, L")"); } } else { wcscpy(*UserDispName, UPNName); } if (CommonName){ delete [] CommonName; } if (UPNName){ delete [] UPNName; } return ERROR_SUCCESS; } try { CString UnknownCertName; UnknownCertName.LoadString(IDS_NOCERTNAME); UserNameBufLen = UnknownCertName.GetLength(); *UserDispName = new TCHAR[UserNameBufLen + 1]; _tcscpy( *UserDispName, UnknownCertName); } catch (...){ return ERROR_NOT_ENOUGH_MEMORY; } return ERROR_SUCCESS; } void USERLIST::OnAdd() { CRYPTUI_SELECTCERTIFICATE_STRUCTW cryptUI; HCERTSTORE otherStore; HCERTSTORE trustedStore; HCERTSTORE memStore; HCERTSTORE localStore[2]; PCCERT_CONTEXT selectedCert; CString DlgTitle; CString DispText; LPTSTR UserDispName; HRESULT hr; DWORD rc; DWORD StoreNum = 0; DWORD StoreIndex = 0xffffffff; BOOL EfsEkuExist = FALSE; DWORD ii; BOOL ContinueProcess = TRUE; otherStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, // dwEncodingType 0, // hCryptProv, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_MAXIMUM_ALLOWED_FLAG, OTHERPEOPLE ); trustedStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, // dwEncodingType 0, // hCryptProv, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_MAXIMUM_ALLOWED_FLAG, TRUSTEDPEOPLE ); if (otherStore) { localStore[0] = otherStore; StoreNum++; } if (trustedStore) { localStore[StoreNum] = trustedStore; StoreNum++; } memStore = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0, CERT_STORE_MAXIMUM_ALLOWED_FLAG, NULL ); if (!memStore) { CString ErrMsg; TCHAR ErrCode[16]; _ltot(GetLastError(), ErrCode, 10 ); AfxFormatString1( ErrMsg, IDS_INTERNALERROR, ErrCode ); MessageBox(ErrMsg); if (otherStore) { CertCloseStore( otherStore, 0 ); } if (trustedStore) { CertCloseStore( trustedStore, 0 ); } return; } // // Let's put it into a memory store to eliminate the redundancy // ii = 0; while ( (ii < StoreNum) && ContinueProcess ) { PCCERT_CONTEXT pCertContext = NULL; while (pCertContext = CertEnumCertificatesInStore( localStore[ii], pCertContext )) { if (!CertAddCertificateLinkToStore( memStore, pCertContext, CERT_STORE_ADD_USE_EXISTING, NULL )){ CString ErrMsg; TCHAR ErrCode[16]; _ltot(GetLastError(), ErrCode, 10 ); AfxFormatString1( ErrMsg, IDS_INTERNALERROR, ErrCode ); MessageBox(ErrMsg); ContinueProcess = FALSE; break; } } ii++; } if (!ContinueProcess) { if (otherStore) { CertCloseStore( otherStore, 0 ); } if (trustedStore) { CertCloseStore( trustedStore, 0 ); } CertCloseStore( memStore, 0 ); return; } if (StoreNum != 0) { RtlZeroMemory(&cryptUI, sizeof (CRYPTUI_SELECTCERTIFICATE_STRUCTW)); cryptUI.dwSize = sizeof (CRYPTUI_SELECTCERTIFICATE_STRUCTW); cryptUI.dwFlags = CRYPTUI_SELECTCERT_ADDFROMDS; cryptUI.cDisplayStores = 1; cryptUI.rghDisplayStores = &memStore; cryptUI.pFilterCallback = EfsFilter; cryptUI.dwDontUseColumn = CRYPTUI_SELECT_LOCATION_COLUMN | CRYPTUI_SELECT_ISSUEDBY_COLUMN | CRYPTUI_SELECT_INTENDEDUSE_COLUMN; if (DlgTitle.LoadString(IDS_DLGTITLE)){ cryptUI.szTitle = (LPCWSTR) DlgTitle.GetBuffer(DlgTitle.GetLength() + 1); } if (DispText.LoadString(IDS_DISPTEXT)){ cryptUI.szDisplayString = (LPCWSTR) DispText.GetBuffer(DispText.GetLength() + 1); } selectedCert = CryptUIDlgSelectCertificateW(&cryptUI); if ( selectedCert ){ PCCERT_CHAIN_CONTEXT pChainContext; // // Let's first see if the cert is from DS, if Yes, add the EFS EKU first if no EKU. // StoreIndex = CertInStore(localStore, StoreNum, selectedCert); if (StoreIndex >= StoreNum){ // // The cert is not in the local stores. Let's see if we need add the EKU or not. // EfsEkuExist = EfsFilter(selectedCert, NULL, NULL); if (!EfsEkuExist) { // // Let's add the EFS EKU // CTL_USAGE EfsEkuUsage; DWORD cbEncoded; void *pbEncoded; CRYPT_DATA_BLOB EfsEkuBlob; EfsEkuUsage.cUsageIdentifier = 1; // Only adding EFS EKU EfsEkuUsage.rgpszUsageIdentifier = &EfsOidlpstr; if(!CryptEncodeObjectEx( X509_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE, &EfsEkuUsage, CRYPT_ENCODE_ALLOC_FLAG, NULL, // Use LocalFree &pbEncoded, &cbEncoded )){ // // Failed to encode the EFS EKU // CString ErrMsg; TCHAR ErrCode[16]; ContinueProcess = FALSE; _ltot(GetLastError(), ErrCode, 10 ); AfxFormatString1( ErrMsg, IDS_ADDEFSEKUFAIL, ErrCode ); MessageBox(ErrMsg); } else { // // Now let's add the EKU to the cert // EfsEkuBlob.cbData=cbEncoded; EfsEkuBlob.pbData=(BYTE *)pbEncoded; if(!CertSetCertificateContextProperty( selectedCert, CERT_ENHKEY_USAGE_PROP_ID, 0, &EfsEkuBlob)){ // // Failed to add the EFS EKU // CString ErrMsg; TCHAR ErrCode[16]; ContinueProcess = FALSE; _ltot(GetLastError(), ErrCode, 10 ); AfxFormatString1( ErrMsg, IDS_ADDEFSEKUFAIL, ErrCode ); MessageBox(ErrMsg); } } } } // // Let's validate the cert first // if (ContinueProcess && CertGetCertificateChain ( HCCE_CURRENT_USER, selectedCert, NULL, NULL, &m_CertChainPara, CERT_CHAIN_REVOCATION_CHECK_CHAIN, NULL, &pChainContext )) { PCERT_SIMPLE_CHAIN pChain = pChainContext->rgpChain[ pChainContext->cChain - 1 ]; PCERT_CHAIN_ELEMENT pElement = pChain->rgpElement[ pChain->cElement - 1 ]; BOOL bSelfSigned = pElement->TrustStatus.dwInfoStatus & CERT_TRUST_IS_SELF_SIGNED; BOOL ContinueAdd = TRUE; DWORD dwErrorStatus = pChainContext->TrustStatus.dwErrorStatus; if (0 == (dwErrorStatus & ~CERT_TRUST_REVOCATION_STATUS_UNKNOWN)) { // // The validation succeed. If the cert is from the DS (not in the store we opened), we will put it // in the my Other People's store // if (StoreIndex >= StoreNum) { // // The cert is not in our local stores. Add it to the other people // if (otherStore) { if(!CertAddCertificateContextToStore( otherStore, selectedCert, CERT_STORE_ADD_NEW, NULL) ) { // // The error code is only for debug. // If we failed to add the cert to other People store, // it is fine to continue // rc = GetLastError(); } } } } else { // // The cert validation failed, as the user if we will accept the cert. If yes, the cert // will be added to my TrustedPeople. // if (((dwErrorStatus & ~CERT_TRUST_REVOCATION_STATUS_UNKNOWN) == CERT_TRUST_IS_UNTRUSTED_ROOT) && bSelfSigned) { // // A self signed cert. Ask the user if he would like to accept. // If it is already in the trusted store, we can skip the pop up. // DWORD StoreIndex; if (trustedStore) { StoreIndex = CertInStore(&trustedStore, 1, selectedCert); } if (StoreIndex >= 1) { CString ErrMsg; TCHAR ErrCode[16]; int buttonID; _ltot(GetLastError(), ErrCode, 10 ); AfxFormatString1( ErrMsg, IDS_ACCEPTSELFCERT, ErrCode ); buttonID = MessageBox(ErrMsg, NULL, MB_ICONQUESTION | MB_YESNO); if (IDYES == buttonID) { // // User Accepted the cert. // if (trustedStore) { if(!CertAddCertificateContextToStore( trustedStore, selectedCert, CERT_STORE_ADD_NEW, NULL) ) { // // The error code is only for debug. // If we failed to add the cert to other People store, // it is fine to continue // rc = GetLastError(); } } } else { // // User declined the cert. // ContinueAdd = FALSE; } } } else { // // Let's get the error code of the chain building. // CERT_CHAIN_POLICY_PARA PolicyPara; CERT_CHAIN_POLICY_STATUS PolicyStatus; ContinueAdd = FALSE; RtlZeroMemory(&PolicyPara, sizeof(CERT_CHAIN_POLICY_PARA)); RtlZeroMemory(&PolicyStatus, sizeof(CERT_CHAIN_POLICY_STATUS)); PolicyPara.cbSize = sizeof(CERT_CHAIN_POLICY_PARA); PolicyStatus.cbSize = sizeof(CERT_CHAIN_POLICY_STATUS); if (CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_BASE, pChainContext, &PolicyPara, &PolicyStatus ) && PolicyStatus.dwError ) { // // Display the error to the user. // DWORD len; LPWSTR DisplayBuffer; len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, PolicyStatus.dwError, 0, (LPWSTR)&DisplayBuffer, 0, NULL); if (len && DisplayBuffer) { MessageBox(DisplayBuffer); LocalFree(DisplayBuffer); } } } } CertFreeCertificateChain( pChainContext ); if (ContinueAdd) { hr = GetCertNameFromCertContext(selectedCert, &UserDispName); if ( ERROR_SUCCESS == hr ){ EFS_CERTIFICATE_BLOB CertBlob; CertBlob.cbData = selectedCert->cbCertEncoded; CertBlob.pbData = selectedCert->pbCertEncoded; CertBlob.dwCertEncodingType = selectedCert->dwCertEncodingType; hr = m_Users.Add( UserDispName, (PVOID)&CertBlob, NULL, USERADDED, (PVOID)selectedCert ); if ( (ERROR_SUCCESS != hr) && (CRYPT_E_EXISTS != hr) ){ // // Error in adding the user // CertFreeCertificateContext(selectedCert); selectedCert = NULL; } else { // // We could just insert the items here to improve the performace. // But we don't have the time right now. We could fix this later // if performance is a problem here. // m_UserListCtrl.DeleteAllItems( ); SetUpListBox(NULL); if ( hr == ERROR_SUCCESS ){ // // UserDispName is used in m_Users.Add // UserDispName = NULL; } /* This is the old code when we have the single list. // // Add the user to the list box. // if ( hr == ERROR_SUCCESS ){ if (m_UsersList.AddString(UserDispName) < 0){ // // Error to add to the list box // m_Users.Remove(UserDispName); } UserDispName = NULL; } else { // // Let's check if we need to add this to the list box. // if (m_UsersList.FindStringExact( 0, UserDispName ) < 0){ // // Not found // if (m_UsersList.AddString(UserDispName) < 0){ // // Error to add to the list box // m_Users.Remove(UserDispName); } } } */ } if (UserDispName){ delete [] UserDispName; } } else { CertFreeCertificateContext(selectedCert); } } } else { CString ErrMsg; TCHAR ErrCode[16]; CertFreeCertificateContext(selectedCert); if (ContinueProcess) { // // The error has not been processed. // _ltot(GetLastError(), ErrCode, 10 ); AfxFormatString1( ErrMsg, IDS_COULDNOTVERIFYCERT, ErrCode ); MessageBox(ErrMsg); } } } if (!DlgTitle.IsEmpty()){ DlgTitle.ReleaseBuffer(); } if (!DispText.IsEmpty()){ DispText.ReleaseBuffer(); } if (otherStore) { CertCloseStore( otherStore, 0 ); } if (trustedStore) { CertCloseStore( trustedStore, 0 ); } } CertCloseStore( memStore, 0 ); return; } DWORD USERLIST::TryGetBetterNameInCert(PEFS_HASH_BLOB HashData, LPTSTR *UserName) { HCERTSTORE localStore; PCCERT_CONTEXT pCertContext; DWORD retCode; // // We will add the remote case later // localStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, 0, // dwEncodingType 0, // hCryptProv, CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_MAXIMUM_ALLOWED_FLAG, TRUSTEDPEOPLE ); if (localStore != NULL) { // // Let's try to the cert in the store // pCertContext = CertFindCertificateInStore( localStore, CRYPT_ASN_ENCODING, 0, CERT_FIND_HASH, (CRYPT_HASH_BLOB *)HashData, NULL ); if ( pCertContext ){ retCode = GetCertNameFromCertContext( pCertContext, UserName ); CertFreeCertificateContext(pCertContext); } else { retCode = GetLastError(); } CertCloseStore( localStore, 0 ); } else { retCode = GetLastError(); } return retCode; } DWORD USERLIST::CertInStore(HCERTSTORE *pStores, DWORD StoreNum, PCCERT_CONTEXT selectedCert) { DWORD ii = 0; PCCERT_CONTEXT pCert = NULL; while (ii < StoreNum) { pCert = CertFindCertificateInStore( pStores[ii], X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_EXISTING, selectedCert, pCert ); if (pCert) { // // We found it. // CertFreeCertificateContext(pCert); break; } ii++; } return ii; } void USERLIST::OnSetfocusListuser(NMHDR* pNMHDR, LRESULT* pResult) { int ItemPos; ShowRemove(); ItemPos = m_UserListCtrl.GetNextItem( -1, LVNI_SELECTED ); if ( ItemPos == -1 ){ m_UserListCtrl.SetItem(0, 0, LVIF_STATE, NULL, 0, LVIS_SELECTED, LVIS_SELECTED, 0); } *pResult = 0; } void USERLIST::OnKillfocusListuser(NMHDR* pNMHDR, LRESULT* pResult) { ShowRemove(); *pResult = 0; } void USERLIST::OnItemchangedListuser(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; ShowRemove(); *pResult = 0; }