WindowsXP-SP1/shell/osshell/encrypt/userlist.cpp

1805 lines
53 KiB
C++

// USERLIST.cpp : implementation file
//
#include "stdafx.h"
#include "EFSADU.h"
#include "USERLIST.h"
#include "cryptui.h"
#include "objsel.h"
#include <winefs.h>
#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;
}