|
|
// ServMigr.cpp : Implementation of CServMigr
#include "stdafx.h"
#include "ScmMigr.h"
#include "ServMigr.h"
#include "ErrDct.hpp"
#include "ResStr.h"
#include "Common.hpp"
#include "PWGen.hpp"
#include "EaLen.hpp"
#include "TReg.hpp"
#include "TxtSid.h"
#include "ARExt_i.c"
#include <lm.h>
#include <dsgetdc.h>
//#import "\bin\McsVarSetMin.tlb" no_namespace, named_guids
//#import "\bin\DBManager.tlb" no_namespace, named_guids
//#import "\bin\McsDctWorkerObjects.tlb" no_namespace, named_guids
#import "VarSet.tlb" no_namespace, named_guids rename("property", "aproperty")
//#import "DBMgr.tlb" no_namespace, named_guids //already #imported in ServMigr.h
#import "WorkObj.tlb" no_namespace, named_guids
TErrorDct err; StringLoader gString;
#define BLOCK_SIZE 160
#define BUFFER_SIZE 400
#define SvcAcctStatus_NotMigratedYet 0
#define SvcAcctStatus_DoNotUpdate 1
#define SvcAcctStatus_Updated 2
#define SvcAcctStatus_UpdateFailed 4
#define SvcAcctStatus_NeverAllowUpdate 8
/////////////////////////////////////////////////////////////////////////////
// CServMigr
STDMETHODIMP CServMigr::ProcessUndo(/*[in]*/ IUnknown * pSource, /*[in]*/ IUnknown * pTarget, /*[in]*/ IUnknown * pMainSettings, /*[in, out]*/ IUnknown ** pPropToSet) { return E_NOTIMPL; }
STDMETHODIMP CServMigr::PreProcessObject(/*[in]*/ IUnknown * pSource, /*[in]*/ IUnknown * pTarget, /*[in]*/ IUnknown * pMainSettings, /*[in, out]*/ IUnknown ** pPropToSet) { return S_OK; }
STDMETHODIMP CServMigr::ProcessObject( /*[in]*/ IUnknown * pSource, /*[in]*/ IUnknown * pTarget, /*[in]*/ IUnknown * pMainSettings, /*[in,out]*/IUnknown ** ppPropsToSet ) { HRESULT hr = S_OK; // BOOL bFailedToUpdateOne = FALSE;
WCHAR domAccount[500]; WCHAR domTgtAccount[500]; _bstr_t domain; _bstr_t account; IVarSetPtr pVarSet(pMainSettings); IIManageDBPtr pDB; _bstr_t logfile; _bstr_t srcComputer; _bstr_t tgtComputer; _bstr_t tgtAccount; _bstr_t tgtDomain; IVarSetPtr pData(CLSID_VarSet); IUnknown * pUnk = NULL; DWORD rc = 0; _bstr_t sIntraForest; BOOL bIntraForest = FALSE; WCHAR * lastOperation = NULL;
try { logfile = pVarSet->get(GET_BSTR(DCTVS_Options_Logfile)); lastOperation = L"Get Log file name"; if ( logfile.length() ) { err.LogOpen(logfile,1); lastOperation = L"Open log"; } pDB = pVarSet->get(GET_BSTR(DCTVS_DBManager)); lastOperation = L"Got DBManager pointer"; if ( pDB != NULL ) { lastOperation = L"DBManager is not null"; // Check to see if this account is referenced in the service accounts table
domain = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain)); tgtDomain = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain)); account = pVarSet->get(GET_BSTR(DCTVS_CopiedAccount_SourceSam)); tgtAccount = pVarSet->get(GET_BSTR(DCTVS_CopiedAccount_TargetSam)); srcComputer = pVarSet->get(GET_BSTR(DCTVS_Options_SourceServer)); tgtComputer = pVarSet->get(GET_BSTR(DCTVS_Options_TargetServer)); sIntraForest = pVarSet->get(GET_BSTR(DCTVS_Options_IsIntraforest)); lastOperation = L"got names from varset"; if ( ! UStrICmp((WCHAR*)sIntraForest,GET_STRING(IDS_YES)) ) { // for intra-forest migration we are moving, not copying, so we don't need to update the password
lastOperation = L"checking whether this migration is intraforest"; // Actually, it turns out that ChangeServiceConfig will not let us update just the service account
// and not the passord, so we'll have to go ahead and change the password for the service ac
//bIntraForest = TRUE;
} //if the SAM account name has a " character in it, it cannot be a service
//account, and therefore we leave
if (wcschr(account, L'\"')) return S_OK;
lastOperation = L"preparing to build domain\\username strings"; swprintf(domAccount,L"%s\\%s",(WCHAR*)domain,(WCHAR*)account); swprintf(domTgtAccount,L"%s\\%s",(WCHAR*)tgtDomain,(WCHAR*)tgtAccount); lastOperation = L"done building domain\\username strings"; } }catch (... ) { err.DbgMsgWrite(ErrE,L"Exception!...LastOperation=%ls",lastOperation); } try { hr = pData->QueryInterface(IID_IUnknown,(void**)&pUnk); lastOperation = L"Got IUnknown pointer to varset"; if ( SUCCEEDED(hr) ) { lastOperation = L"Checking database for this account"; hr = pDB->raw_GetServiceAccount(SysAllocString(domAccount),&pUnk); lastOperation = L"Got service account info"; } } catch ( ... ) { err.DbgMsgWrite(ErrE,L"Exception!...lastOperation=%ls",lastOperation); } try { if ( SUCCEEDED(hr) ) { lastOperation = L"preparing to check service account info"; pData = pUnk; lastOperation = L"freeing old pointer"; pUnk->Release(); lastOperation = L"freed old pointer"; // remove the password must change flag, if set
USER_INFO_2 * uInfo = NULL; DWORD parmErr = 0; WCHAR password[LEN_Password]; long entries = pData->get("ServiceAccountEntries"); lastOperation = L"got entry count"; if ( (entries != 0) && !bIntraForest ) // if we're moving the account, don't mess with its properties
{ lastOperation = L"getting target user info"; rc = NetUserGetInfo(tgtComputer,tgtAccount,2,(LPBYTE*)&uInfo); lastOperation = L"got target user info"; if ( ! rc ) { // generate a new, strong, 14 character password for this account,
// and set the password to not expire
lastOperation = L"generating password"; EaPasswordGenerate(3,3,3,3,6,14,password,DIM(password)); lastOperation = L"generated password"; uInfo->usri2_flags |= (UF_DONT_EXPIRE_PASSWD); lastOperation = L"updating flags"; uInfo->usri2_password = password; lastOperation = L"setting user info"; rc = NetUserSetInfo(tgtComputer,tgtAccount,2,(LPBYTE)uInfo,&parmErr); lastOperation = L"set user info"; if ( ! rc ) { lastOperation = L"writing log messages"; err.MsgWrite(0,DCT_MSG_REMOVED_PWDCHANGE_FLAG_S,(WCHAR*)tgtAccount); lastOperation = L"writing log messages2"; err.MsgWrite(0,DCT_MSG_PWGENERATED_S,(WCHAR*)tgtAccount); lastOperation = L"wrote log messages"; // write the password to the password log file and mark this account, so that the
// SetPassword extension will not reset the password again.
pVarSet->put(GET_BSTR(DCTVS_CopiedAccount_DoNotUpdatePassword),account); lastOperation = L"put flag into varset"; _bstr_t sFileName = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_PasswordFile)); lastOperation = L"got name for password file"; if ( !m_bTriedToOpenFile ) { lastOperation = L"trying to open password file"; m_bTriedToOpenFile = true; lastOperation = L"set password file flag"; // we should see if the varset specifies a file name
if ( sFileName.length() > 0 ) { lastOperation = L"password file has a name"; // we have the file name so lets open it and save the handle.
m_passwordLog.LogOpen(sFileName, TRUE, 1); lastOperation = L"opened password file"; } //failure to get to password file so store it elsewhere and
//post that new file location in the migration log
if (!m_passwordLog.IsOpen() ) { WCHAR sPasswordFile[MAX_PATH]; if (GetDirectory(sPasswordFile))//place log in default log dir
wcscat(sPasswordFile, L"Logs\\passwords.txt"); else wcscpy(sPasswordFile, L"c:\\passwords.txt"); m_passwordLog.LogOpen(sPasswordFile, TRUE, 1);//open this log file
if ( m_passwordLog.IsOpen() ) err.MsgWrite(0,DCT_MSG_NEW_PASSWORD_LOG_S,(WCHAR*)sFileName,sPasswordFile); } } lastOperation = L"done with pwd file opening"; // Log the new password in the password log.
if ( m_passwordLog.IsOpen() ) { lastOperation = L"preparing to write to password file"; m_passwordLog.MsgWrite(L"%ls,%ls",(WCHAR*)tgtAccount,password); lastOperation = L"wrote to password file"; } } lastOperation = L"done with user set info"; uInfo->usri2_password = NULL; lastOperation = L"cleared password property"; NetApiBufferFree(uInfo); lastOperation = L"freed buffer"; } lastOperation = L"done with get user info"; if ( rc ) { lastOperation = L"writing error message"; err.SysMsgWrite(ErrE,rc,DCT_MSG_REMOVED_PWDCHANGE_FLAG_FAILED_SD,(WCHAR*)tgtAccount,rc); lastOperation = L"done writing error message"; } } if (entries != 0 ) { lastOperation = L"There are some entries"; try { if ( ! rc ) { lastOperation = L"no errors"; WCHAR strSID[200] = L""; BYTE sid[200]; WCHAR domain[LEN_Domain]; SID_NAME_USE snu; DWORD lenSid = DIM(sid); DWORD lenDomain = DIM(domain); DWORD lenStrSid = DIM(strSID);
lastOperation = L"Looking up account name"; if ( LookupAccountName(tgtComputer,tgtAccount,sid,&lenSid,domain,&lenDomain,&snu) ) { lastOperation = L"getting txt for sid"; if ( GetTextualSid(sid,strSID,&lenStrSid) ) { lastOperation = L"got txt for sid"; // for each reference to the service account, update the SCM
// for intra-forest migration, don't update the password
if ( bIntraForest ) UpdateSCMs(pData,domTgtAccount,NULL,strSID,pDB); else UpdateSCMs(pData,domTgtAccount,password,strSID,pDB); lastOperation = L"did scm updates"; } else { lastOperation = L"didn't get text for sid"; err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_CANNOT_FIND_ACCOUNT_SSD,tgtAccount,tgtComputer,GetLastError()); } } else { lastOperation = L"didn't find account name"; err.SysMsgWrite(ErrE,GetLastError(),DCT_MSG_CANNOT_FIND_ACCOUNT_SSD,tgtAccount,tgtComputer,GetLastError()); lastOperation = L"wrote LookupAccountName error message"; } } } catch(...) { err.DbgMsgWrite(ErrE,L"Exception!, last=%ls",lastOperation); } lastOperation = L"123"; } lastOperation = L"444444"; lastOperation = L"656346"; } else { lastOperation = L"234234242"; err.SysMsgWrite(ErrE,E_FAIL,DCT_MSG_DB_OBJECT_CREATE_FAILED_D,E_FAIL); lastOperation = L"asdfsadf"; } lastOperation = L"ddddd"; err.LogClose(); } catch (... ) { err.DbgMsgWrite(ErrE,L"An exception occurred. LastOperation=%ls",lastOperation); } return S_OK; }
STDMETHODIMP CServMigr::get_sDesc(/*[out, retval]*/ BSTR *pVal) { (*pVal) = SysAllocString(L"Updates SCM entries for services using migrated accounts."); return S_OK; }
STDMETHODIMP CServMigr::put_sDesc(/*[in]*/ BSTR newVal) { return E_NOTIMPL; }
STDMETHODIMP CServMigr::get_sName(/*[out, retval]*/ BSTR *pVal) { (*pVal) = SysAllocString(L"Generic Service Account Migration"); return S_OK; }
STDMETHODIMP CServMigr::put_sName(/*[in]*/ BSTR newVal) { return E_NOTIMPL; }
DWORD CServMigr::DoUpdate( WCHAR const * account, WCHAR const * password, WCHAR const * strSid, WCHAR const * computer, WCHAR const * service, BOOL bNeedToGrantLOS ) { DWORD rc = 0; IUserRightsPtr pRights; WCHAR const * ppassword = password;
// if password is empty, set it to NULL
if ( ppassword && ppassword[0] == 0 ) { ppassword = NULL; } else if ( !UStrCmp(password,L"NULL") ) { ppassword = NULL; } // only try to update entries that we need to be updating
// try to connect to the SCM on this machine
rc = pRights.CreateInstance(CLSID_UserRights); if ( FAILED(rc) ) { pRights = NULL; } SC_HANDLE pScm = OpenSCManager(computer, NULL, SC_MANAGER_ALL_ACCESS ); if ( pScm ) { // grant the logon as a service right to the target account
if ( pRights != NULL ) { if ( bNeedToGrantLOS ) { rc = pRights->raw_AddUserRight(SysAllocString(computer),SysAllocString(strSid),SysAllocString(L"SeServiceLogonRight")); if ( rc ) { err.SysMsgWrite(ErrE,rc,DCT_MSG_LOS_GRANT_FAILED_SSD, account,(WCHAR*)computer,rc); } else { err.MsgWrite(0,DCT_MSG_LOS_GRANTED_SS, account,(WCHAR*)computer); } } }
SC_HANDLE pService = OpenService(pScm,service,SERVICE_ALL_ACCESS);
if ( pService ) { int nCnt = 0; // update the account and password for the service
while ( !ChangeServiceConfig(pService, SERVICE_NO_CHANGE, // dwServiceType
SERVICE_NO_CHANGE, // dwStartType
SERVICE_NO_CHANGE, // dwErrorControl
NULL, // lpBinaryPathName
NULL, // lpLoadOrderGroup
NULL, // lpdwTagId
NULL, // lpDependencies
account, // lpServiceStartName
ppassword, // lpPassword
NULL) && nCnt < 5) // lpDisplayName
{ nCnt++; Sleep(500); } if ( nCnt < 5 ) { err.MsgWrite(0,DCT_MSG_UPDATED_SCM_ENTRY_SS,(WCHAR*)computer,(WCHAR*)service); } else { rc = GetLastError(); } CloseServiceHandle(pService); } CloseServiceHandle(pScm); } else { rc = GetLastError(); } return rc; }
BOOL CServMigr::UpdateSCMs( IUnknown * pVS, WCHAR const * account, WCHAR const * password, WCHAR const * strSid, IIManageDB * pDB ) { BOOL bGotThemAll = TRUE; IVarSetPtr pVarSet = pVS; LONG nCount = 0; WCHAR key[LEN_Path]; _bstr_t computer; _bstr_t service; long status; DWORD rc = 0; BOOL bFirst = TRUE; WCHAR prevComputer[LEN_Path] = L""; try { nCount = pVarSet->get("ServiceAccountEntries"); for ( long i = 0 ; i < nCount ; i++ ) { swprintf(key,L"Computer.%ld",i); computer = pVarSet->get(key); swprintf(key,L"Service.%ld",i); service = pVarSet->get(key); swprintf(key,L"ServiceAccountStatus.%ld",i); status = pVarSet->get(key); if ( status == SvcAcctStatus_NotMigratedYet || status == SvcAcctStatus_UpdateFailed ) { if ( UStrICmp(prevComputer,(WCHAR*)computer) ) { bFirst = TRUE; // reset the 'first' flag when the computer changes
} try { rc = DoUpdate(account,password,strSid,computer,service,bFirst/*only grant SeServiceLogonRight once per account*/); bFirst = FALSE; safecopy(prevComputer,(WCHAR*)computer); } catch (...) { err.DbgMsgWrite(ErrE,L"Exception!"); err.DbgMsgWrite(0,L"Updating %ls on %ls",(WCHAR*)service,(WCHAR*)computer); err.DbgMsgWrite(0,L"Account=%ls, SID=%ls",(WCHAR*)account,(WCHAR*)strSid); rc = E_FAIL; } if (! rc ) { // the update was successful
pDB->raw_SetServiceAcctEntryStatus(computer,service,SysAllocString(account),SvcAcctStatus_Updated); } else { // couldn't connect to this one -- we will need to save this account's password
// in our encrypted storage
pDB->raw_SetServiceAcctEntryStatus(computer,service,SysAllocString(account),SvcAcctStatus_UpdateFailed); bGotThemAll = FALSE; SaveEncryptedPassword(computer,service,account,password); err.SysMsgWrite(ErrE,rc,DCT_MSG_UPDATE_SCM_ENTRY_FAILED_SSD,(WCHAR*)computer,(WCHAR*)service,rc); } } } } catch ( ... ) { err.DbgMsgWrite(ErrE,L"Exception!"); } return bGotThemAll; }
HRESULT CServMigr::SaveEncryptedPassword( WCHAR const * server, WCHAR const * service, WCHAR const * account, WCHAR const * password ) { HRESULT hr = S_OK; TNodeListEnum e; TEntryNode* pNode;
// if entry exists...
for (pNode = (TEntryNode*)e.OpenFirst(&m_List); pNode; pNode = (TEntryNode*)e.Next()) { if (_wcsicmp(pNode->GetComputer(), server) == 0) { if (_wcsicmp(pNode->GetService(), service) == 0) { if (_wcsicmp(pNode->GetAccount(), account) == 0) { // update password
pNode->SetPassword(password); break; } } } }
// else...
if (pNode == NULL) { // insert new entry
pNode = new TEntryNode(server, service, account, password);
if (pNode) { m_List.InsertBottom(pNode); } else { hr = E_OUTOFMEMORY; } }
return hr; }
//////////////////////////////////////////////////////////////////////////////////////
///
/// TEntryList implementation of secure storage for service account passwords
///
///
//////////////////////////////////////////////////////////////////////////////////////
DWORD TEntryList::LoadFromFile(WCHAR const * filename) { DWORD rc = 0; FILE * hSource = NULL; HCRYPTPROV hProv = 0; HCRYPTKEY hKey = 0;
BYTE pbBuffer[BLOCK_SIZE]; WCHAR strData[BLOCK_SIZE * 5] = { 0 }; DWORD dwCount; int eof = 0; WCHAR fullpath[LEN_Path];
BYTE *pbKeyBlob = NULL; DWORD dwBlobLen;
// Get our install directory from the registry, and then append the filename
HKEY hRegKey; DWORD type; DWORD lenValue = (sizeof fullpath);
rc = RegOpenKey(HKEY_LOCAL_MACHINE,L"Software\\Mission Critical Software\\DomainAdmin",&hRegKey); if ( ! rc ) { rc = RegQueryValueEx(hRegKey,L"Directory",0,&type,(LPBYTE)fullpath,&lenValue); if (! rc ) { UStrCpy(fullpath+UStrLen(fullpath),filename); } RegCloseKey(hRegKey); } // Open the source file.
if((hSource = _wfopen(fullpath,L"rb"))==NULL) { rc = GetLastError(); goto done; }
// acquire handle to key container which must exist
if ((hProv = AcquireContext(true)) == 0) { rc = GetLastError(); goto done; }
// Read the key blob length from the source file and allocate it to memory.
fread(&dwBlobLen, sizeof(DWORD), 1, hSource); if(ferror(hSource) || feof(hSource)) { rc = GetLastError(); goto done; }
if((pbKeyBlob = (BYTE*)malloc(dwBlobLen)) == NULL) { rc = GetLastError(); goto done; }
// Read the key blob from the source file.
fread(pbKeyBlob, 1, dwBlobLen, hSource); if(ferror(hSource) || feof(hSource)) { rc = GetLastError(); goto done; }
// Import the key blob into the CSP.
if(!CryptImportKey(hProv, pbKeyBlob, dwBlobLen, 0, 0, &hKey)) { rc = GetLastError(); goto done; } // Decrypt the source file and load the list
do { // Read up to BLOCK_SIZE bytes from source file.
dwCount = fread(pbBuffer, 1, BLOCK_SIZE, hSource); if(ferror(hSource)) { rc = GetLastError(); goto done; } eof=feof(hSource);
// Decrypt the data.
if(!CryptDecrypt(hKey, 0, eof, 0, pbBuffer, &dwCount)) { rc = GetLastError(); goto done; } // Read any complete entries from the buffer
// first, add the buffer contents to any leftover information we had read from before
WCHAR * curr = strData; long len = UStrLen(strData); WCHAR * nl = NULL; WCHAR computer[LEN_Computer]; WCHAR service[LEN_Service]; WCHAR account[LEN_Account]; WCHAR password[LEN_Password];
wcsncpy(strData + len,(WCHAR*)pbBuffer, dwCount / sizeof(WCHAR)); strData[len + (dwCount / sizeof(WCHAR))] = 0; do { nl = wcschr(curr,L'\n'); if ( nl ) { *nl = 0; if ( swscanf(curr,L" %[^\t]\t%[^\t]\t%[^\t]\t%[^\t]\n",computer,service,account,password) ) { TEntryNode * pNode = new TEntryNode(computer,service,account,password); InsertBottom(pNode); } else { rc = E_FAIL; break; } // go on to the next entry
curr = nl + 1; } } while ( nl ); // there may be a partial record left in the buffer
// if so, save it for the next read
if ( (*curr) != 0 ) { memmove(strData,curr,( 1 + UStrLen(curr) ) * (sizeof WCHAR)); }
} while(!feof(hSource));
done:
// Clean up
if(pbKeyBlob) free(pbKeyBlob);
if(hKey != 0) CryptDestroyKey(hKey);
if(hProv != 0) CryptReleaseContext(hProv, 0);
if(hSource != NULL) fclose(hSource);
return rc; }
DWORD TEntryList::SaveToFile(WCHAR const * filename) { DWORD rc = 0; BYTE pbBuffer[BUFFER_SIZE]; DWORD dwCount; FILE * hDest; BYTE * pbKeyBlob = NULL; DWORD dwBlobLen; HCRYPTPROV hProv = 0; HCRYPTKEY hKey = 0; HCRYPTKEY hXchgKey = 0; TEntryNode * pNode; TNodeListEnum e; WCHAR fullpath[LEN_Path]; DWORD dwBlockSize; DWORD cbBlockSize = sizeof(dwBlockSize); DWORD dwPaddedCount;
// Open the destination file.
HKEY hRegKey; DWORD type; DWORD lenValue = (sizeof fullpath);
rc = RegOpenKey(HKEY_LOCAL_MACHINE,L"Software\\Mission Critical Software\\DomainAdmin",&hRegKey); if ( ! rc ) { rc = RegQueryValueEx(hRegKey,L"Directory",0,&type,(LPBYTE)fullpath,&lenValue); if (! rc ) { UStrCpy(fullpath+UStrLen(fullpath),filename); } RegCloseKey(hRegKey); } if( (hDest = _wfopen(fullpath,L"wb")) == NULL) { rc = GetLastError(); goto done; }
// acquire handle to key container
if ((hProv = AcquireContext(false)) == 0) { rc = GetLastError(); goto done; }
// Attempt to get handle to exchange key.
if(!CryptGetUserKey(hProv,AT_KEYEXCHANGE,&hKey)) { if(GetLastError()==NTE_NO_KEY) { // Create key exchange key pair.
if(!CryptGenKey(hProv,AT_KEYEXCHANGE,0,&hKey)) { rc = GetLastError(); goto done; } } else { rc = GetLastError(); goto done; } } CryptDestroyKey(hKey); CryptReleaseContext(hProv,0);
// acquire handle to key container
if ((hProv = AcquireContext(false)) == 0) { rc = GetLastError(); goto done; }
// Get a handle to key exchange key.
if(!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey)) { rc = GetLastError(); goto done; }
// Create a random block cipher session key.
if(!CryptGenKey(hProv, CALG_RC2, CRYPT_EXPORTABLE, &hKey)) { rc = GetLastError(); goto done; }
// Determine the size of the key blob and allocate memory.
if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, NULL, &dwBlobLen)) { rc = GetLastError(); goto done; }
if((pbKeyBlob = (BYTE*)malloc(dwBlobLen)) == NULL) { rc = ERROR_NOT_ENOUGH_MEMORY; goto done; }
// Export the key into a simple key blob.
if(!CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwBlobLen)) { rc = GetLastError(); free(pbKeyBlob); goto done; }
// Write the size of the key blob to the destination file.
fwrite(&dwBlobLen, sizeof(DWORD), 1, hDest);
if(ferror(hDest)) { rc = GetLastError(); free(pbKeyBlob); goto done; }
// Write the key blob to the destination file.
fwrite(pbKeyBlob, 1, dwBlobLen, hDest); if(ferror(hDest)) { rc = GetLastError(); free(pbKeyBlob); goto done; }
// Free memory.
free(pbKeyBlob);
// get key cipher's block length in bytes
if (CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE*)&dwBlockSize, &cbBlockSize, 0)) { dwBlockSize /= 8; } else { rc = GetLastError(); goto done; }
// Encrypt the item list and write it to the destination file.
for ( pNode = (TEntryNode*)e.OpenFirst(this); pNode ; pNode = (TEntryNode *)e.Next() ) { // copy an item into the buffer in the following format:
// Computer\tService\tAccount\tPassword
if ( pNode->GetPassword() && *pNode->GetPassword() ) { swprintf((WCHAR*)pbBuffer,L"%s\t%s\t%s\t%s\n",pNode->GetComputer(),pNode->GetService(),pNode->GetAccount(),pNode->GetPassword()); } else { swprintf((WCHAR*)pbBuffer,L"%s\t%s\t%s\t%s\n",pNode->GetComputer(),pNode->GetService(),pNode->GetAccount(),L"NULL"); }
dwCount = UStrLen((WCHAR*)pbBuffer) * (sizeof WCHAR) ;
// the buffer must be a multiple of the key cipher's block length
// NOTE: this algorithm assumes block length is multiple of sizeof(WCHAR)
if (dwBlockSize > 0) { // calculate next multiple greater than count
dwPaddedCount = ((dwCount + (dwBlockSize / 2)) / dwBlockSize) * dwBlockSize;
// pad buffer with space characters
WCHAR* pch = (WCHAR*)(pbBuffer + dwCount);
for (; dwCount < dwPaddedCount; dwCount += sizeof(WCHAR)) { *pch++ = L' '; } }
// Encrypt the data.
if(!CryptEncrypt(hKey, 0, (pNode->Next() == NULL) , 0, pbBuffer, &dwCount, BUFFER_SIZE)) { rc = GetLastError(); goto done; }
// Write the data to the destination file.
fwrite(pbBuffer, 1, dwCount, hDest); if(ferror(hDest)) { rc = GetLastError(); goto done; } }
done:
// Destroy the session key.
if(hKey != 0) CryptDestroyKey(hKey);
// Destroy the key exchange key.
if(hXchgKey != 0) CryptDestroyKey(hXchgKey);
// Release the provider handle.
if(hProv != 0) CryptReleaseContext(hProv, 0);
// Close destination file.
if(hDest != NULL) fclose(hDest);
return rc; }
// AcquireContext Method
//
// acquire handle to key container within cryptographic service provider (CSP)
//
HCRYPTPROV TEntryList::AcquireContext(bool bContainerMustExist) { HCRYPTPROV hProv = 0;
#define KEY_CONTAINER_NAME _T("A69904BC349C4CFEAAEAB038BAB8C3B1")
if (bContainerMustExist) { // first try Microsoft Enhanced Cryptographic Provider
if (!CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { if (GetLastError() == NTE_KEYSET_NOT_DEF) { // then try Microsoft Base Cryptographic Provider
CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET); } } } else { // first try Microsoft Enhanced Cryptographic Provider
if (!CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { DWORD dwError = GetLastError();
if ((dwError == NTE_BAD_KEYSET) || (dwError == NTE_KEYSET_NOT_DEF)) { // then try creating key container in enhanced provider
if (!CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET|CRYPT_NEWKEYSET)) { dwError = GetLastError();
if (dwError == NTE_KEYSET_NOT_DEF) { // then try Microsoft Base Cryptographic Provider
if (!CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET)) { dwError = GetLastError();
if ((dwError == NTE_BAD_KEYSET) || (dwError == NTE_KEYSET_NOT_DEF)) { // finally try creating key container in base provider
CryptAcquireContext(&hProv, KEY_CONTAINER_NAME, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_MACHINE_KEYSET|CRYPT_NEWKEYSET); } } } } } } }
return hProv; }
STDMETHODIMP CServMigr::TryUpdateSam(BSTR computer,BSTR service,BSTR account) { HRESULT hr = S_OK; // Find the entry in the list, and perform the update
TNodeListEnum e; TEntryNode * pNode; BOOL bFound = FALSE;
for ( pNode = (TEntryNode*)e.OpenFirst(&m_List) ; pNode ; pNode = (TEntryNode*)e.Next() ) { if ( !UStrICmp(computer,pNode->GetComputer()) && !UStrICmp(service,pNode->GetService()) && !UStrICmp(account,pNode->GetAccount()) ) { // found it!
bFound = TRUE; hr = TryUpdateSamWithPassword(computer,service,account,SysAllocString(pNode->GetPassword()) ); break; } } if ( ! bFound ) { hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } return hr; }
STDMETHODIMP CServMigr::TryUpdateSamWithPassword(BSTR computer,BSTR service,BSTR domAccount,BSTR password) { DWORD rc = 0; WCHAR domain[LEN_Domain]; WCHAR dc[LEN_Computer]; WCHAR account[LEN_Account]; WCHAR domStr[LEN_Domain]; BYTE sid[100]; WCHAR strSid[200]; WCHAR * pSlash = wcschr(domAccount,L'\\'); DOMAIN_CONTROLLER_INFO * pInfo = NULL; SID_NAME_USE snu; DWORD lenSid = DIM(sid); DWORD lenDomStr = DIM(domStr); DWORD lenStrSid = DIM(strSid);
// split out the domain and account names
if ( pSlash ) { // UStrCpy(domain,domAccount,pSlash - domAccount + 1);
UStrCpy(domain,domAccount,(int)(pSlash - domAccount + 1)); UStrCpy(account,pSlash+1); rc = DsGetDcName(NULL,domain,NULL,NULL,0,&pInfo); if (! rc ) { safecopy(dc,pInfo->DomainControllerName); NetApiBufferFree(pInfo); }
// get the SID for the target account
if ( LookupAccountName(dc,account,sid,&lenSid,domStr,&lenDomStr,&snu) ) { GetTextualSid(sid,strSid,&lenStrSid);
rc = DoUpdate(domAccount,password,strSid,computer,service,TRUE); } else { rc = GetLastError(); } } else { rc = ERROR_NOT_FOUND; } return HRESULT_FROM_WIN32(rc); }
BOOL // ret - TRUE if directory found
CServMigr::GetDirectory( WCHAR * filename // out - string buffer to store directory name
) { DWORD rc = 0; BOOL bFound = FALSE; TRegKey key;
rc = key.OpenRead(GET_STRING(IDS_HKLM_DomainAdmin_Key),HKEY_LOCAL_MACHINE);
if ( ! rc ) {
rc = key.ValueGetStr(L"Directory",filename,MAX_PATH);
if ( ! rc ) { if ( *filename ) bFound = TRUE; } } key.Close();
return bFound; }
|