647 lines
17 KiB
C++
647 lines
17 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997-2001.
|
|
//
|
|
// File: Users.cpp
|
|
//
|
|
// Contents:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// Users.cpp: implementation of the CUsers class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "Users.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#ifndef ALPHA
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CUsers::CUsers()
|
|
{
|
|
m_UsersRoot = NULL;
|
|
m_UserAddedCnt = 0;
|
|
m_UserRemovedCnt = 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Walk through the chain to free the memory
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CUsers::~CUsers()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
PUSERSONFILE
|
|
CUsers::RemoveItemFromHead(void)
|
|
{
|
|
PUSERSONFILE PItem = m_UsersRoot;
|
|
if (m_UsersRoot){
|
|
m_UsersRoot = m_UsersRoot->m_pNext;
|
|
if ((PItem->m_dwFlag & USERADDED) && !(PItem->m_dwFlag & USERREMOVED)){
|
|
m_UserAddedCnt--;
|
|
}
|
|
if ((PItem->m_dwFlag & USERINFILE) && (PItem->m_dwFlag & USERREMOVED)){
|
|
m_UserRemovedCnt--;
|
|
}
|
|
}
|
|
return PItem;
|
|
}
|
|
|
|
DWORD
|
|
CUsers::Add( CUsers &NewUsers )
|
|
{
|
|
PUSERSONFILE NewItem = NewUsers.RemoveItemFromHead();
|
|
|
|
while ( NewItem )
|
|
{
|
|
PUSERSONFILE TmpItem = m_UsersRoot;
|
|
|
|
while ( TmpItem )
|
|
{
|
|
|
|
if ((NewItem->m_szUserName && TmpItem->m_szUserName && !_tcsicmp(NewItem->m_szUserName, TmpItem->m_szUserName)) ||
|
|
( !NewItem->m_szUserName && !TmpItem->m_szUserName))
|
|
{
|
|
if ( !TmpItem->m_szUserName)
|
|
{
|
|
bool bUserMatched = false;
|
|
|
|
if (( !NewItem->m_szDnName && !TmpItem->m_szDnName) ||
|
|
(NewItem->m_szDnName && TmpItem->m_szDnName && !_tcsicmp(NewItem->m_szDnName, TmpItem->m_szDnName)))
|
|
{
|
|
bUserMatched = true;
|
|
}
|
|
|
|
if ( !bUserMatched )
|
|
{
|
|
TmpItem = TmpItem->m_pNext;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// User exist
|
|
//
|
|
|
|
if ( TmpItem->m_dwFlag & USERREMOVED )
|
|
{
|
|
if ( TmpItem->m_dwFlag & USERADDED )
|
|
{
|
|
ASSERT(!(TmpItem->m_dwFlag & USERINFILE));
|
|
|
|
//
|
|
// User added and removed
|
|
//
|
|
m_UserAddedCnt++;
|
|
|
|
}
|
|
else if ( TmpItem->m_dwFlag & USERINFILE )
|
|
{
|
|
//
|
|
// User added and removed
|
|
//
|
|
m_UserRemovedCnt--;
|
|
|
|
}
|
|
TmpItem->m_dwFlag &= ~USERREMOVED;
|
|
}
|
|
|
|
//
|
|
// The caller will count on CUsers to release the memory
|
|
//
|
|
|
|
if (NewItem->m_szUserName)
|
|
{
|
|
delete [] NewItem->m_szUserName;
|
|
}
|
|
if (NewItem->m_szDnName)
|
|
{
|
|
delete [] NewItem->m_szDnName;
|
|
}
|
|
if ( NewItem->m_pCertContext )
|
|
{
|
|
CertFreeCertificateContext(NewItem->m_pCertContext);
|
|
}
|
|
delete [] NewItem->m_pCert;
|
|
if (NewItem->m_UserSid)
|
|
{
|
|
delete [] NewItem->m_UserSid;
|
|
}
|
|
delete NewItem;
|
|
NewItem = NULL;
|
|
break;
|
|
}
|
|
TmpItem = TmpItem->m_pNext;
|
|
}
|
|
|
|
if (NewItem )
|
|
{
|
|
//
|
|
// New item. Insert into the head.
|
|
//
|
|
|
|
NewItem->m_pNext = m_UsersRoot;
|
|
m_UsersRoot = NewItem;
|
|
m_UserAddedCnt++;
|
|
}
|
|
|
|
NewItem = NewUsers.RemoveItemFromHead();
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
CUsers::Add(
|
|
LPWSTR pszUserName,
|
|
LPWSTR pszDnName,
|
|
PVOID UserCert,
|
|
PSID UserSid, /* = NULL */
|
|
DWORD dwFlag, /* = USERINFILE */
|
|
PCCERT_CONTEXT pCertContext /* = NULL */
|
|
)
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine Description:
|
|
// Create an item for a user
|
|
// Arguments:
|
|
// m_szUserName -- User's name
|
|
// m_szDnName -- User's distinguished name
|
|
// UserCert -- User's certificate blob or hash
|
|
// m_UserSid -- User's ID. Can be NULL
|
|
// m_dwFlag -- Indicate if the item is existing in the file, to be added or removed
|
|
// Return Value:
|
|
// NO_ERROR if succeed.
|
|
// Will throw exception if memory allocation fails. ( From new.)
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
{
|
|
|
|
PUSERSONFILE UserItem = 0;
|
|
PUSERSONFILE TmpUserItem = m_UsersRoot;
|
|
PEFS_CERTIFICATE_BLOB CertBlob;
|
|
PEFS_HASH_BLOB CertHashBlob;
|
|
DWORD CertSize;
|
|
DWORD SidSize;
|
|
|
|
if ( !UserCert )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
ASSERT ( (( dwFlag & USERADDED ) || ( dwFlag & USERINFILE )) &&
|
|
( (dwFlag & (USERADDED | USERINFILE)) != (USERADDED | USERINFILE)));
|
|
|
|
|
|
//
|
|
// If the user already in the memory, no new item is to be created except for unknown user
|
|
//
|
|
|
|
while ( TmpUserItem )
|
|
{
|
|
if ( (pszUserName && TmpUserItem->m_szUserName && !_tcsicmp(pszUserName, TmpUserItem->m_szUserName)) ||
|
|
((!pszUserName) && (TmpUserItem->m_szUserName == NULL)))
|
|
{
|
|
if (!pszUserName)
|
|
{
|
|
bool bUserMatched = false;
|
|
|
|
if (( !pszDnName && !TmpUserItem->m_szDnName) ||
|
|
(pszDnName && TmpUserItem->m_szDnName && !_tcsicmp(pszDnName, TmpUserItem->m_szDnName)))
|
|
{
|
|
bUserMatched = true;
|
|
}
|
|
|
|
if ( !bUserMatched )
|
|
{
|
|
TmpUserItem = TmpUserItem->m_pNext;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// User exist
|
|
//
|
|
|
|
if ( TmpUserItem->m_dwFlag & USERREMOVED )
|
|
{
|
|
if ( TmpUserItem->m_dwFlag & USERADDED )
|
|
{
|
|
ASSERT(!(TmpUserItem->m_dwFlag & USERINFILE));
|
|
|
|
//
|
|
// User added and removed
|
|
//
|
|
m_UserAddedCnt++;
|
|
|
|
}
|
|
else if ( TmpUserItem->m_dwFlag & USERINFILE )
|
|
{
|
|
//
|
|
// User added and removed
|
|
//
|
|
m_UserRemovedCnt--;
|
|
|
|
}
|
|
TmpUserItem->m_dwFlag &= ~USERREMOVED;
|
|
}
|
|
|
|
//
|
|
// The caller will count on CUsers to release the memory
|
|
// for Username and the context if the call is succeeded. This is just for
|
|
// performance reason.
|
|
//
|
|
|
|
if (pszUserName)
|
|
{
|
|
delete [] pszUserName;
|
|
}
|
|
if (pszDnName)
|
|
{
|
|
delete [] pszDnName;
|
|
}
|
|
if ( pCertContext )
|
|
{
|
|
::CertFreeCertificateContext (pCertContext);
|
|
pCertContext = NULL;
|
|
}
|
|
return (DWORD) CRYPT_E_EXISTS;
|
|
}
|
|
TmpUserItem = TmpUserItem->m_pNext;
|
|
}
|
|
|
|
try {
|
|
UserItem = new USERSONFILE;
|
|
if ( !UserItem )
|
|
{
|
|
AfxThrowMemoryException( );
|
|
}
|
|
|
|
UserItem->m_pNext = NULL;
|
|
|
|
//
|
|
// In case exception raised, we can call delete.
|
|
// Delete NULL is OK, but random data is not OK.
|
|
//
|
|
|
|
UserItem->m_UserSid = NULL;
|
|
UserItem->m_pCert = NULL;
|
|
UserItem->m_pCertContext = NULL;
|
|
|
|
if ( UserSid )
|
|
{
|
|
SidSize = GetLengthSid (UserSid );
|
|
if ( SidSize > 0 )
|
|
{
|
|
UserItem->m_UserSid = new BYTE[SidSize];
|
|
if ( !UserItem->m_UserSid )
|
|
{
|
|
AfxThrowMemoryException( );
|
|
}
|
|
if ( !CopySid(SidSize, UserItem->m_UserSid, UserSid))
|
|
{
|
|
delete [] UserItem->m_UserSid;
|
|
delete UserItem;
|
|
return GetLastError();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
delete UserItem;
|
|
return GetLastError();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UserItem->m_UserSid = NULL;
|
|
}
|
|
|
|
if ( dwFlag & USERINFILE )
|
|
{
|
|
|
|
//
|
|
// The info is from the file. Use the hash structure
|
|
//
|
|
|
|
CertHashBlob = ( PEFS_HASH_BLOB ) UserCert;
|
|
CertSize = sizeof(EFS_HASH_BLOB) + CertHashBlob->cbData;
|
|
UserItem->m_pCert = new BYTE[CertSize];
|
|
if ( !UserItem->m_pCert )
|
|
{
|
|
AfxThrowMemoryException( );
|
|
}
|
|
((PEFS_HASH_BLOB)UserItem->m_pCert)->cbData = CertHashBlob->cbData;
|
|
((PEFS_HASH_BLOB)UserItem->m_pCert)->pbData = (PBYTE)(UserItem->m_pCert) + sizeof(EFS_HASH_BLOB);
|
|
memcpy(((PEFS_HASH_BLOB)UserItem->m_pCert)->pbData,
|
|
CertHashBlob->pbData,
|
|
CertHashBlob->cbData
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The info is from the user picked cert. Use m_pCert Blob structure
|
|
//
|
|
|
|
CertBlob = ( PEFS_CERTIFICATE_BLOB ) UserCert;
|
|
CertSize = sizeof(EFS_CERTIFICATE_BLOB) + CertBlob->cbData;
|
|
UserItem->m_pCert = new BYTE[CertSize];
|
|
if ( NULL == UserItem->m_pCert ){
|
|
AfxThrowMemoryException( );
|
|
}
|
|
((PEFS_CERTIFICATE_BLOB)UserItem->m_pCert)->cbData = CertBlob->cbData;
|
|
((PEFS_CERTIFICATE_BLOB)UserItem->m_pCert)->dwCertEncodingType = CertBlob->dwCertEncodingType;
|
|
((PEFS_CERTIFICATE_BLOB)UserItem->m_pCert)->pbData = (PBYTE)(UserItem->m_pCert) + sizeof(EFS_CERTIFICATE_BLOB);
|
|
memcpy(((PEFS_CERTIFICATE_BLOB)UserItem->m_pCert)->pbData,
|
|
CertBlob->pbData,
|
|
CertBlob->cbData
|
|
);
|
|
|
|
}
|
|
|
|
UserItem->m_szUserName = pszUserName;
|
|
UserItem->m_szDnName = pszDnName;
|
|
UserItem->m_pCertContext = pCertContext;
|
|
UserItem->m_dwFlag = dwFlag;
|
|
if ( dwFlag & USERADDED )
|
|
{
|
|
m_UserAddedCnt ++;
|
|
}
|
|
}
|
|
catch (...) {
|
|
delete [] UserItem->m_UserSid;
|
|
delete [] UserItem->m_pCert;
|
|
delete UserItem;
|
|
AfxThrowMemoryException( );
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Add to the head
|
|
//
|
|
|
|
if ( m_UsersRoot )
|
|
{
|
|
UserItem->m_pNext = m_UsersRoot;
|
|
}
|
|
m_UsersRoot = UserItem;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
DWORD
|
|
CUsers::Remove(
|
|
LPCWSTR m_szUserName,
|
|
LPCWSTR UserCertName
|
|
)
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine Description:
|
|
// Remove a user from the list. Actually just mark for remove.
|
|
// Arguments:
|
|
// m_szUserName -- User's name
|
|
// UserCertName -- User's certificate name
|
|
// Return Value:
|
|
// NO_ERROR if succeed.
|
|
// ERROR_NOT_FOUND if the user cannot be found.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
{
|
|
PUSERSONFILE TmpUserItem = m_UsersRoot;
|
|
bool bUserMatched = false;
|
|
|
|
while ( TmpUserItem ){
|
|
if (((NULL==m_szUserName) && ( NULL == TmpUserItem->m_szUserName)) ||
|
|
( m_szUserName && TmpUserItem->m_szUserName && !_tcsicmp(m_szUserName, TmpUserItem->m_szUserName))){
|
|
|
|
//
|
|
// Make sure the CertName matches also if the user name is NULL
|
|
//
|
|
|
|
if (NULL==m_szUserName)
|
|
{
|
|
if (((NULL==UserCertName) && ( NULL == TmpUserItem->m_szDnName)) ||
|
|
(UserCertName && TmpUserItem->m_szDnName && !_tcsicmp(UserCertName, TmpUserItem->m_szDnName))){
|
|
|
|
bUserMatched = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bUserMatched = true;
|
|
}
|
|
|
|
if (bUserMatched)
|
|
{
|
|
//
|
|
// User exist, mark it for remove
|
|
//
|
|
|
|
if ( TmpUserItem->m_dwFlag & USERINFILE ){
|
|
m_UserRemovedCnt++;
|
|
} else if ( TmpUserItem->m_dwFlag & USERADDED ) {
|
|
m_UserAddedCnt--;
|
|
}
|
|
TmpUserItem->m_dwFlag |= USERREMOVED;
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
TmpUserItem = TmpUserItem->m_pNext;
|
|
}
|
|
return ERROR_NOT_FOUND;
|
|
}
|
|
|
|
PUSERSONFILE CUsers::StartEnum()
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine Description:
|
|
// Prepare for GetNextUser
|
|
// Arguments:
|
|
//
|
|
// Return Value:
|
|
// A pointer used for GetNextUser
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
{
|
|
return m_UsersRoot;
|
|
}
|
|
|
|
PUSERSONFILE CUsers::GetNextUser(
|
|
PUSERSONFILE Token,
|
|
CString &szUserName,
|
|
CString &CertName
|
|
)
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine Description:
|
|
// Get next user in the list.(Not removed).
|
|
// Arguments:
|
|
// m_szUserName -- m_pNext User's name
|
|
// CertName -- Certificate name
|
|
// Token -- A pointer returned by previous GetNextUser or StartEnum.
|
|
// Return Value:
|
|
// A pointer for GetNextUser()
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
{
|
|
|
|
PUSERSONFILE TmpItem = Token;
|
|
PUSERSONFILE RetPointer = NULL;
|
|
|
|
while ( TmpItem )
|
|
{
|
|
if ( TmpItem->m_dwFlag & USERREMOVED )
|
|
{
|
|
TmpItem = TmpItem->m_pNext;
|
|
continue;
|
|
}
|
|
|
|
try{
|
|
szUserName = TmpItem->m_szUserName;
|
|
CertName = TmpItem->m_szDnName;
|
|
RetPointer = TmpItem->m_pNext;
|
|
}
|
|
catch (...){
|
|
|
|
//
|
|
// Out of memory
|
|
//
|
|
|
|
TmpItem = NULL;
|
|
RetPointer = NULL;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ( NULL == TmpItem )
|
|
{
|
|
szUserName.Empty();
|
|
CertName.Empty();
|
|
}
|
|
return RetPointer;
|
|
|
|
}
|
|
|
|
DWORD CUsers::GetUserAddedCnt()
|
|
{
|
|
return m_UserAddedCnt;
|
|
}
|
|
|
|
DWORD CUsers::GetUserRemovedCnt()
|
|
{
|
|
return m_UserRemovedCnt;
|
|
}
|
|
|
|
PVOID CUsers::GetNextChangedUser(
|
|
PVOID Token,
|
|
LPWSTR * m_szUserName,
|
|
LPWSTR * m_szDnName,
|
|
PSID * m_UserSid,
|
|
PVOID * CertData,
|
|
DWORD * m_dwFlag
|
|
)
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine Description:
|
|
// Get the info for changed users. This method is not well behaved in the
|
|
// sense of OOP. It exposes internal pointers to the ouside world. The gain
|
|
// is performance. At this moment, CUsers is a supporting class and used only
|
|
// by USERLIST and CAddEFSWizSheet (single thread). We can make USERLIST a
|
|
// friend of CUsers if such concerns are raised in the future or reimplement this.
|
|
// The same issue applies to the enumerate methods.
|
|
//
|
|
// Arguments:
|
|
// Token -- A pointer to the item returned in previous GetNextChangedUser or StartEnum.
|
|
// m_szUserName -- User's name
|
|
// m_szDnName -- User's Distinguished name
|
|
// CertData -- User's certificate blob or hash
|
|
// m_UserSid -- User's ID. Can be NULL
|
|
// m_dwFlag -- Indicate if the item is existing in the file, to be added or removed
|
|
// Return Value:
|
|
// m_pNext item pointer.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
{
|
|
bool bChangedUserFound = false;
|
|
|
|
while ( Token )
|
|
{
|
|
*m_dwFlag = ((PUSERSONFILE) Token)->m_dwFlag;
|
|
|
|
if ( ( *m_dwFlag & USERADDED ) && !( *m_dwFlag & USERREMOVED ))
|
|
{
|
|
//
|
|
// The user is to to be added to the file
|
|
//
|
|
|
|
*m_dwFlag = USERADDED;
|
|
bChangedUserFound = true;
|
|
}
|
|
else if ( ( *m_dwFlag & USERREMOVED ) && ( *m_dwFlag & USERINFILE))
|
|
{
|
|
//
|
|
// The user is to be removed from the file
|
|
//
|
|
|
|
*m_dwFlag = USERREMOVED;
|
|
bChangedUserFound = true;
|
|
}
|
|
|
|
if ( bChangedUserFound )
|
|
{
|
|
*m_szUserName = ((PUSERSONFILE) Token)->m_szUserName;
|
|
*m_szDnName = ((PUSERSONFILE) Token)->m_szDnName;
|
|
*m_UserSid = ((PUSERSONFILE) Token)->m_UserSid;
|
|
*CertData = ((PUSERSONFILE) Token)->m_pCert;
|
|
return ((PUSERSONFILE) Token)->m_pNext;
|
|
}
|
|
else
|
|
{
|
|
Token = ((PUSERSONFILE) Token)->m_pNext;
|
|
}
|
|
|
|
}
|
|
|
|
*m_szUserName = NULL;
|
|
*m_szDnName = NULL;
|
|
*m_UserSid = NULL;
|
|
*CertData = NULL;
|
|
*m_dwFlag = 0;
|
|
return NULL;
|
|
}
|
|
|
|
void CUsers::Clear()
|
|
{
|
|
PUSERSONFILE TmpUserItem = m_UsersRoot;
|
|
while (TmpUserItem)
|
|
{
|
|
m_UsersRoot = TmpUserItem->m_pNext;
|
|
delete [] TmpUserItem->m_szUserName;
|
|
delete [] TmpUserItem->m_szDnName;
|
|
delete [] TmpUserItem->m_pCert;
|
|
if (TmpUserItem->m_UserSid)
|
|
{
|
|
delete [] TmpUserItem->m_UserSid;
|
|
}
|
|
if (TmpUserItem->m_pCertContext)
|
|
{
|
|
::CertFreeCertificateContext(TmpUserItem->m_pCertContext);
|
|
}
|
|
delete TmpUserItem;
|
|
TmpUserItem = m_UsersRoot;
|
|
}
|
|
|
|
m_UsersRoot = NULL;
|
|
m_UserAddedCnt = 0;
|
|
m_UserRemovedCnt = 0;
|
|
|
|
}
|