Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1025 lines
28 KiB

//+----------------------------------------------------------------------------
//
// File: pwutil.cpp
//
// Module: Common Source
//
// Synopsis: Simple encryption funcs - borrowed from RAS
//
// Copyright (c) 1994-1999 Microsoft Corporation
//
// Author: nickball Created 08/03/99
//
//+----------------------------------------------------------------------------
#define PASSWORDMAGIC 0xA5
VOID
ReverseSzA(
CHAR* psz )
/* Reverses order of characters in 'psz'.
*/
{
CHAR* pszBegin;
CHAR* pszEnd;
for (pszBegin = psz, pszEnd = psz + lstrlenA( psz ) - 1;
pszBegin < pszEnd;
++pszBegin, --pszEnd)
{
CHAR ch = *pszBegin;
*pszBegin = *pszEnd;
*pszEnd = ch;
}
}
VOID
ReverseSzW(
WCHAR* psz )
/* Reverses order of characters in 'psz'.
*/
{
WCHAR* pszBegin;
WCHAR* pszEnd;
for (pszBegin = psz, pszEnd = psz + lstrlenW( psz ) - 1;
pszBegin < pszEnd;
++pszBegin, --pszEnd)
{
WCHAR ch = *pszBegin;
*pszBegin = *pszEnd;
*pszEnd = ch;
}
}
VOID
CmDecodePasswordA(
IN OUT CHAR* pszPassword )
/* Un-obfuscate 'pszPassword' in place.
**
** Returns Nothing
*/
{
CmEncodePasswordA( pszPassword );
}
VOID
CmDecodePasswordW(
IN OUT WCHAR* pszPassword )
/* Un-obfuscate 'pszPassword' in place.
**
** Returns the address of 'pszPassword'.
*/
{
CmEncodePasswordW( pszPassword );
}
VOID
CmEncodePasswordA(
IN OUT CHAR* pszPassword )
/* Obfuscate 'pszPassword' in place to foil memory scans for passwords.
**
** Returns Nothing
*/
{
if (pszPassword)
{
CHAR* psz;
ReverseSzA( pszPassword );
for (psz = pszPassword; *psz != '\0'; ++psz)
{
if (*psz != PASSWORDMAGIC)
*psz ^= PASSWORDMAGIC;
}
}
}
VOID
CmEncodePasswordW(
IN OUT WCHAR* pszPassword )
/* Obfuscate 'pszPassword' in place to foil memory scans for passwords.
**
** Returns Nothing
*/
{
if (pszPassword)
{
WCHAR* psz;
ReverseSzW( pszPassword );
for (psz = pszPassword; *psz != L'\0'; ++psz)
{
if (*psz != PASSWORDMAGIC)
*psz ^= PASSWORDMAGIC;
}
}
}
VOID
CmWipePasswordA(
IN OUT CHAR* pszPassword )
/* Zero out the memory occupied by a password.
**
** Returns Nothing
*/
{
if (pszPassword)
{
CHAR* psz = pszPassword;
//
// We are assuming the string is NULL terminated, thus we just need to pass
// the actual string length (converted to bytes) to be wiped. The is no need
// to include the NULL character in the count.
//
psz = (CHAR*)CmSecureZeroMemory((PVOID)psz, lstrlenA(psz) * sizeof(CHAR));
}
}
VOID
CmWipePasswordW(
IN OUT WCHAR* pszPassword )
/* Zero out the memory occupied by a password.
**
** Returns Nothing
*/
{
if (pszPassword)
{
WCHAR* psz = pszPassword;
//
// We are assuming the string is NULL terminated, thus we just need to pass
// the actual string length (converted to bytes) to be wiped. The is no need
// to include the NULL character in the count.
//
psz = (WCHAR*)CmSecureZeroMemory((PVOID)psz, lstrlenW(psz) * sizeof(WCHAR));
}
}
//+----------------------------------------------------------------------------
//
// Function: CmSecureZeroMemory
//
// Synopsis: RtlSecureZeroMemory isn't available on all platforms so we took
// its implementation.
//
// Arguments: ptr - memory pointer
// cnt - size in bytes of memory to clear
//
// Returns: poniter to beginning of memory
//
//+----------------------------------------------------------------------------
PVOID CmSecureZeroMemory(IN PVOID ptr, IN SIZE_T cnt)
{
if (ptr)
{
volatile char *vptr = (volatile char *)ptr;
while (cnt)
{
*vptr = 0;
vptr++;
cnt--;
}
}
return ptr;
}
// Only include this code in CMDial32.dll
#ifdef _ICM_INC
//+----------------------------------------------------------------------------
// Class: CSecurePassword
//
// Function: CSecurePassword
//
// Synopsis: Constructor
//
// Arguments: none
//
// Returns: Nothing
//
// History: 11/05/2002 tomkel Created
//
//+----------------------------------------------------------------------------
CSecurePassword::CSecurePassword()
{
this->Init();
}
//+----------------------------------------------------------------------------
//
// Function: ~CSecurePassword
//
// Synopsis: Destructor. Unloads DLL, tries to clear memory & free memory.
// Makes sure we don't have a memory leak.
//
// Arguments: none
//
// Returns: Nothing
//
//+----------------------------------------------------------------------------
CSecurePassword::~CSecurePassword()
{
this->UnInit();
//
// Assert if m_iAllocAndFreeCounter isn't zero. It means we are leaking memory.
// Each GetPasswordWithAlloc call increments this
// Each ClearAndFree call decrements this.
//
MYDBGASSERT(0 == m_iAllocAndFreeCounter);
}
//+----------------------------------------------------------------------------
//
// Function: Init
//
// Synopsis: Initializes member variables.
//
// Arguments: none
//
// Returns: Nothing
//
//+----------------------------------------------------------------------------
VOID CSecurePassword::Init()
{
m_iAllocAndFreeCounter = 0;
m_fIsLibAndFuncPtrsAvail = FALSE;
m_pEncryptedPW = NULL;
fnCryptProtectData = NULL;
fnCryptUnprotectData = NULL;
m_fIsEmptyString = TRUE;
m_fIsHandleToPassword = FALSE;
// By default just set it to PWLEN
m_dwMaxDataLen = PWLEN;
this->ClearMemberVars();
}
//+----------------------------------------------------------------------------
//
// Function: SetPassword
//
// Synopsis: We take this string that is passed in and store it
// internally. Based on the OS it encrypts
// or encodes it, thus we don't store it in clear. This method handles
// 0 length strings, which can be used to clear the member
// variable. If a RAS password handle (consists of 16 '*'),
// there is no need for us to encrypt it. To optimize this
// we set an member flag specifying that currently this
// instance just hold a handle to a password. On downlevel
// platforms we don't use expensive encryption calls, thus
// the logic doesn't distinguish between a normal password
// and a password handle.
//
// Arguments: szPassword - password in clear text.
//
// Returns: TRUE - if everything succeeded
// FALSE - if something failed
//
//+----------------------------------------------------------------------------
BOOL CSecurePassword::SetPassword(IN LPWSTR pszPassword)
{
BOOL fRetCode = FALSE;
DWORD dwRetCode = ERROR_SUCCESS;
DWORD dwPwLen = 0;
//
// OS_NT5 expands to a few function calls, so just cache the result and reuse it below
//
BOOL fIsNT5OrAbove = OS_NT5;
//
// If there is an allocated blob then free it first so we don't leak memory.
//
this->ClearMemberVars();
m_fIsEmptyString = ((NULL == pszPassword) || (TEXT('\0') == pszPassword[0]));
if (m_fIsEmptyString)
{
//
// No need to continue, since password can be NULL the code below that compares
// it to a handle (16 *s) would be dereferencing a NULL
//
m_fIsHandleToPassword = FALSE;
return TRUE;
}
//
// Check whether this is a handle to a password (****************)
//
m_fIsHandleToPassword = (fIsNT5OrAbove && (0 == lstrcmpW(c_pszSavedPasswordToken, pszPassword)));
//
// If the internal flag is set, there is no need to encrypt or decrypt this string.
//
if (m_fIsHandleToPassword)
{
return TRUE;
}
//
// Make sure the password that is being encrypted is shorter than the allowed maximum
//
dwPwLen = lstrlenU(pszPassword);
if (m_dwMaxDataLen < dwPwLen)
{
return FALSE;
}
if (fIsNT5OrAbove)
{
m_pEncryptedPW = (DATA_BLOB*)CmMalloc(sizeof(DATA_BLOB));
if (m_pEncryptedPW)
{
dwRetCode = this->EncodePassword((dwPwLen + 1) * sizeof(WCHAR), (PBYTE)pszPassword, m_pEncryptedPW);
if (ERROR_SUCCESS == dwRetCode)
{
fRetCode = TRUE;
}
else
{
//
// Free the allocated DATA_BLOB so that decryption doesn't cause issue in case caller
// ends up calling it. And reset internal flags.
//
this->ClearMemberVars();
m_fIsEmptyString = TRUE;
m_fIsHandleToPassword = FALSE;
CMTRACE1(TEXT("CSecurePassword::SetPassword - this->EncodePassword failed. 0x%x"), dwRetCode);
}
}
}
else
{
//
// Downlevel (Win9x, NT4) we don't support encryption
//
lstrcpynU(m_tszPassword, pszPassword, CELEMS(m_tszPassword));
CmEncodePassword(m_tszPassword);
fRetCode = TRUE;
}
MYDBGASSERT(fRetCode);
return fRetCode;
}
//+----------------------------------------------------------------------------
//
// Function: GetPasswordWithAlloc
//
// Synopsis: Allocates a buffer and copies the clear-text password into it.
// Based on the OS it decrypts or decodes it since it's not stored
// in clear. If the internal password is an empty string we allocate
// an empty string buffer. This is done for consistency since the caller
// needs to call our free method so memory isn't leaked. If we are storing
// a RAS password handle (consists of 16 '*') we actually didn't store it,
// but only set our internal flag. In this case we need to allocate a buffer
// with 16 * and return it. On downlevel platforms we don't use expensive
// decryption calls, thus the logic doesn't distinguish between a
// normal password and a password handle.
//
// Arguments: pszClearPw - holds a pointer to a buffer that was allocated by this
// class.
// pcbClearPw - hold the size of the allocated buffer in bytes
//
// Returns: TRUE - if everything succeeded
// FALSE - if something failed
//
//+----------------------------------------------------------------------------
BOOL CSecurePassword::GetPasswordWithAlloc(OUT LPWSTR* pszClearPw, OUT DWORD* pcbClearPw)
{
BOOL fRetCode = FALSE;
DWORD dwRetCode = ERROR_SUCCESS;
DWORD cbData = 0;
PBYTE pbData = NULL;
if ((NULL == pszClearPw) || (NULL == pcbClearPw))
{
MYDBGASSERT(FALSE);
return FALSE;
}
*pszClearPw = NULL;
*pcbClearPw = 0;
if (OS_NT5)
{
if (m_fIsEmptyString)
{
//
// In case there is nothing saved in this class, just allocate an empty string
// and return it back. This at least doesn't have to decrypt and empty string.
//
DWORD cbLen = sizeof(WCHAR);
LPWSTR szTemp = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, cbLen);
if (szTemp)
{
*pszClearPw = szTemp;
*pcbClearPw = cbLen;
fRetCode = TRUE;
m_iAllocAndFreeCounter++;
}
}
else
{
//
// Check if this instance is just a handle to a RAS password (16 *)
// If so, then just allocate that string and return it to the caller,
// otherwise proceed normally and decrypt our blob.
//
if (m_fIsHandleToPassword)
{
size_t nLen = lstrlenW(c_pszSavedPasswordToken) + 1;
DWORD cbLen = nLen * sizeof(WCHAR);
LPWSTR szTemp = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, cbLen);
if (szTemp)
{
lstrcpynW(szTemp, c_pszSavedPasswordToken, nLen);
*pszClearPw = szTemp;
*pcbClearPw = cbLen;
fRetCode = TRUE;
m_iAllocAndFreeCounter++;
}
}
else
{
if (m_pEncryptedPW)
{
dwRetCode = this->DecodePassword(m_pEncryptedPW, &cbData, &pbData);
if ((NO_ERROR == dwRetCode) && pbData && cbData)
{
*pszClearPw = (LPWSTR)pbData;
*pcbClearPw = cbData;
fRetCode = TRUE;
m_iAllocAndFreeCounter++;
}
}
}
}
}
else
{
//
// Downlevel (Win9x, NT4) doesn't support 16 *
//
size_t nLen = lstrlenU(m_tszPassword) + 1;
LPTSTR pszBuffer = (LPWSTR)CmMalloc(nLen * sizeof(TCHAR));
if (pszBuffer)
{
//
// Copy our encoded buffer to the newly allocated buffer
// We can do this because d/encoding is done in place
//
lstrcpynU(pszBuffer, m_tszPassword, nLen);
//
// Decode the outgoing buffer
//
CmDecodePassword(pszBuffer);
*pszClearPw = (LPWSTR)pszBuffer;
*pcbClearPw = nLen * sizeof(TCHAR);
fRetCode = TRUE;
m_iAllocAndFreeCounter++;
}
}
MYDBGASSERT(fRetCode);
return fRetCode;
}
//+----------------------------------------------------------------------------
//
// Function: ClearAndFree
//
// Synopsis: Clear then free a buffer that was allocated by this class. Notice that
// on downlevel platforms the way a buffer is freed differs. That
// is because encrypting and decrypting needs us to free it
// using LocalFree. For downlevel platforms we chose CM's standard
// way of allocating memory (CmMalloc) and it now needs to be
// freed using CmFree.
//
// Arguments: pszClearPw - holds a pointer to a buffer that was allocated by this
// class.
// cbClearPw - size of the allocated buffer in bytes
//
// Returns: TRUE - if everything succeeded
// FALSE - if something failed
//
//+----------------------------------------------------------------------------
VOID CSecurePassword::ClearAndFree(IN OUT LPWSTR* pszClearPw, IN DWORD cbClearPw)
{
if ((NULL == pszClearPw) || (0 == cbClearPw))
{
return;
}
if (NULL == *pszClearPw)
{
return;
}
CmSecureZeroMemory(*pszClearPw, cbClearPw);
if (OS_NT5)
{
//
// Uses LocalFree because CryptProtectData requires this way
// to free its memory
//
LocalFree(*pszClearPw);
}
else
{
//
// We used CmMalloc to allocate so we need to call CmFree
//
CmFree(*pszClearPw);
}
*pszClearPw = NULL;
m_iAllocAndFreeCounter--;
return;
}
//+----------------------------------------------------------------------------
//
// Function: ClearMemberVars
//
// Synopsis: Clears our member variables. Notice that we only clear the
// passwords & member variables. This doesn't mean that m_fIsEmptyString
// should be set. This needs to be a private method
// because it doesn't reset the empty or password handle flags. Thus
// outside callers should NOT use this, because it would create an invalid
// state.
//
// Arguments: none
//
// Returns: none
//
//+----------------------------------------------------------------------------
VOID CSecurePassword::ClearMemberVars()
{
if (OS_NT5)
{
if (m_pEncryptedPW)
{
this->FreePassword(m_pEncryptedPW);
CmFree(m_pEncryptedPW);
m_pEncryptedPW = NULL;
}
}
else
{
//
// Zero out the password buffer
//
CmSecureZeroMemory((PVOID)m_tszPassword, sizeof(m_tszPassword));
}
}
//+----------------------------------------------------------------------------
//
// Function: UnInit
//
// Synopsis: Unloads DLL, clear and frees memory.
//
// Arguments: none
//
// Returns: none
//
//+----------------------------------------------------------------------------
VOID CSecurePassword::UnInit()
{
this->UnloadCrypt32();
this->ClearMemberVars();
m_fIsHandleToPassword = FALSE;
m_fIsEmptyString = FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: UnloadCrypt32
//
// Synopsis: Unloads DLL
//
// Arguments: none
//
// Returns: none
//
//+----------------------------------------------------------------------------
VOID CSecurePassword::UnloadCrypt32()
{
fnCryptProtectData = NULL;
fnCryptUnprotectData = NULL;
m_dllCrypt32.Unload();
m_fIsLibAndFuncPtrsAvail = FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: EncodePassword
//
// Synopsis: Encrypts data using CryptProtectData
//
// Arguments: cbPassword - size of buffer in bytes
// pbPassword - pointer to a buffer to encrypt
// pDataBlobPassword - pointer to an allocated DATA_BLOB structure
//
// Returns: none
//
//+----------------------------------------------------------------------------
DWORD CSecurePassword::EncodePassword(IN DWORD cbPassword,
IN PBYTE pbPassword,
OUT DATA_BLOB* pDataBlobPassword)
{
DWORD dwErr = NO_ERROR;
DATA_BLOB DataBlobIn;
if(NULL == pDataBlobPassword)
{
dwErr = E_INVALIDARG;
CMTRACE(TEXT("CSecurePassword::EncodePassword - NULL == pDataBlobPassword"));
goto done;
}
if( (0 == cbPassword)
|| (NULL == pbPassword))
{
//
// nothing to encrypt.
//
dwErr = E_INVALIDARG;
CMTRACE(TEXT("CSecurePassword::EncodePassword - E_INVALIDARG"));
goto done;
}
//
// If Crypt32.DLL is not loaded, try to loaded and get the
// function pointers.
//
if (FALSE == m_fIsLibAndFuncPtrsAvail)
{
if (FALSE == this->LoadCrypt32AndGetFuncPtrs())
{
//
// This failed, thus we can't continue. We should free memory.
//
this->ClearMemberVars();
m_fIsEmptyString = TRUE;
m_fIsHandleToPassword = FALSE;
dwErr = ERROR_DLL_INIT_FAILED;
CMTRACE(TEXT("CSecurePassword::EncodePassword - this-> LoadCrypt32AndGetFuncPtrs failed."));
goto done;
}
}
ZeroMemory(pDataBlobPassword, sizeof(DATA_BLOB));
DataBlobIn.cbData = cbPassword;
DataBlobIn.pbData = pbPassword;
if (fnCryptProtectData)
{
LPCWSTR wszDesc[] = {TEXT("Readable description of data.")};
LPWSTR pszDesc = NULL;
if (OS_W2K)
{
//
// The crypto API needs this, but only on Win2K
//
pszDesc = (LPWSTR)wszDesc;
}
if(!fnCryptProtectData(
&DataBlobIn,
(LPCWSTR)pszDesc,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN,
pDataBlobPassword))
{
dwErr = GetLastError();
CMTRACE1(TEXT("CSecurePassword::EncodePassword - fnCryptProtectData failed. 0x%x"), dwErr);
goto done;
}
}
else
{
CMTRACE(TEXT("CSecurePassword::EncodePassword - ERROR_FUNCTION_NOT_CALLED"));
dwErr = ERROR_FUNCTION_NOT_CALLED;
}
done:
MYDBGASSERT(NO_ERROR == dwErr);
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Function: DecodePassword
//
// Synopsis: Decrypts data using CryptUnprotectData
//
// Arguments: pDataBlobPassword - pointer to a DATA_BLOB structure to be decrypted
// cbPassword - pointer that holds the size of buffer in bytes
// pbPassword - pointer to a buffer to encrypt
//
//
// Returns: none
//
//+----------------------------------------------------------------------------
DWORD CSecurePassword::DecodePassword(IN DATA_BLOB* pDataBlobPassword,
OUT DWORD* pcbPassword,
OUT PBYTE* ppbPassword)
{
DWORD dwErr = NO_ERROR;
DATA_BLOB DataOut;
if( (NULL == pDataBlobPassword)
|| (NULL == pcbPassword)
|| (NULL == ppbPassword))
{
dwErr = E_INVALIDARG;
goto done;
}
*pcbPassword = 0;
*ppbPassword = NULL;
if( (NULL == pDataBlobPassword->pbData)
|| (0 == pDataBlobPassword->cbData))
{
//
// nothing to decrypt. Just return success.
//
goto done;
}
//
// If Crypt32.DLL is not loaded, try to loaded and get the
// function pointers.
//
if (FALSE == m_fIsLibAndFuncPtrsAvail)
{
if (FALSE == this->LoadCrypt32AndGetFuncPtrs())
{
//
// This failed, thus we can't continue. We should free memory.
//
this->ClearMemberVars();
m_fIsEmptyString = TRUE;
m_fIsHandleToPassword = FALSE;
dwErr = ERROR_DLL_INIT_FAILED;
goto done;
}
}
ZeroMemory(&DataOut, sizeof(DATA_BLOB));
if (fnCryptUnprotectData)
{
if(!fnCryptUnprotectData(
pDataBlobPassword,
NULL,
NULL,
NULL,
NULL,
CRYPTPROTECT_UI_FORBIDDEN,
&DataOut))
{
dwErr = GetLastError();
goto done;
}
dwErr = NO_ERROR;
*pcbPassword = DataOut.cbData;
*ppbPassword = DataOut.pbData;
}
else
{
dwErr = ERROR_FUNCTION_NOT_CALLED;
}
done:
MYDBGASSERT(NO_ERROR == dwErr);
return dwErr;
}
//+----------------------------------------------------------------------------
//
// Function: FreePassword
//
// Synopsis: Frees data in DATA_BLOB structure
//
// Arguments: pDBPassword - pointer to a DATA_BLOB structure
//
// Returns: none
//
//+----------------------------------------------------------------------------
VOID CSecurePassword::FreePassword(IN DATA_BLOB *pDBPassword)
{
if(NULL == pDBPassword)
{
return;
}
if(NULL != pDBPassword->pbData)
{
CmSecureZeroMemory(pDBPassword->pbData, pDBPassword->cbData);
LocalFree(pDBPassword->pbData);
}
//
// Clear sensitive data.
//
CmSecureZeroMemory(pDBPassword, sizeof(DATA_BLOB));
}
//+----------------------------------------------------------------------------
//
// Function: LoadCrypt32AndGetFuncPtrs
//
// Synopsis: Loads crypt32.dll and gets function pointer to needed methods
//
// Arguments: none
//
// Returns: TRUE - if .DLL was loaded and function pointers were retrieved
// FALSE - when an error was encountered
//
//+----------------------------------------------------------------------------
BOOL CSecurePassword::LoadCrypt32AndGetFuncPtrs()
{
BOOL fRetVal = FALSE;
if (OS_NT5)
{
if (FALSE == m_fIsLibAndFuncPtrsAvail)
{
fRetVal = m_dllCrypt32.Load(TEXT("crypt32.dll"));
if (fRetVal)
{
fnCryptProtectData = (fnCryptProtectDataFunc)m_dllCrypt32.GetProcAddress("CryptProtectData");
fnCryptUnprotectData = (fnCryptUnprotectDataFunc)m_dllCrypt32.GetProcAddress("CryptUnprotectData");
if (fnCryptProtectData && fnCryptUnprotectData)
{
CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - success"));
m_fIsLibAndFuncPtrsAvail = TRUE;
fRetVal = TRUE;
}
else
{
CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - missing function pointers"));
this->UnloadCrypt32();
}
}
else
{
CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - m_dllCrypt32.Load failed"));
}
}
else
{
fRetVal = m_fIsLibAndFuncPtrsAvail;
}
}
MYDBGASSERT(fRetVal);
return fRetVal;
}
//+----------------------------------------------------------------------------
//
// Function: IsEmptyString
//
// Synopsis: Used as a shortcut so we don't have to encrypt/decrypt in case
// we stored an empty string.
//
// Arguments: none
//
// Returns: TRUE - if instance is suppose to be holding an empty string
// FALSE - if currenttly saved string is not empty
//
//+----------------------------------------------------------------------------
BOOL CSecurePassword::IsEmptyString()
{
return m_fIsEmptyString;
}
//+----------------------------------------------------------------------------
//
// Function: IsHandleToPassword
//
// Synopsis: Used as a shortcut so we don't have to encrypt/decrypt in case
// we stored a handle to a RAS password (16 *).
//
// Arguments: none
//
// Returns: TRUE - if instance is suppose to be holding ****************
// FALSE - if currenttly saved string is a normal password
//
//+----------------------------------------------------------------------------
BOOL CSecurePassword::IsHandleToPassword()
{
return m_fIsHandleToPassword;
}
//+----------------------------------------------------------------------------
//
// Function: SetMaxDataLenToProtect
//
// Synopsis: Set the maximum length password to protect. This value will be
// checked when encrypting a password.
//
// Arguments: dwMaxDataLen - maximum password length in characters
//
// Returns: Nothing
//
//+----------------------------------------------------------------------------
VOID CSecurePassword::SetMaxDataLenToProtect(DWORD dwMaxDataLen)
{
m_dwMaxDataLen = dwMaxDataLen;
}
//+----------------------------------------------------------------------------
//
// Function: GetMaxDataLenToProtect
//
// Synopsis: Get the maximum length password that this class can protect.
//
// Arguments: none
//
// Returns: DWORD - maximum password length
//
//+----------------------------------------------------------------------------
DWORD CSecurePassword::GetMaxDataLenToProtect()
{
return m_dwMaxDataLen;
}
#endif // _ICM_INC