|
|
//+----------------------------------------------------------------------------
//
// File: userinfo.cpp
//
// Module: CMDIAL32.DLL
//
// Synopsis: This module contains the code that handles getting/saving user info.
//
// Copyright (c) 1996-1999 Microsoft Corporation
//
// Author: henryt created 02/??/98
// quintinb created Header 08/16/99
//
//+----------------------------------------------------------------------------
#include "cmmaster.h"
#include "cmuufns.h"
#include "pwd_str.h"
#include "userinfo_str.h"
#include "conact_str.h"
///////////////////////////////////////////////////////////////////////////////////
// define's
///////////////////////////////////////////////////////////////////////////////////
//
// CM_MAX_PWD - Maximum possible size of password dataencrypted or otherwise.
// Includes inbound buffer size + room for encryption expansion.
//
const DWORD CM_MAX_PWD = PWLEN * 3; // 2.73 would be enough
//
// Define this if you want to test userinfo upgrade! You should also delete the key
// HKEY_CURRENT_USER\Software\Microsoft\Connection Manager\UserInfo\<Service Name>
//
//#define TEST_USERINFO_UPGRADE 1
#define CACHE_KEY_LEN 80 // Don't change unless you've read every comment regarding it
//
// Suffix for CacheEntry name used on Legacy and W9x. Note: the space is not a typo
const TCHAR* const c_pszCacheEntryNameSuffix = TEXT(" (Connection Manager)");
///////////////////////////////////////////////////////////////////////////////////
// typedef's
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
// func prototypes
///////////////////////////////////////////////////////////////////////////////////
////////////////
BOOL WriteDataToReg( LPCTSTR pszKey, UINT uiDataID, DWORD dwType, CONST BYTE *lpData, DWORD cbData, BOOL fAllUser);
BOOL ReadDataFromReg( LPCTSTR pszKey, UINT uiDataID, LPDWORD lpdwType, BYTE *lpData, LPDWORD lpcbData, BOOL fAllUser);
LPBYTE GetDataFromReg( LPCTSTR pszKey, UINT uiDataID, DWORD dwType, DWORD dwSize, BOOL fAllUser);
BOOL DeleteDataFromReg( LPCTSTR pszKey, UINT uiDataID, BOOL fAllUser);
BOOL DeleteUserInfoFromReg( ArgsStruct *pArgs, UINT uiEntry);
BOOL ReadPasswordFromCmp( ArgsStruct *pArgs, UINT uiEntry, LPTSTR *ppszPassword);
LPCTSTR TranslateUserDataID( UINT uiDataID);
BOOL ReadUserInfoFromCmp( ArgsStruct *pArgs, UINT uiEntry, PVOID *ppvData);
BOOL DeleteUserInfoFromCmp( ArgsStruct *pArgs, UINT uiEntry);
DWORD RasSetCredsWrapper( ArgsStruct *pArgs, LPCTSTR pszPhoneBook, DWORD dwMask, LPCTSTR pszData);
int WriteUserInfoToRas( ArgsStruct *pArgs, UINT uiDataID, PVOID pvData);
int DeleteUserInfoFromRas( ArgsStruct *pArgs, UINT uiEntry);
DWORD RasGetCredsWrapper( ArgsStruct *pArgs, LPCTSTR pszPhoneBook, DWORD dwMask, PVOID *ppvData);
BOOL ReadUserInfoFromRas( ArgsStruct *pArgs, UINT uiEntry, PVOID *ppvData);
///////////////
BOOL ReadStringFromCache( ArgsStruct *pArgs, LPTSTR pszEntryName, LPTSTR *ppszStr );
BOOL DeleteStringFromCache( ArgsStruct *pArgs, LPTSTR pszEntryName );
LPTSTR GetLegacyKeyName(ArgsStruct *pArgs);
LPTSTR EncryptPassword( ArgsStruct *pArgs, LPCTSTR pszPassword, LPDWORD lpdwBufSize, LPDWORD lpdwCryptType, BOOL fReg, LPSTR pszSubKey);
LPBYTE DecryptPassword( ArgsStruct *pArgs, LPBYTE pszEncryptedData, DWORD dwEncryptionType, DWORD dwEncryptedBytes, BOOL /*fReg*/, LPSTR pszSubKey);
LPTSTR BuildUserInfoSubKey( LPCTSTR pszServiceKey, BOOL fAllUser);
///////////////////////////////////////////////////////////////////////////////////
// Implementation
///////////////////////////////////////////////////////////////////////////////////
#ifdef TEST_USERINFO_UPGRADE
//+---------------------------------------------------------------------------
//
// Function: WriteStringToCache
//
// Synopsis: Write a null terminated password string to cache.
//
// Arguments: pArgs ptr to ArgsStruct
// pszEntryName name to identify the cache entry
// pszStr the string
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL WriteStringToCache( ArgsStruct *pArgs, LPTSTR pszEntryName, LPTSTR pszStr) { MYDBGASSERT(pArgs); MYDBGASSERT(pszEntryName && *pszEntryName); MYDBGASSERT(pszStr && *pszStr); DWORD dwRes = ERROR_SUCCESS;
//
// In the legacy case, we use mpr.dll for caching user data on W9x.
// On NT we use the Local Security Authority (LSA)
//
if (OS_NT) { if (InitLsa(pArgs)) { if (!(*ppszStr = (LPTSTR)CmMalloc(dwBufSize))) { return FALSE; } dwRes = LSA_WriteString(pArgs, pszEntryName, pszStr); DeInitLsa(pArgs); } else { dwRes = GetLastError(); } } else { //
// for Windows95
//
HINSTANCE hInst = NULL; WORD (WINAPI *pfnFunc)(LPSTR,WORD,LPSTR,WORD,BYTE,UINT) = NULL; //
// Load MPR for system password cache support
//
MYVERIFY(hInst = LoadLibraryExA("mpr.dll", NULL, 0)); if (hInst) { //
// Get function ptr for WNetCachePassword API and cache the password
//
MYVERIFY(pfnFunc = (WORD (WINAPI *)(LPSTR,WORD,LPSTR,WORD,BYTE,UINT)) GetProcAddress(hInst, "WNetCachePassword")); if (pfnFunc) { //
// Convert the EntryName and Password Strings to Ansi
//
LPSTR pszAnsiEntryName = WzToSzWithAlloc(pszEntryName); LPSTR pszAnsiStr = WzToSzWithAlloc(pszStr);
if (pszAnsiStr && pszAnsiEntryName) { //
// Store the password
//
dwRes = pfnFunc(pszAnsiEntryName, (WORD)lstrlenA(pszAnsiEntryName), pszAnsiStr, (WORD)lstrlenA(pszAnsiStr), CACHE_KEY_LEN, 0); } else { dwRes = ERROR_NOT_ENOUGH_MEMORY; }
CmFree(pszAnsiStr); CmFree(pszAnsiEntryName); } else { dwRes = GetLastError(); }
FreeLibrary(hInst); } else { dwRes = GetLastError(); } }
#ifdef DEBUG
if (dwRes) { CMTRACE1(TEXT("WriteStringToCache() failed, err=%u."), dwRes); } #endif
return (ERROR_SUCCESS == dwRes); }
#endif //TEST_USERINFO_UPGRADE
//+----------------------------------------------------------------------------
//
// Function: BuildUserInfoSubKey
//
// Synopsis: Constructs the appropriate subkey for UserInfo based on the service
// name key and the user mode of the profile.
//
// Arguments: LPCTSTR pszServiceKey - The service name key
// BOOL fAllUser - Flag indicating that profile is All-User
//
// Returns: LPTSTR - Ptr to allocated buffer containing subkey or NULL on failure.
//
// History: nickball Created 8/14/98
//
//+----------------------------------------------------------------------------
LPTSTR BuildUserInfoSubKey(LPCTSTR pszServiceKey, BOOL fAllUser) { MYDBGASSERT(pszServiceKey);
if (NULL == pszServiceKey) { return NULL; }
//
// Use the appropriate base key
//
LPTSTR pszSubKey = NULL;
if (fAllUser) { pszSubKey = CmStrCpyAlloc(c_pszRegCmUserInfo); } else { pszSubKey = CmStrCpyAlloc(c_pszRegCmSingleUserInfo); }
MYDBGASSERT(pszSubKey);
//
// Append profile service name
//
if (pszSubKey && *pszSubKey) { pszSubKey = CmStrCatAlloc(&pszSubKey, pszServiceKey); MYDBGASSERT(pszSubKey);
return pszSubKey; }
CmFree(pszSubKey);
return NULL; }
//+----------------------------------------------------------------------------
//
// Function: BuildICSDataInfoSubKey
//
// Synopsis: Constructs the appropriate subkey for ICS UserInfo based on the service
// name key.
//
// Arguments: LPCTSTR pszServiceKey - The service name key
//
// Returns: LPTSTR - Ptr to allocated buffer containing subkey or NULL on failure.
//
// History: 03/30/2001 tomkel Created
//
//+----------------------------------------------------------------------------
LPTSTR BuildICSDataInfoSubKey(LPCTSTR pszServiceKey) { MYDBGASSERT(pszServiceKey);
if (NULL == pszServiceKey) { return NULL; }
//
// Use the appropriate base key
//
LPTSTR pszSubKey = NULL;
pszSubKey = CmStrCpyAlloc(c_pszRegCmRoot);
MYDBGASSERT(pszSubKey);
//
// Append profile service name
//
if (pszSubKey && *pszSubKey) { pszSubKey = CmStrCatAlloc(&pszSubKey, pszServiceKey); MYDBGASSERT(pszSubKey);
if (pszSubKey) { CmStrCatAlloc(&pszSubKey, TEXT("\\")); if (pszSubKey) { CmStrCatAlloc(&pszSubKey, c_pszCmRegKeyICSDataKey); } }
return pszSubKey; }
CmFree(pszSubKey);
return NULL; }
//+----------------------------------------------------------------------------
//
// Function: dwGetWNetCachedPassword
//
// Synopsis: Wrapper to encapsulate linking to MPR.DLL and calling GetWNetCac
// hedPassword.
//
// Arguments: LPSTR pszEntryName - The names of the key used to identify the password.
// LPSTR* ppszStr - The buffer to receive the retrieved password.
// WORD* pwSizeOfStr - The size of the input buffer. Also receives
// of the # of chars retrieved.
//
// Returns: DWORD - Windows error code.
//
// History: nickball Created Header 6/17/99
//
//+----------------------------------------------------------------------------
DWORD dwGetWNetCachedPassword(LPSTR pszEntryName, LPSTR* ppszStr, WORD* pwSizeOfStr) { MYDBGASSERT(OS_W9X);
DWORD dwRes = ERROR_SUCCESS; WORD (WINAPI *pfnFunc)(LPSTR,WORD,LPSTR,LPWORD,BYTE) = NULL; HINSTANCE hInst = NULL;
//
// Load MPR for system password cache support
//
MYVERIFY(hInst = LoadLibraryExA("mpr.dll", NULL, 0)); if (hInst) { //
// Get function ptr for WNetGetCachedPassword API and retrieve the string
//
MYVERIFY(pfnFunc = (WORD (WINAPI *)(LPSTR,WORD,LPSTR,LPWORD,BYTE)) GetProcAddress(hInst, "WNetGetCachedPassword"));
//
// Read the cache data
//
if (pfnFunc) { //
// NOTE: Final param must be CACHE_KEY_LEN (80), no docs to indicate
// exact usage of API but retrieval is tied to the value used when
// storing the pwd. Thus we hard code to CACHE_KEY_LEN because this
// is the value that was used by the original version that stored
// the password in the 9X cache. The receiving buffer size is
// retained at 256 to minimize delta from latest shipping version.
//
// NT# 355459 - nickball - 6/17/99
//
dwRes = pfnFunc(pszEntryName, (WORD)lstrlenA(pszEntryName), *ppszStr, pwSizeOfStr, CACHE_KEY_LEN); } else { dwRes = GetLastError(); } } else { dwRes = GetLastError(); }
if (NULL != hInst) { FreeLibrary(hInst); }
return (dwRes); }
//+---------------------------------------------------------------------------
//
// Function: ReadStringFromCache
//
// Synopsis: Read a null terminated string from cache.
//
// Arguments: pArgs ptr to ArgsStruct
// pszEntryName name to identify the cache entry
// ppszStr ptr to the ptr of the buffer.
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL ReadStringFromCache( ArgsStruct *pArgs, LPTSTR pszEntryName, LPTSTR *ppszStr ) { DWORD dwRes = ERROR_SUCCESS; //
// Alloc buffer - the buffer is uuencoded. See UserInfoToString().
//
WORD wBufSize = 256; // arbitrary, we used to use 80 on W95
//
// On NT, we use the Local Security Authority (LSA) services for reading
// the string in the legacy case. On Win9x, we uses mpr.dll.
// Note: wBufSize is used as an in\out param, can be modified below.
//
if (OS_NT) { if (InitLsa(pArgs)) { if (!(*ppszStr = (LPTSTR)CmMalloc(wBufSize))) { return FALSE; }
dwRes = LSA_ReadString(pArgs, pszEntryName, *ppszStr, wBufSize); DeInitLsa(pArgs); } else { dwRes = GetLastError(); } } else { //
// for Windows95
//
LPSTR pszAnsiStr = (LPSTR)CmMalloc(wBufSize); LPSTR pszAnsiEntryName = WzToSzWithAlloc(pszEntryName); if (pszAnsiStr && pszAnsiEntryName) { dwRes = dwGetWNetCachedPassword(pszAnsiEntryName, &pszAnsiStr, &wBufSize);
if (ERROR_SUCCESS == dwRes) { *ppszStr = SzToWzWithAlloc(pszAnsiStr); if (NULL == *ppszStr) { dwRes = ERROR_NOT_ENOUGH_MEMORY; } } }
CmFree (pszAnsiStr); CmFree (pszAnsiEntryName); }
if (dwRes) { CmFree(*ppszStr); *ppszStr = NULL; CMTRACE1(TEXT("ReadStringFromCache() failed, err=%u."), dwRes); }
return (ERROR_SUCCESS == dwRes); }
//+---------------------------------------------------------------------------
//
// Function: DeleteStringFromCache
//
// Synopsis: Delete the string from cache.
//
// Arguments: pArgs ptr to ArgsStruct
// pszEntryName name to identify the cache entry
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL DeleteStringFromCache( ArgsStruct *pArgs, LPTSTR pszEntryName ) { DWORD dwRes;
//
// on NT, we use the Local Security Authority (LSA) services for storing
// the string. On Win95, we use mpr.dll.
//
if (OS_NT) { if (InitLsa(pArgs)) { dwRes = LSA_WriteString(pArgs, pszEntryName, NULL); DeInitLsa(pArgs); } else { dwRes = GetLastError(); } } else { //
// for Windows95
//
HINSTANCE hInst = NULL; WORD (WINAPI *pfnFunc)(LPSTR,WORD,BYTE) = NULL;
// Load MPR for system password cache support
MYVERIFY(hInst = LoadLibraryExA("mpr.dll", NULL, 0)); // Get function ptr for WNetRemoveCachedPassword API and remove the string
if (!hInst) { return FALSE; }
MYVERIFY(pfnFunc = (WORD (WINAPI *)(LPSTR,WORD,BYTE)) GetProcAddress(hInst, "WNetRemoveCachedPassword"));
if (!pfnFunc) { FreeLibrary(hInst); return FALSE; } LPSTR pszAnsiEntryName = WzToSzWithAlloc(pszEntryName); if (pszAnsiEntryName) { dwRes = pfnFunc(pszAnsiEntryName, (WORD)lstrlenA(pszAnsiEntryName), CACHE_KEY_LEN); } else { dwRes = ERROR_NOT_ENOUGH_MEMORY; }
CmFree (pszAnsiEntryName);
FreeLibrary(hInst); }
#ifdef DEBUG
if (dwRes) { CMTRACE1(TEXT("DeleteStringFromCache() LSA_WriteString/WNetRemoveCachedPassword() failed, err=%u."), dwRes); } #endif
return (ERROR_SUCCESS == dwRes); }
//+---------------------------------------------------------------------------
//
// Function: RasSetCredsWrapper
//
// Synopsis: Wrapper to call RasSetCredential. This function stores the
// given string in the appropriate field of a RASCREDENTIALS struct
// (based on the value in dwMask) and calls RasSetCredentials.
//
//
// Arguments: pArgs ptr to ArgsStruct
// pszPhoneBook Full path to the phonebook file, or NULL for
// the default all user pbk
// dwMask dwMask value to set in the RASCREDENTIALS
// struct. Currently must be one of RASCM_UserName,
// RASCM_Domain, or RASCM_Password.
// pszData string data to set
//
// Returns: DWORD ERROR_SUCCESS if successful, a windows error code otherwise
//
//----------------------------------------------------------------------------
DWORD RasSetCredsWrapper( ArgsStruct *pArgs, LPCTSTR pszPhoneBook, DWORD dwMask, LPCTSTR pszData ) { DWORD dwRet = ERROR_INVALID_PARAMETER; BOOL fSavePassword = TRUE;
MYDBGASSERT(pArgs && pArgs->rlsRasLink.pfnSetCredentials); MYDBGASSERT(pszData); MYDBGASSERT((RASCM_UserName == dwMask) || (RASCM_Domain == dwMask) || (RASCM_Password == dwMask));
if (pArgs && pszData && pArgs->rlsRasLink.pfnSetCredentials) { LPTSTR pszConnectoid = GetRasConnectoidName(pArgs, pArgs->piniService, FALSE);
if (pszConnectoid) { RASCREDENTIALS RasCredentials = {0}; RasCredentials.dwSize = sizeof(RasCredentials); if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { RasCredentials.dwMask = dwMask | RASCM_DefaultCreds; } else { RasCredentials.dwMask = dwMask; } BOOL bClearPassword = FALSE;
if (RASCM_UserName == dwMask) { lstrcpyU(RasCredentials.szUserName, pszData); } else if (RASCM_Domain == dwMask) { lstrcpyU(RasCredentials.szDomain, pszData); } else if (RASCM_Password == dwMask) { if (0 == lstrcmpU(c_pszSavedPasswordToken, pszData)) { //
// We have 16 *'s. This password is from the RAS cred store,
// so we don't want to save the 16 *'s
//
fSavePassword = FALSE; dwRet = ERROR_SUCCESS; } else { lstrcpyU(RasCredentials.szPassword, pszData); bClearPassword = (TEXT('\0') == pszData[0]); } } else { CmFree(pszConnectoid); return ERROR_INVALID_PARAMETER; }
if (fSavePassword) { dwRet = pArgs->rlsRasLink.pfnSetCredentials(pszPhoneBook, pszConnectoid, &RasCredentials, bClearPassword);
if (ERROR_CANNOT_FIND_PHONEBOOK_ENTRY == dwRet) { //
// Then the phonebook entry doesn't exist yet, lets create it.
//
LPRASENTRY pRasEntry = (LPRASENTRY)CmMalloc(sizeof(RASENTRY));
if (pRasEntry && pArgs->rlsRasLink.pfnSetEntryProperties) { pRasEntry->dwSize = sizeof(RASENTRY); dwRet = pArgs->rlsRasLink.pfnSetEntryProperties(pszPhoneBook, pszConnectoid, pRasEntry, pRasEntry->dwSize, NULL, 0);
//
// Lets try to set the credentials one more time ...
//
if (ERROR_SUCCESS == dwRet) { dwRet = pArgs->rlsRasLink.pfnSetCredentials(pszPhoneBook, pszConnectoid, &RasCredentials, bClearPassword); }
CmFree(pRasEntry); } } } CmWipePassword(RasCredentials.szPassword); CmFree(pszConnectoid); } }
return dwRet; }
//+---------------------------------------------------------------------------
//
// Function: WriteUserInfoToRas
//
// Synopsis: Write a userinfo data to ras credential storage
//
// Arguments: pArgs ptr to ArgsStruct
// uiDataID the resource ID associated with the data
// pvData userinfo data
//
// Returns: int TRUE = success, FALSE = failure, returns -1 if RAS
// doesn't cache this piece of data and it should be put
// in the registry instead.
//
//----------------------------------------------------------------------------
int WriteUserInfoToRas( ArgsStruct *pArgs, UINT uiDataID, PVOID pvData) { int iReturn = -1;
if (OS_NT5 && pArgs && pArgs->bUseRasCredStore) { DWORD dwMask; LPTSTR pszPhoneBook = NULL;
switch (uiDataID) { case UD_ID_USERNAME: dwMask = RASCM_UserName; iReturn = (ERROR_SUCCESS == RasSetCredsWrapper(pArgs, pArgs->pszRasPbk, dwMask, (LPCTSTR)pvData)); break;
case UD_ID_PASSWORD: dwMask = RASCM_Password; iReturn = (ERROR_SUCCESS == RasSetCredsWrapper(pArgs, pArgs->pszRasPbk, dwMask, (LPCTSTR)pvData)); MYDBGASSERT(iReturn);
//
// Note that if we are using the same username then we want to write the password to both the
// password and the InetPassword storage. This is because we don't actually have a password, just
// 16 *'s. This tells RAS to look in its internal store for the password. The trouble is that if
// we don't cache the real password when we hand RAS the 16 *'s, it looks and finds a NULL password.
// Thus we keep both passwords the same and this avoids that problem.
//
if (pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryUseSameUserName)) { pszPhoneBook = CreateRasPrivatePbk(pArgs);
if (pszPhoneBook) { iReturn = (ERROR_SUCCESS == RasSetCredsWrapper(pArgs, pszPhoneBook, dwMask, (LPCTSTR)pvData)); CmFree(pszPhoneBook); } }
break;
case UD_ID_DOMAIN: dwMask = RASCM_Domain; iReturn = (ERROR_SUCCESS == RasSetCredsWrapper(pArgs, pArgs->pszRasPbk, dwMask, (LPCTSTR)pvData)); break;
case UD_ID_INET_PASSWORD: dwMask = RASCM_Password; pszPhoneBook = CreateRasPrivatePbk(pArgs);
if (pszPhoneBook) { iReturn = (ERROR_SUCCESS == RasSetCredsWrapper(pArgs, pszPhoneBook, dwMask, (LPCTSTR)pvData)); CmFree(pszPhoneBook); } break;
case UD_ID_INET_USERNAME: dwMask = RASCM_UserName; pszPhoneBook = CreateRasPrivatePbk(pArgs);
if (pszPhoneBook) { iReturn = (ERROR_SUCCESS == RasSetCredsWrapper(pArgs, pszPhoneBook, dwMask, (LPCTSTR)pvData)); CmFree(pszPhoneBook); } break;
default: break; } }
if ((0 != iReturn) && (-1 != iReturn)) { if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { CMTRACE1(TEXT("WriteUserInfoToRas() - %s saved to the Global RAS Credential store"), TranslateUserDataID(uiDataID)); } else { CMTRACE1(TEXT("WriteUserInfoToRas() - %s saved to the User RAS Credential store"), TranslateUserDataID(uiDataID)); } }
return iReturn; }
//+---------------------------------------------------------------------------
//
// Function: WriteUserInfoToReg
//
// Synopsis: Write a userinfo data to the registry.
//
// Arguments: pArgs ptr to ArgsStruct
// uiDataID the resource ID associated with the data
// pvData userinfo data
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL WriteUserInfoToReg( ArgsStruct *pArgs, UINT uiDataID, PVOID pvData) { MYDBGASSERT(pArgs); MYDBGASSERT(pvData);
BOOL fRet = FALSE; UINT uiID = uiDataID; // can be changed in switch
BYTE *lpData;
if (NULL == pArgs || NULL == pvData) { return FALSE; }
//
// Determine Reg params based upon uiDataID
//
switch (uiID) { case UD_ID_USERNAME: case UD_ID_INET_USERNAME: case UD_ID_DOMAIN: case UD_ID_CURRENTACCESSPOINT: { //
// Store as strings
//
DWORD dwSize = (lstrlenU((LPTSTR)pvData) + 1) * sizeof(TCHAR); MYDBGASSERT(dwSize <= (UNLEN + sizeof(TCHAR))); // Make sure size is reasonable
lpData = (BYTE *) pvData;
fRet = WriteDataToReg(pArgs->szServiceName, uiID, REG_SZ, lpData, dwSize, pArgs->fAllUser); break; }
case UD_ID_PASSWORD: case UD_ID_INET_PASSWORD: { DWORD dwBufLen = 0; DWORD dwCrypt = 0; LPTSTR pszSubKey = BuildUserInfoSubKey(pArgs->szServiceName, pArgs->fAllUser); LPSTR pszAnsiSubKey = WzToSzWithAlloc(pszSubKey); if (UD_ID_INET_PASSWORD == uiID) { dwCrypt |= CMSECURE_ET_USE_SECOND_RND_KEY; }
//
// Encrypt
//
LPTSTR pszEncryptedData = EncryptPassword(pArgs, (LPTSTR) pvData, &dwBufLen, &dwCrypt, TRUE, pszAnsiSubKey); //
// Free in case we return if the function failed
//
CmFree(pszSubKey); CmFree(pszAnsiSubKey);
if (!pszEncryptedData) { return FALSE; }
MYDBGASSERT(dwBufLen <= CM_MAX_PWD); // Can't read it out otherwise
//
// Write the password and the encryption type on success
//
if (WriteDataToReg(pArgs->szServiceName, uiID, REG_BINARY, (BYTE *) pszEncryptedData, dwBufLen, pArgs->fAllUser)) { //
// A second write for the encryption type. Written as a DWORD.
//
uiID = UD_ID_PCS; //
// Now that we're UNICODE enabled, we will always be encrypting
// a UNICODE string, so update the crypt type, so that it can be
// properly decrypted.
//
dwCrypt = AnsiToUnicodePcs(dwCrypt); lpData = (BYTE *) &dwCrypt; fRet = WriteDataToReg(pArgs->szServiceName, uiID, REG_DWORD, lpData, sizeof(DWORD), pArgs->fAllUser); }
//
// Release the buffer before we go
//
CmFree(pszEncryptedData);
break; } case UD_ID_NOPROMPT: case UD_ID_REMEMBER_PWD: case UD_ID_REMEMBER_INET_PASSWORD: case UD_ID_ACCESSPOINTENABLED: { //
// Store BOOL as DWORD
//
DWORD dwTmp = *(LPBOOL)pvData; lpData = (BYTE *) &dwTmp;
fRet = WriteDataToReg(pArgs->szServiceName, uiID, REG_DWORD, lpData, sizeof(DWORD), pArgs->fAllUser); break; }
default: break; }
MYDBGASSERT(fRet); return fRet; }
//+----------------------------------------------------------------------------
//
// Function: WriteDataToReg
//
// Synopsis: Stores the specified data as the specifed value under the
// specified key under the userinfo root.
//
// Arguments: LPCTSTR pszKey - The key name (service name)
// UINT uiDataID - The resource ID, used to name the value
// DWORD dwType - The registry data type
// CONST BYTE *lpData - Ptr to the data to be stored
// DWORD cbData - The size of the data buffer
// BOOL fAllUser - Flag indicating that profile is All-User
//
// Returns: BOOL - TRUE on success, otherwise FALSE
//
// History: nickball Created 5/21/98
//
//+----------------------------------------------------------------------------
BOOL WriteDataToReg( LPCTSTR pszKey, UINT uiDataID, DWORD dwType, CONST BYTE *lpData, DWORD cbData, BOOL fAllUser) { MYDBGASSERT(pszKey && *pszKey); MYDBGASSERT(lpData);
HKEY hKeyCm; DWORD dwDisposition; DWORD dwRes = 1; LPTSTR pszSubKey;
if (NULL == pszKey || !*pszKey || NULL == lpData) { return FALSE; } //
// Per-user data is always stored under HKEY_CURRENT_USER
// Build the sub key to be opened.
//
pszSubKey = BuildUserInfoSubKey(pszKey, fAllUser);
if (NULL == pszSubKey) { return FALSE; } //
// Open the sub key under HKCU
//
dwRes = RegCreateKeyExU(HKEY_CURRENT_USER, pszSubKey, 0, TEXT(""), REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKeyCm, &dwDisposition);
//
// If we opened the key successfully, write the value
//
if (ERROR_SUCCESS == dwRes) { dwRes = RegSetValueExU(hKeyCm, TranslateUserDataID(uiDataID), NULL, dwType, lpData, cbData); #ifdef DEBUG
if (ERROR_SUCCESS == dwRes) { CMTRACE1(TEXT("WriteDataToReg() - %s written to registry"), TranslateUserDataID(uiDataID)); } #endif
RegCloseKey(hKeyCm); }
CmFree(pszSubKey);
return (ERROR_SUCCESS == dwRes); }
//+----------------------------------------------------------------------------
//
// Function: DeleteDataFromReg
//
// Synopsis: Deletes the specified value under the specified by uiDataID
//
// Arguments: LPCTSTR pszKey - The key name (service name)
// UINT uiDataID - The resource ID, used to name the value
// BOOL fAllUser - Flag indicating that profile is All-User
//
// Returns: BOOL - TRUE on success, otherwise FALSE
//
// History: nickball Created 5/21/98
//
//+----------------------------------------------------------------------------
BOOL DeleteDataFromReg( LPCTSTR pszKey, UINT uiDataID, BOOL fAllUser) { MYDBGASSERT(pszKey && *pszKey);
HKEY hKeyCm; DWORD dwRes = 1; LPTSTR pszSubKey;
if (NULL == pszKey || !*pszKey) { return FALSE; } //
// Per-user data is always stored under HKEY_CURRENT_USER
// Build the sub key to be opened.
//
pszSubKey = BuildUserInfoSubKey(pszKey, fAllUser);
if (NULL == pszSubKey) { return FALSE; } //
// Open the sub key under HKCU
//
dwRes = RegOpenKeyExU(HKEY_CURRENT_USER, pszSubKey, 0, KEY_SET_VALUE, &hKeyCm); //
// If we opened the key successfully, delete the value
//
if (ERROR_SUCCESS == dwRes) { dwRes = RegDeleteValueU(hKeyCm, TranslateUserDataID(uiDataID));
//
// Delete the key used for encrypting the passwords
//
if (UD_ID_PASSWORD == uiDataID) { dwRes = RegDeleteValueU(hKeyCm, c_pszCmRegKeyEncryptedPasswordKey); }
if (UD_ID_INET_PASSWORD == uiDataID) { dwRes = RegDeleteValueU(hKeyCm, c_pszCmRegKeyEncryptedInternetPasswordKey); }
#ifdef DEBUG
if (ERROR_SUCCESS == dwRes) { CMTRACE1(TEXT("DeleteDataFromReg() - %s removed from registry"), TranslateUserDataID(uiDataID)); } #endif
RegCloseKey(hKeyCm); }
CmFree(pszSubKey);
return (ERROR_SUCCESS == dwRes); }
//+----------------------------------------------------------------------------
//
// Function: GetDataFromReg
//
// Synopsis: Allocates a buffer for and retrieves the specifed data from the
// registry.
//
// Arguments: LPCTSTR pszKey - The key name (service name)
// UINT uiDataID - The resource ID, used to name the value
// DWORD dwType - The registry data type
// DWORD dwSize - Numbrt of bytes in the data buffer
// BOOL fAllUser - Flag indicating that profile is All-User
//
// Returns: LPBYTE - Ptr to retrieved data, NULL on error
//
// History: nickball Created 5/21/98
//
//+----------------------------------------------------------------------------
LPBYTE GetDataFromReg( LPCTSTR pszKey, UINT uiDataID, DWORD dwType, DWORD dwSize, BOOL fAllUser) { MYDBGASSERT(pszKey);
DWORD dwSizeTmp = dwSize; DWORD dwTypeTmp = dwType;
if (NULL == pszKey || !*pszKey) { return NULL; }
//
// Allocate a buffer of the desired size
//
LPBYTE lpData = (BYTE *) CmMalloc(dwSize);
if (NULL == lpData) { return FALSE; }
//
// Read the data from the registry
//
if (!ReadDataFromReg(pszKey, uiDataID, &dwTypeTmp, lpData, &dwSizeTmp, fAllUser)) { CmFree(lpData); lpData = NULL; }
return lpData; } //+---------------------------------------------------------------------------
//
// Function: ReadUserInfoFromReg
//
// Synopsis: Read the specified userinfo data from the registry.
//
// Arguments: pArgs ptr to ArgsStruct
// uiDataID the resource ID associated with the data
// ppvData ptr to ptr to be allocated and filled
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL ReadUserInfoFromReg( ArgsStruct *pArgs, UINT uiDataID, PVOID *ppvData) { MYDBGASSERT(pArgs); MYDBGASSERT(ppvData);
BYTE *lpData = NULL;
if (NULL == pArgs || NULL == ppvData) { return FALSE; }
//
// Set size and type as appropriate
//
switch (uiDataID) { case UD_ID_USERNAME: case UD_ID_INET_USERNAME: case UD_ID_DOMAIN: case UD_ID_CURRENTACCESSPOINT: { lpData = GetDataFromReg(pArgs->szServiceName, uiDataID, REG_SZ, (UNLEN + 1) * sizeof(TCHAR), pArgs->fAllUser); if (lpData) { *ppvData = lpData; } break; }
case UD_ID_PASSWORD: case UD_ID_INET_PASSWORD: { BYTE *lpTmp = NULL;
//
// Get the encryption type
//
lpData = GetDataFromReg(pArgs->szServiceName, UD_ID_PCS, REG_DWORD, sizeof(DWORD), pArgs->fAllUser);
if (!lpData) { return FALSE; } //
// Since we know the return value in this case is a DWORD, then cast it to DWORD pointer
// and get the value
//
DWORD dwCrypt = *((DWORD*)lpData); CmFree(lpData);
//
// Now retrieve the encrypted password
//
lpData = GetDataFromReg(pArgs->szServiceName, uiDataID, REG_BINARY, CM_MAX_PWD, pArgs->fAllUser);
if (!lpData) { return FALSE; }
//
// Decrypt it
//
DWORD dwSize = lstrlenU((LPTSTR)lpData)*sizeof(TCHAR);
//
// Crypt routines only know about Ansi PCS values, so convert as necessary
//
LPTSTR pszSubKey = BuildUserInfoSubKey(pArgs->szServiceName, pArgs->fAllUser); LPSTR pszAnsiSubKey = WzToSzWithAlloc(pszSubKey);
if (UD_ID_INET_PASSWORD == uiDataID) { dwCrypt |= CMSECURE_ET_USE_SECOND_RND_KEY; }
lpTmp = DecryptPassword(pArgs, (LPBYTE)lpData, UnicodeToAnsiPcs(dwCrypt), dwSize, TRUE, pszAnsiSubKey);
//
// Free the buffer for the reg query
//
CmFree(lpData); //
// We're Unicode now, so if the password was encrypted
// as an Ansi string convert the data to a UNICODE string.
// Otherwise, just update the supplied buffer.
//
if (IsAnsiPcs(dwCrypt) && lpTmp) { *ppvData = SzToWzWithAlloc((LPSTR)lpTmp); CmFree(lpTmp); } else { *ppvData = lpTmp; }
//
// Assign lpData for return purposes
//
lpData = (BYTE*) *ppvData; // NULL on failure
CmFree(pszSubKey); CmFree(pszAnsiSubKey); break; }
case UD_ID_NOPROMPT: case UD_ID_REMEMBER_PWD: case UD_ID_REMEMBER_INET_PASSWORD: case UD_ID_ACCESSPOINTENABLED: { lpData = GetDataFromReg(pArgs->szServiceName, uiDataID, REG_DWORD, sizeof(DWORD), pArgs->fAllUser);
if (lpData) { //
// Translate to DWORD pointer and check the value
//
if (*((DWORD*)lpData)) { *(BOOL *)*ppvData = TRUE; } else { *(BOOL *)*ppvData = FALSE; } CmFree(lpData); } break; }
default: MYDBGASSERT(FALSE); return FALSE; }
return (NULL != lpData); }
//+----------------------------------------------------------------------------
//
// Function: ReadDataFromReg
//
// Synopsis: Retrieves the data from the specifed value under the
// specified key under the userinfo root.
//
// Arguments: LPCTSTR pszKey - The key name (service name)
// UINT uiDataID - The resource ID, used to name the value
// LPDWORD lpdwType - The registry data type expected, and returned
// CONST BYTE *lpData - Ptr to buffer for data
// LPDWORD lpcbData - The size of the data buffer
// BOOL fAllUser - Flag indicating that profile is All-User
//
// Returns: BOOL - TRUE on success, otherwise FALSE
//
// History: nickball Created 5/21/98
//
//+----------------------------------------------------------------------------
BOOL ReadDataFromReg( LPCTSTR pszKey, UINT uiDataID, LPDWORD lpdwType, BYTE *lpData, LPDWORD lpcbData, BOOL fAllUser) { MYDBGASSERT(pszKey && *pszKey); MYDBGASSERT(lpData); MYDBGASSERT(lpcbData); MYDBGASSERT(lpdwType);
HKEY hKeyCm; DWORD dwRes = 1; DWORD dwTypeTmp; // the value returned by query
LPTSTR pszSubKey;
if (NULL == pszKey || !*pszKey || NULL == lpData) { return FALSE; } //
// Per-user data is always stored under HKEY_CURRENT_USER
// Build the sub key to be opened.
//
pszSubKey = BuildUserInfoSubKey(pszKey, fAllUser);
if (NULL == pszSubKey) { return FALSE; } //
// Open the sub key under HKCU
//
dwRes = RegOpenKeyExU(HKEY_CURRENT_USER, pszSubKey, 0, KEY_QUERY_VALUE, &hKeyCm); //
// If we opened the key successfully, retrieve the value
//
if (ERROR_SUCCESS == dwRes) { dwRes = RegQueryValueExU(hKeyCm, TranslateUserDataID(uiDataID), NULL, &dwTypeTmp, lpData, lpcbData); if (ERROR_SUCCESS == dwRes) { CMTRACE1(TEXT("ReadDataFromReg() - %s read from registry"), TranslateUserDataID(uiDataID)); MYDBGASSERT(*lpdwType == dwTypeTmp);
if (*lpdwType == dwTypeTmp) { *lpdwType = dwTypeTmp; } } RegCloseKey(hKeyCm); }
CmFree(pszSubKey); return (ERROR_SUCCESS == dwRes && (*lpdwType == dwTypeTmp)); // sanity check that type was expected
}
//+---------------------------------------------------------------------------
//
// Function: DeleteUserInfoFromReg
//
// Synopsis: Delete userinfo data from registry
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry cmp field entry id
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL DeleteUserInfoFromReg( ArgsStruct *pArgs, UINT uiEntry ) { return DeleteDataFromReg(pArgs->szServiceName, uiEntry, pArgs->fAllUser); }
//+---------------------------------------------------------------------------
//
// Function: DeleteUserInfoFromRas
//
// Synopsis: Delete userinfo data from the RAS credential cache
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry cmp field entry id
//
// Returns: int TRUE = success, FALSE = failure, -1 if RAS doesn't
// store this info
//
//----------------------------------------------------------------------------
int DeleteUserInfoFromRas( ArgsStruct *pArgs, UINT uiEntry ) { LPTSTR pszEmpty = TEXT("");
return WriteUserInfoToRas(pArgs, uiEntry, pszEmpty); }
//+---------------------------------------------------------------------------
//
// Function: ReadPasswordFromCmp
//
// Synopsis: Read a null terminated password string from Cmp.
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry cmp entry name
// ppszPassword ptr to ptr of the password buffer.
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL ReadPasswordFromCmp( ArgsStruct *pArgs, UINT uiEntry, LPTSTR *ppszPassword ) { MYDBGASSERT(pArgs); MYDBGASSERT(ppszPassword);
if (NULL == pArgs || NULL == ppszPassword) { return FALSE; }
//
// Read in password from profile
//
BOOL fOk = FALSE;
LPTSTR pszEncryptedData = pArgs->piniProfile->GPPS(c_pszCmSection, TranslateUserDataID(uiEntry));
if (*pszEncryptedData) { //
// Trim away all the spaces at both ends
//
CmStrTrim(pszEncryptedData);
//
// Get the type and decrypt
//
DWORD dwEncryptionType = (DWORD)pArgs->piniProfile->GPPI(c_pszCmSection, c_pszCmEntryPcs, CMSECURE_ET_RC2); // default
//
// Since this was saved in the CMP in Ansi form, we need to convert the characters back to
// Ansi form so that we can decrypt them. We still may not be able to (if we cannot
// round trip the Unicode conversion for instance) but then we will fail and display a
// blank password. Not the end of the world but hopefully avoidable.
//
LPSTR pszAnsiEncryptedData; LPSTR pszAnsiUnEncryptedData;
pszAnsiEncryptedData = WzToSzWithAlloc(pszEncryptedData); if (NULL != pszAnsiEncryptedData) { DWORD dwSize = lstrlenA(pszAnsiEncryptedData)*sizeof(TCHAR); //
// Here we don't need to differentiate between main password and internet password
// because we are reading this from a file and the mask is used when reading to/from
// registry.
//
pszAnsiUnEncryptedData = (LPSTR)DecryptPassword(pArgs, (LPBYTE)pszAnsiEncryptedData, dwEncryptionType, dwSize, FALSE, NULL);
if (pszAnsiUnEncryptedData) { *ppszPassword = SzToWzWithAlloc(pszAnsiUnEncryptedData);
if (NULL != *ppszPassword) { fOk = ((BOOL)**ppszPassword); } CmWipePasswordA(pszAnsiUnEncryptedData); CmFree(pszAnsiUnEncryptedData); } }
CmFree(pszAnsiEncryptedData); }
CmFree(pszEncryptedData);
return fOk; }
//+---------------------------------------------------------------------------
//
// Function: ReadUserInfoFromCmp
//
// Synopsis: Read a userinfo data from cmp.
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry the cmp file entry
// ppvData ptr to ptr to the data buffer. If the userinfo
// is multiple byte(e.g. password), the func allocs
// the buffer.
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL ReadUserInfoFromCmp( ArgsStruct *pArgs, UINT uiEntry, PVOID *ppvData ) { switch (uiEntry) { case UD_ID_USERNAME: case UD_ID_INET_USERNAME: case UD_ID_DOMAIN: *ppvData = (PVOID)pArgs->piniProfile->GPPS(c_pszCmSection, TranslateUserDataID(uiEntry)); break;
case UD_ID_PASSWORD: case UD_ID_INET_PASSWORD: return ReadPasswordFromCmp(pArgs, uiEntry, (LPTSTR *)ppvData); break;
case UD_ID_NOPROMPT: case UD_ID_REMEMBER_PWD: case UD_ID_REMEMBER_INET_PASSWORD: *(BOOL *)(*ppvData) = pArgs->piniProfile->GPPB(c_pszCmSection, TranslateUserDataID(uiEntry)); break;
//
// None of these should be in the CMP by this point. Return a failure value.
//
case UD_ID_PCS: case UD_ID_ACCESSPOINTENABLED: case UD_ID_CURRENTACCESSPOINT: // if we are trying to read the access point
CMASSERTMSG(FALSE, TEXT("ReadUserInfoFromCmp -- trying to read a value that should never be in the cmp, why?")); *ppvData = NULL; return FALSE; break;
default: MYDBGASSERT(0); break; }
return TRUE; }
//+---------------------------------------------------------------------------
//
// Function: DeleteUserInfoFromCmp
//
// Synopsis: Deletes userinfo data from cmp.
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry the cmp file entry
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL DeleteUserInfoFromCmp( ArgsStruct *pArgs, UINT uiEntry ) { BOOL bReturn = FALSE; UINT uiKeepDefCreds = 0; const TCHAR* const c_pszKeepDefaultCredentials = TEXT("KeepDefaultCredentials");
if (NULL == pArgs) { return bReturn; }
switch (uiEntry) { case UD_ID_USERNAME: case UD_ID_DOMAIN: case UD_ID_INET_USERNAME: case UD_ID_NOPROMPT: case UD_ID_REMEMBER_PWD: case UD_ID_REMEMBER_INET_PASSWORD: case UD_ID_PASSWORD: case UD_ID_INET_PASSWORD:
//
// Get KeepDefaultCredentials value from CMP
//
uiKeepDefCreds = GetPrivateProfileIntU(c_pszCmSection, c_pszKeepDefaultCredentials, 0, pArgs->piniProfile->GetFile());
if (0 == uiKeepDefCreds) { if (WritePrivateProfileStringU(c_pszCmSection, TranslateUserDataID(uiEntry), NULL, pArgs->piniProfile->GetFile())) { bReturn = TRUE; } } break;
default: MYDBGASSERT(0); break;
} return bReturn; }
//+---------------------------------------------------------------------------
//
// Function: RasGetCredsWrapper
//
// Synopsis: Wrapper function to call RasGetCredentials. The function
// calls RasGetCredentials and then copies the appropriate data
// from the RASCREDENTIALS struct into the buffer pointed to by
// *ppvData (allocated on the caller behalf). Note that the value
// set in dwMask determines which data item is retrieved from the
// credentials cache. Currently, dwMask must be one of RASCM_UserName,
// RASCM_Domain, or RASCM_Password.
//
// Arguments: pArgs ptr to ArgsStruct
// pszPhoneBook full path to the phonebook file to get the
// data from, or NULL to use the all user default pbk
// dwMask dwMask value for the RASCREDENTIALS struct
// ppvData ptr to ptr to the data buffer. If the userinfo
// is multiple byte(e.g. password), the func allocs
// the buffer.
//
// Returns: DWORD ERROR_SUCCESS on success, winerror on failure
//
//----------------------------------------------------------------------------
DWORD RasGetCredsWrapper( ArgsStruct *pArgs, LPCTSTR pszPhoneBook, DWORD dwMask, PVOID *ppvData ) { DWORD dwRet = ERROR_INVALID_PARAMETER;
MYDBGASSERT(pArgs && pArgs->rlsRasLink.pfnGetCredentials); MYDBGASSERT(ppvData); MYDBGASSERT((RASCM_UserName == dwMask) || (RASCM_Domain == dwMask) || (RASCM_Password == dwMask));
if (pArgs && ppvData && pArgs->rlsRasLink.pfnGetCredentials) { LPTSTR pszConnectoid = GetRasConnectoidName(pArgs, pArgs->piniService, FALSE);
if (pszConnectoid) { RASCREDENTIALS RasCredentials = {0}; RasCredentials.dwSize = sizeof(RasCredentials); if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { RasCredentials.dwMask = dwMask | RASCM_DefaultCreds; } else { RasCredentials.dwMask = dwMask; } dwRet = pArgs->rlsRasLink.pfnGetCredentials(pszPhoneBook, pszConnectoid, &RasCredentials);
if (ERROR_SUCCESS == dwRet) { LPTSTR pszData = NULL;
if (RASCM_UserName == dwMask) { pszData = RasCredentials.szUserName; } else if (RASCM_Domain == dwMask) { pszData = RasCredentials.szDomain; } else if (RASCM_Password == dwMask) { pszData = RasCredentials.szPassword; }
LPTSTR pszReturn = CmStrCpyAlloc(pszData);
if (NULL == pszReturn) { dwRet = ERROR_NOT_ENOUGH_MEMORY; } else { *ppvData = pszReturn; } }
CmWipePassword(RasCredentials.szPassword);
CmFree(pszConnectoid); } }
return dwRet; }
//+---------------------------------------------------------------------------
//
// Function: ReadUserInfoFromRas
//
// Synopsis: Read userinfo data from the RAS credentials cache
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry the cmp file entry
// ppvData ptr to ptr to the data buffer. If the userinfo
// is multiple byte(e.g. password), the func allocs
// the buffer.
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL ReadUserInfoFromRas( ArgsStruct *pArgs, UINT uiEntry, PVOID *ppvData ) { BOOL bReturn = FALSE;
if (OS_NT5 && pArgs && pArgs->bUseRasCredStore) { DWORD dwMask; LPTSTR pszPhoneBook = NULL;
switch (uiEntry) { case UD_ID_USERNAME: dwMask = RASCM_UserName; bReturn = (ERROR_SUCCESS == RasGetCredsWrapper(pArgs, pArgs->pszRasPbk, dwMask, ppvData));
break;
case UD_ID_PASSWORD: dwMask = RASCM_Password; bReturn = (ERROR_SUCCESS == RasGetCredsWrapper(pArgs, pArgs->pszRasPbk, dwMask, ppvData)); break;
case UD_ID_DOMAIN: dwMask = RASCM_Domain; bReturn = (ERROR_SUCCESS == RasGetCredsWrapper(pArgs, pArgs->pszRasPbk, dwMask, ppvData)); break;
case UD_ID_INET_PASSWORD: dwMask = RASCM_Password; pszPhoneBook = CreateRasPrivatePbk(pArgs);
if (pszPhoneBook) { bReturn = (ERROR_SUCCESS == RasGetCredsWrapper(pArgs, pszPhoneBook, dwMask, ppvData)); CmFree(pszPhoneBook); } break;
case UD_ID_INET_USERNAME: dwMask = RASCM_UserName; pszPhoneBook = CreateRasPrivatePbk(pArgs);
if (pszPhoneBook) { bReturn = (ERROR_SUCCESS == RasGetCredsWrapper(pArgs, pszPhoneBook, dwMask, ppvData)); CmFree(pszPhoneBook); } break; } }
if (bReturn) { if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { CMTRACE1(TEXT("ReadUserInfoFromRas() - %s retrieved from the Global RAS Credential store"), TranslateUserDataID(uiEntry)); } else { CMTRACE1(TEXT("ReadUserInfoFromRas() - %s retrieved from the User RAS Credential store"), TranslateUserDataID(uiEntry)); } }
return bReturn; }
//+---------------------------------------------------------------------------
//
// Function: GetUserInfo
//
// Synopsis: Get an userinfo. The user info can reside in either the
// cache, cmp, or registry. This functions hides this from the
// user.
//
// We first try the cmp file. If that fails, we try the cache.
// We'll get the following user info:
// username,
// password,
// domain,
// remember main passwd,
// dial automatically,
// inet username,
// inet passwd
// remember inet password
// inet use same user name
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry the cmp file entry
// pvData ptr to ptr to the data buffer. If the userinfo
// is multiple byte(e.g. password), the func allocs
// the buffer.
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL GetUserInfo( ArgsStruct *pArgs, UINT uiEntry, PVOID *ppvData ) { BOOL bReturn = ReadUserInfoFromRas(pArgs, uiEntry, ppvData);
if (!bReturn) { bReturn = ReadUserInfoFromReg(pArgs, uiEntry, ppvData); }
if (!bReturn) { bReturn = ReadUserInfoFromCmp(pArgs, uiEntry, ppvData); }
return bReturn; }
//+---------------------------------------------------------------------------
//
// Function: SaveUserInfo
//
// Synopsis: Save an userinfo. The user info can reside in either the
// RAS cred cache or the registry. This functions abstracts
// this from the user.
//
// We first try the RAS cred cache. If the RAS cred cache doesn't hold that
// piece of info we then save it in the registry.
// We'll save the following user info:
// username,
// password,
// domain,
// remember main passwd,
// dial automatically,
// inet username,
// inet passwd
// remember inet password
// inet use same user name
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry the cmp file entry
// pvData ptr to the data buffer. If the userinfo is
// multiple byte(e.g. password), the func allocs
// the buffer.
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL SaveUserInfo( ArgsStruct *pArgs, UINT uiEntry, PVOID pvData ) { //
// Try giving the Data to RAS first. If the function returns
// -1, then this is data that RAS doesn't hold for us and we will
// have to put it in the registry instead.
//
int iReturn = WriteUserInfoToRas(pArgs, uiEntry, pvData);
if (-1 == iReturn) { //
// Just write the data to the registry. Use CMP only as
// an upgrade reference for UserInfo data post CM 1.1
//
iReturn = WriteUserInfoToReg(pArgs, uiEntry, pvData); }
return iReturn; }
//+---------------------------------------------------------------------------
//
// Function: DeleteUserInfo
//
// Synopsis: Delete an userinfo. The user info can reside in either the
// RAS Cred cache or the registry. This functions abstracts
// this from the user.
//
// We first try the RAS cache first. If that piece of info isn't stored
// in the RAS cache then we try the registry.
//
// We'll delete the following user info:
// username,
// password,
// domain,
// remember main passwd,
// dial automatically,
// inet username,
// inet passwd
// remember inet password
// inet use same user name
//
// Arguments: pArgs ptr to ArgsStruct
// uiEntry the cmp file entry
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL DeleteUserInfo( ArgsStruct *pArgs, UINT uiEntry ) { int iReturn = DeleteUserInfoFromRas(pArgs, uiEntry);
if (-1 == iReturn) { iReturn = DeleteUserInfoFromReg(pArgs, uiEntry); }
return iReturn; }
//+---------------------------------------------------------------------------
//
// Function: NeedToUpgradeUserInfo
//
// Synopsis: Do we need to upgrade the cm 1.0/1.1 userinfo to the cm 1.2 format?
//
// Arguments: pArgs - Ptr to global args struct
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
int NeedToUpgradeUserInfo( ArgsStruct *pArgs) { MYDBGASSERT(pArgs);
DWORD dwRes; HKEY hKeyCm; LPTSTR pszSubKey; int iReturn = c_iNoUpgradeRequired;
if (pArgs) { //
// If this is NT5 or greater, we want to be storing our credentials with RAS
// instead of the registry.
//
// If this isn't NT5 we still want to upgrade the user to using the registry as
// storage instead of the cmp if they haven't already
// been upgraded. Thus the simple test is to open the service name key in HKCU.
// This key will exist, if the user has already run 1.2 bits.
//
pszSubKey = BuildUserInfoSubKey(pArgs->szServiceName, pArgs->fAllUser);
dwRes = RegOpenKeyExU(HKEY_CURRENT_USER, pszSubKey, 0, KEY_QUERY_VALUE, &hKeyCm);
if (ERROR_SUCCESS == dwRes) { //
// Then we have the registry method, unless we are supposed to be using the RAS
// cred store we are done. If we are supposed to be using the RAS cred store
// we need to check to make sure that we are using it. Note we could have a problem
// here if the user has registry cred data and then their registry gets write protected.
// This would allow us to read from it but not delete the old data. Thus the user
// would never be able to save any changes because we would always think they needed
// to upgrade. An unlikely scenario but possible ...
//
if (pArgs->bUseRasCredStore) { LPTSTR pszUserName = NULL;
BOOL bRet = ReadUserInfoFromReg(pArgs, UD_ID_USERNAME, (PVOID*)&pszUserName);
if (bRet && (NULL != pszUserName) && (TEXT('\0') != pszUserName[0])) { //
// Then we have the username in the registry. Lets upgrade to the RAS
// credential store.
//
iReturn = c_iUpgradeFromRegToRas; }
CmFree(pszUserName); }
RegCloseKey(hKeyCm); } else { iReturn = c_iUpgradeFromCmp; }
CmFree(pszSubKey); } else { CMASSERTMSG(FALSE, TEXT("NeedToUpgradeUserInfo -- NULL pArgs passed")); }
//
// We don't want to upgrade if it's ICS. This prevents from adding info to the registry.
//
if (CM_LOGON_TYPE_ICS == pArgs->dwWinLogonType) { iReturn = c_iNoUpgradeRequired; }
return iReturn; }
//+---------------------------------------------------------------------------
//
// Function: UpgradeUserInfoFromRegToRasAndReg
//
// Synopsis: Upgrade the userinfo from CM 1.2 registry only format to the
// CM 1.3 format which uses both RAS credential storage and
// the registry.
//
// Arguments: pArgs ptr to ArgsStruct
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL UpgradeUserInfoFromRegToRasAndReg( ArgsStruct *pArgs ) { BOOL bReturn = FALSE;
if (OS_NT5) { LPTSTR pszTmp;
pszTmp = NULL;
//
// If we get an empty string "" from ReadUserInfoFromReg we don't want to
// save the empty string to the RAS Credstore because it might overwrite
// global credentials information. This can happen if User1 saves global
// credentials and User2 tries using the same profile. Since User2 is running
// this profile for the 1st time, he'll run through an upgrade path and if global
// creds exist we don't want to null them out.
//
if (ReadUserInfoFromReg(pArgs, UD_ID_INET_USERNAME, (PVOID*)&pszTmp)) { DeleteUserInfoFromReg(pArgs, UD_ID_INET_USERNAME); if (pszTmp && lstrlenU(pszTmp)) { WriteUserInfoToRas(pArgs, UD_ID_INET_USERNAME, pszTmp); } CmFree(pszTmp); }
pszTmp = NULL; if (ReadUserInfoFromReg(pArgs, UD_ID_INET_PASSWORD, (PVOID*)&pszTmp)) { DeleteUserInfoFromReg(pArgs, UD_ID_INET_PASSWORD); if (pszTmp && lstrlenU(pszTmp)) { WriteUserInfoToRas(pArgs, UD_ID_INET_PASSWORD, pszTmp); } CmFree(pszTmp); }
pszTmp = NULL; if (ReadUserInfoFromReg(pArgs, UD_ID_USERNAME, (PVOID*)&pszTmp)) { DeleteUserInfoFromReg(pArgs, UD_ID_USERNAME); if (pszTmp && lstrlenU(pszTmp)) { WriteUserInfoToRas(pArgs, UD_ID_USERNAME, pszTmp); } CmFree(pszTmp); }
pszTmp = NULL; if (ReadUserInfoFromReg(pArgs, UD_ID_DOMAIN, (PVOID*)&pszTmp)) { DeleteUserInfoFromReg(pArgs, UD_ID_DOMAIN); if (pszTmp && lstrlenU(pszTmp)) { WriteUserInfoToRas(pArgs, UD_ID_DOMAIN, pszTmp); } CmFree(pszTmp); }
pszTmp = NULL; if (ReadUserInfoFromReg(pArgs, UD_ID_PASSWORD, (PVOID*)&pszTmp)) { DeleteUserInfoFromReg(pArgs, UD_ID_PASSWORD); if (pszTmp && lstrlenU(pszTmp)) { WriteUserInfoToRas(pArgs, UD_ID_PASSWORD, pszTmp); } CmFree(pszTmp); }
//
// Now delete the PCS value as it is no longer meaningful
//
DeleteUserInfoFromReg(pArgs, UD_ID_PCS); } else { MYDBGASSERT(FALSE); }
return bReturn; }
//+---------------------------------------------------------------------------
//
// Function: UpgradeUserInfoFromCmp
//
// Synopsis: Upgrade the userinfo from cm1.0/1,1 format to 1.3 format.
//
// Arguments: pArgs ptr to ArgsStruct
//
// Returns: BOOL TRUE = success, FALSE = failure
//
//----------------------------------------------------------------------------
BOOL UpgradeUserInfoFromCmp( ArgsStruct *pArgs ) { LPTSTR pszTmp; BOOL fTmp; PVOID pv;
//
// First retrieve each of the non-cached data items
// Then delete username, internetusername, domain, password,
// internetpassword, remember password, remember internet password
// and noprompt (dial automatically) from the CMP file.
// If the KeepDefaultCredentials is set to 1 in the .CMP file then the
// DeleteUserInfoFromCmp function does not actually delete the values from
// the file.
// If we get an empty string "" from ReadUserInfoFromCmp we don't want to
// save the empty string to the RAS Credstore because it might overwrite
// global credentials information. This can happen if User1 saves global
// credentials and User2 tries using the same profile. Since User2 is running
// this profile for the 1st time, he'll run through an upgrade path and if global
// creds exist we don't want to null them out.
//
pszTmp = NULL; ReadUserInfoFromCmp(pArgs, UD_ID_USERNAME, (PVOID*)&pszTmp); if (pszTmp && lstrlenU(pszTmp)) { SaveUserInfo(pArgs, UD_ID_USERNAME, pszTmp); } DeleteUserInfoFromCmp(pArgs, UD_ID_USERNAME); CmFree(pszTmp);
pszTmp = NULL; ReadUserInfoFromCmp(pArgs, UD_ID_DOMAIN, (PVOID*)&pszTmp); if (pszTmp && lstrlenU(pszTmp)) { SaveUserInfo(pArgs, UD_ID_DOMAIN, pszTmp); } DeleteUserInfoFromCmp(pArgs, UD_ID_DOMAIN); CmFree(pszTmp);
pszTmp = NULL; ReadUserInfoFromCmp(pArgs, UD_ID_INET_USERNAME, (PVOID*)&pszTmp); if (pszTmp && lstrlenU(pszTmp)) { SaveUserInfo(pArgs, UD_ID_INET_USERNAME, pszTmp); } DeleteUserInfoFromCmp(pArgs, UD_ID_INET_USERNAME); CmFree(pszTmp);
pv = &fTmp; ReadUserInfoFromCmp(pArgs, UD_ID_NOPROMPT, &pv); SaveUserInfo(pArgs, UD_ID_NOPROMPT, pv); DeleteUserInfoFromCmp(pArgs, UD_ID_NOPROMPT);
pv = &fTmp; ReadUserInfoFromCmp(pArgs, UD_ID_REMEMBER_PWD, &pv); SaveUserInfo(pArgs, UD_ID_REMEMBER_PWD, pv); DeleteUserInfoFromCmp(pArgs, UD_ID_REMEMBER_PWD);
pv = &fTmp; ReadUserInfoFromCmp(pArgs, UD_ID_REMEMBER_INET_PASSWORD, &pv); SaveUserInfo(pArgs, UD_ID_REMEMBER_INET_PASSWORD, pv); DeleteUserInfoFromCmp(pArgs, UD_ID_REMEMBER_INET_PASSWORD);
//
// Construct old cache entry name
//
LPTSTR pszCacheEntryName = GetLegacyKeyName(pArgs); //
// main passwd
//
pszTmp = NULL; //
// To get the passwords, the cm 1.1 logic is that we first try the cmp, then the cache.
//
if (ReadUserInfoFromCmp(pArgs, UD_ID_PASSWORD, (PVOID*)&pszTmp)) { if (pszTmp && lstrlenU(pszTmp)) { SaveUserInfo(pArgs, UD_ID_PASSWORD, pszTmp); } } else { CmFree(pszTmp); pszTmp = NULL;
#ifdef TEST_USERINFO_UPGRADE
MYVERIFY(WriteStringToCache(pArgs, pszCacheEntryName, TEXT("CM 1.1 main password"))); #endif
//
// Try to read it from cache
//
if (ReadStringFromCache(pArgs, pszCacheEntryName, &pszTmp)) { if (pszTmp && lstrlenU(pszTmp)) { if (SaveUserInfo(pArgs, UD_ID_PASSWORD, pszTmp)) {
#ifdef TEST_USERINFO_UPGRADE
MYVERIFY(DeleteStringFromCache(pArgs, pszCacheEntryName)); #endif
} } } } DeleteUserInfoFromCmp(pArgs, UD_ID_PASSWORD); CmFree(pszTmp);
//
// inet passwd
//
pszTmp = NULL; if (ReadUserInfoFromCmp(pArgs, UD_ID_INET_PASSWORD, (PVOID*)&pszTmp)) { if (pszTmp && lstrlenU(pszTmp)) { SaveUserInfo(pArgs, UD_ID_INET_PASSWORD, pszTmp); } } else { CmFree(pszTmp); pszTmp = NULL;
//
// Build tunnel entry name and read string from cache
//
pszCacheEntryName = CmStrCatAlloc(&pszCacheEntryName, TEXT("-tunnel"));
#ifdef TEST_USERINFO_UPGRADE
MYVERIFY(WriteStringToCache(pArgs, pszCacheEntryName, TEXT("CM 1.1 internet password"))); #endif
if (ReadStringFromCache(pArgs, pszCacheEntryName, &pszTmp)) { if (pszTmp && lstrlenU(pszTmp)) { if (SaveUserInfo(pArgs, UD_ID_INET_PASSWORD, pszTmp)) {
#ifdef TEST_USERINFO_UPGRADE
MYVERIFY(DeleteStringFromCache(pArgs, pszCacheEntryName)); #endif
} } } } DeleteUserInfoFromCmp(pArgs, UD_ID_INET_PASSWORD); CmFree(pszTmp);
CmFree(pszCacheEntryName);
return TRUE; // MarkUserInfoUpgraded(pArgs);
}
//+----------------------------------------------------------------------------
//
// Function: GetLegacyKeyName
//
// Synopsis: Builds the string fragment used to build cache entry name. The "
// sign-in" prefix is maintained for legacy compatibility
//
// Arguments: ArgsStruct *pArgs - Ptr to global args struct
//
// Returns: LPTSTR - Ptr to allocated string containing "<service name> - Sign-In"
//
// Note: Used exclusively for cache entry name construction
//
// History: nickball Created Header 4/16/98
//
//+----------------------------------------------------------------------------
LPTSTR GetLegacyKeyName(ArgsStruct *pArgs) { MYDBGASSERT(pArgs);
//
// Service name is the basis of the key name. We also include
// IDMSG_TITLESERVICE and append a suffix of " (Connection Manager)"
//
LPTSTR pszRes = CmFmtMsg(g_hInst, IDMSG_TITLESERVICE, pArgs->szServiceName); MYDBGASSERT(pszRes && *pszRes);
if (pszRes) { pszRes = CmStrCatAlloc(&pszRes, c_pszCacheEntryNameSuffix); }
return (pszRes); }
//+----------------------------------------------------------------------------
//
// Function: EncryptPassword
//
// Synopsis: Wrapper for encrypting password
//
// Arguments: ArgsStruct *pArgs - Ptr to global args struct
// LPCTSTR pszPassword - The password to be encrypted
// LPDWORD lpdwBufSize - Buffer for size of the encrypted buffer - optional
// LPDWORD lpdwCryptType - Buffer for crypto type used
// BOOL fReg - Password is disguised for registry storage
//
// Returns: LPTSTR - Ptr to allocated buffer containing encrypted form of password
//
// History: nickball Created Header 5/22/98
//
//+----------------------------------------------------------------------------
LPTSTR EncryptPassword( ArgsStruct *pArgs, LPCTSTR pszPassword, LPDWORD lpdwBufSize, LPDWORD lpdwCryptType, BOOL /*fReg*/, LPSTR pszSubKey) { MYDBGASSERT(pArgs); MYDBGASSERT(pszPassword); MYDBGASSERT(lpdwCryptType); DWORD dwEncryptedBufferLen; DWORD dwSize = 0;
LPTSTR pszEncryptedData = NULL; TCHAR szSourceData[PWLEN + 1];
if (NULL == pArgs || NULL == pszPassword || NULL == lpdwCryptType) { return NULL; }
//
// Standard encryption, copy the password
//
lstrcpyU(szSourceData, pszPassword); //
// It is not safe to call InitSecure more than once
//
if (!pArgs->fInitSecureCalled) { pArgs->fInitSecureCalled = TRUE; InitSecure(FALSE); // don't use fast encryption anymore
}
//
// Encrypt the provided password
//
if (EncryptData( (LPBYTE)szSourceData, (lstrlenU(szSourceData)+1) * sizeof(TCHAR), (LPBYTE*)&pszEncryptedData, &dwEncryptedBufferLen, lpdwCryptType, #if defined(DEBUG) && defined(DEBUG_MEM)
(PFN_CMSECUREALLOC)AllocDebugMem, // Give the DEBUG_MEM version of alloc/free
(PFN_CMSECUREFREE)FreeDebugMem, // Not quit right, AllocDebugMem takes 3 param
pszSubKey)) #else
(PFN_CMSECUREALLOC)CmMalloc, (PFN_CMSECUREFREE)CmFree, pszSubKey)) #endif
{ if (lpdwBufSize) { *lpdwBufSize = dwEncryptedBufferLen; } }
MYDBGASSERT(pszEncryptedData); CmWipePassword(szSourceData); return pszEncryptedData; }
//+----------------------------------------------------------------------------
//
// Function: DecryptPassword
//
// Synopsis: Wrapper to decrypt password
//
// Arguments: ArgsStruct *pArgs - Ptr to global args struct
// LPCTSTR pszEncryptedData - The encrypted data
// DWORD dwEncryptionType - The encryption type of the data
// BOOL fReg - Password is disguised for registry storage
//
// Returns: LPTSTR - Ptr to a buffer containing the decrypted form of the password.
//
// History: nickball Created 5/22/98
//
//+----------------------------------------------------------------------------
LPBYTE DecryptPassword( ArgsStruct *pArgs, LPBYTE pszEncryptedData, DWORD dwEncryptionType, DWORD dwEncryptedBytes, BOOL /*fReg*/, LPSTR pszSubKey) { MYDBGASSERT(pArgs); MYDBGASSERT(pszEncryptedData); DWORD dwDecryptedBufferLen; LPBYTE pszDecryptedData = NULL;
if (NULL == pArgs || NULL == pszEncryptedData) { return NULL; }
//
// It is not safe to call InitSecure more than once
//
if (!pArgs->fInitSecureCalled) { pArgs->fInitSecureCalled = TRUE; InitSecure(FALSE); // don't use fast encryption anymore
}
if (DecryptData(pszEncryptedData, dwEncryptedBytes, &pszDecryptedData, &dwDecryptedBufferLen, dwEncryptionType, #if defined(DEBUG) && defined(DEBUG_MEM)
(PFN_CMSECUREALLOC)AllocDebugMem, // Give the DEBUG_MEM version of alloc/free
(PFN_CMSECUREFREE)FreeDebugMem, // Not quit right, AllocDebugMem takes 3 param
pszSubKey))
#else
(PFN_CMSECUREALLOC)CmMalloc, (PFN_CMSECUREFREE)CmFree, pszSubKey)) #endif
{ return pszDecryptedData; }
return NULL; }
//+----------------------------------------------------------------------------
//
// Function: TranslateUserDataID
//
// Synopsis: Wrapper to map user data ID to string name of .CMP entry
//
// Arguments: UINT uiDataID - UserInfo data ID to be translated
//
// Returns: LPCTSTR - Ptr to a constant containing the .CMP entry flag
//
// History: nickball Created 10/13/98
//
//+----------------------------------------------------------------------------
LPCTSTR TranslateUserDataID(UINT uiDataID) { switch(uiDataID) {
case UD_ID_USERNAME: return c_pszCmEntryUserName; break;
case UD_ID_INET_USERNAME: return c_pszCmEntryInetUserName; break;
case UD_ID_DOMAIN: return c_pszCmEntryDomain; break;
case UD_ID_PASSWORD: return c_pszCmEntryPassword; break;
case UD_ID_INET_PASSWORD: return c_pszCmEntryInetPassword; break;
case UD_ID_NOPROMPT: return c_pszCmEntryNoPrompt; break;
case UD_ID_REMEMBER_PWD: return c_pszCmEntryRememberPwd; break; case UD_ID_REMEMBER_INET_PASSWORD: return c_pszCmEntryRememberInetPwd; break; case UD_ID_PCS: return c_pszCmEntryPcs; break;
case UD_ID_ACCESSPOINTENABLED: return c_pszCmEntryAccessPointsEnabled; break;
case UD_ID_CURRENTACCESSPOINT: return c_pszCmEntryCurrentAccessPoint; break;
default: break; }
MYDBGASSERT(FALSE); return NULL; }
|