Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1788 lines
55 KiB

/*Copyright (c) 1995-1999, Mission Critical Software, Inc. All rights reserved.
===============================================================================
Module - SecTranslator.cpp
System - Domain Consolidation Toolkit.
Author - Christy Boles
Created - 97/06/27
Description - COM object that controls the security translation process.
Reads the settings for the translation and performs the necessary
operations.
Updates -
===============================================================================
*/
// SecTranslator.cpp : Implementation of CSecTranslator
#include "stdafx.h"
#include "WorkObj.h"
#include "SecTrans.h"
#include "Mcs.h"
#include "EaLen.hpp"
#include "BkupRstr.hpp"
#include "exchange.hpp"
#include "ErrDct.hpp"
#include "MapiProf.hpp"
#include "SDStat.hpp"
#include "sd.hpp"
#include "SecObj.hpp"
#include "LGTrans.h"
#include "RightsTr.h"
#include "RegTrans.h"
#include "RebootU.h"
#include "TReg.hpp"
#include "TxtSid.h"
#include "LSAUtils.h"
//#import "\bin\DBManager.tlb" no_namespace, named_guids
#import "DBMgr.tlb" no_namespace, named_guids
#include "varset_i.c"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#ifndef IStatusObjPtr
_COM_SMARTPTR_TYPEDEF(IStatusObj, __uuidof(IStatusObj));
#endif
/////////////////////////////////////////////////////////////////////////////
// CSecTranslator
#define BACKUP_FAILED 5
#define BAD_PATH 6
#define BAD_LOG 2
#define LEN_SID 200
extern TErrorDct err;
// Defined in EnumVols.cpp
bool // ret -true if name begins with "\\" has at least 3 total chars, and no other '\'
IsMachineName(
const LPWSTR name // in -possible machine name to check
);
DWORD // ret- OS return code
GetProgramFilesDirectory(
WCHAR * directory, // out- location of program files directory
WCHAR const * computer // in - computer to find PF directory on
)
{
TRegKey hklm;
TRegKey key;
DWORD rc;
rc = hklm.Connect(HKEY_LOCAL_MACHINE,computer);
if ( ! rc )
{
rc = key.Open(L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",&hklm);
}
if ( !rc )
{
rc = key.ValueGetStr(L"ProgramFilesDir",directory,MAX_PATH * (sizeof WCHAR));
}
return rc;
}
BOOL
IsLocallyInstalled()
{
BOOL bFound;
TRegKey key;
DWORD rc;
rc = key.Open(GET_STRING(IDS_HKLM_DomainAdmin_Key));
if ( ! rc )
{
bFound = TRUE;
}
else
{
bFound = FALSE;
}
return bFound;
}
DWORD // ret- OS return code
GetLocalMachineName(WCHAR * computer)
{
DWORD rc = 0;
WKSTA_INFO_100 * buf = NULL;
rc = NetWkstaGetInfo(NULL,100,(LPBYTE*)&buf);
if ( ! rc )
{
UStrCpy(computer,L"\\\\");
UStrCpy(computer+2,buf->wki100_computername);
NetApiBufferFree(buf);
}
return rc;
}
BOOL
IsThisDispatcherMachine(IVarSet * pVarSet)
{
BOOL bIsIt = FALSE;
_bstr_t dispatcher = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Server));
WCHAR localComputer[LEN_Computer] = L"";
GetLocalMachineName(localComputer);
if ( ! UStrICmp(dispatcher,localComputer) )
{
bIsIt = TRUE;
}
return bIsIt;
}
class TSession : public TNode
{
WCHAR server[LEN_Computer];
public:
TSession(WCHAR const * s) { safecopy(server,s); }
WCHAR const * ServerName() { return server;}
};
BOOL
CSecTranslator::EstablishASession(
WCHAR const * serverName // in - computer to establish a session to
)
{
BOOL bSuccess = TRUE;
TSession * pSession = new TSession(serverName);
if ( EstablishSession(serverName,m_domain,m_username,m_password,TRUE) )
{
m_ConnectionList.InsertBottom(pSession);
}
else
{
delete pSession;
bSuccess = FALSE;
err.SysMsgWrite(ErrW,GetLastError(),DCT_MSG_NO_SESSION_SD,serverName,GetLastError());
}
return bSuccess;
}
void
CSecTranslator::CleanupSessions()
{
TNodeListEnum e;
TSession * s;
TSession * snext;
for ( s = (TSession*)e.OpenFirst(&m_ConnectionList) ; s ; s = snext )
{
snext = (TSession*) e.Next();
m_ConnectionList.Remove(s);
// close the session
EstablishSession(s->ServerName(),NULL,NULL,NULL,FALSE);
delete s;
}
e.Close();
}
STDMETHODIMP
CSecTranslator::Process(
IUnknown * pWorkItem // in - varset describing translation options
)
{
HRESULT hr = S_OK;
IVarSetPtr pVarSet = pWorkItem;
IStatusObjPtr pStatus = pVarSet->get(GET_BSTR(DCTVS_StatusObject));
BOOL bReallyDoEverything = FALSE; // this (though not implemented yet) can be used
// to provide a way to override the default behavior
// of only processing file, etc. security when running as
// local system. This would allow selective translation of items
// on the local machine
_bstr_t text = pVarSet->get(GET_BSTR(DCTVS_Options_Logfile));
m_Args.LogFile(text);
// Open the log file
// use append mode since other processes may also be using this file
if ( ! err.LogOpen(m_Args.LogFile(),1 /*append*/,0) )
{
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
LoadSettingsFromVarSet(pVarSet);
// Set up the cache
TSDResolveStats stat(m_Args.Cache(),m_Args.PathList(),pVarSet);
if ( pStatus )
{
m_Args.Cache()->SetStatusObject(pStatus);
}
if ( m_Args.Cache()->IsTree() )
{
m_Args.Cache()->ToSorted();
}
m_Args.Cache()->SortedToScrambledTree();
m_Args.Cache()->Sort(&RidComp);
m_Args.Cache()->Balance();
m_Args.Cache()->UnCancel();
// Verify that the Cache got the source and target domain information it needs
if ( ! m_Args.Cache()->IsInitialized() )
{
err.MsgWrite(ErrS,DCT_MSG_NO_CACHE_INFO);
}
else
// if (1)
{
if ( m_Args.IsLocalSystem() || bReallyDoEverything )
{// Do the required translations
if ( m_Args.TranslateFiles() || m_Args.TranslateShares() || m_Args.TranslatePrinters() || m_Args.TranslateRecycler() )
{
// This runs the old FST code
pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_FST_OPERATION_TEXT));
DoResolution(&stat);
}
if ( m_Args.TranslateLocalGroups() )
{
pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_LGST_OPERATION_TEXT));
DoLocalGroupResolution(&stat);
}
if ( m_Args.TranslateUserRights() )
{
pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_URST_OPERATION_TEXT));
DoUserRightsTranslation(&stat);
}
if ( m_Args.TranslateRegistry() )
{
pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_REGST_OPERATION_TEXT));
GetBkupRstrPriv((WCHAR*)NULL);
GetPrivilege((WCHAR*)NULL,SE_SECURITY_NAME);
TranslateRegistry(NULL,&m_Args,m_Args.Cache(),&stat);
}
if ( m_Args.TranslateUserProfiles() )
{
GetBkupRstrPriv((WCHAR*)NULL);
GetPrivilege((WCHAR*)NULL,SE_SECURITY_NAME);
TranslateLocalProfiles(&m_Args,m_Args.Cache(),&stat);
}
}
else
{
// do exchange translation
if ( m_Args.TranslateMailboxes() || m_Args.TranslateContainers() )
{
// This will run the old EST code
pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),GET_BSTR(IDS_EST_OPERATION_TEXT));
DoExchangeResolution(&stat,pVarSet);
}
}
}
pVarSet->put(GET_BSTR(DCTVS_CurrentOperation),"");
ExportStatsToVarSet(pVarSet,&stat);
if ( *m_CacheFile )
{
BuildCacheFile(m_CacheFile);
}
// Record whether errors occurred
long level = pVarSet->get(GET_BSTR(DCTVS_Results_ErrorLevel));
if ( level < err.GetMaxSeverityLevel() )
{
pVarSet->put(GET_BSTR(DCTVS_Results_ErrorLevel),(LONG)err.GetMaxSeverityLevel());
}
err.LogClose();
CleanupSessions();
return hr;
}
void
CSecTranslator::LoadSettingsFromVarSet(
IVarSet * pVarSet // in - varset containing settings
)
{
MCSASSERT(pVarSet);
_bstr_t text;
_bstr_t text2;
DWORD val;
try
{
m_Args.Reset();
text = pVarSet->get(GET_BSTR(DCTVS_Options_LocalProcessingOnly));
if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
{
err.MsgWrite(0,DCT_MSG_LOCAL_MODE);
m_LocalOnly = TRUE;
m_Args.SetLocalMode(TRUE);
text = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomainSid));
safecopy(m_SourceSid,(WCHAR const *)text);
text = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomainSid));
safecopy(m_TargetSid,(WCHAR const *)text);
}
text = pVarSet->get(GET_BSTR(DCTVS_Options_SourceDomain));
m_Args.Source(text);
text = pVarSet->get(GET_BSTR(DCTVS_Options_TargetDomain));
m_Args.Target(text);
val = (LONG)pVarSet->get(GET_BSTR(DCTVS_Options_LogLevel));
if ( val )
m_Args.SetLogging(val);
val = (LONG)pVarSet->get(L"Security.DebugLogLevel");
if ( val )
m_Args.SetLogging(val);
text = pVarSet->get(GET_BSTR(DCTVS_Options_NoChange));
if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.SetWriteChanges(FALSE);
}
else
{
m_Args.SetWriteChanges(TRUE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslationMode));
if ( !UStrICmp(text,GET_STRING(IDS_Add)) )
{
m_Args.SetTranslationMode(ADD_SECURITY);
}
else if (! UStrICmp(text,GET_STRING(IDS_Replace)) )
{
m_Args.SetTranslationMode(REPLACE_SECURITY);
}
else if ( ! UStrICmp(text,GET_STRING(IDS_Remove)) )
{
m_Args.SetTranslationMode(REMOVE_SECURITY);
}
else
{
// Incorrect value - don't need to log this, just use replace
// the log will show replace as the translation mode
// err.MsgWrite(ErrE,DCT_MSG_BAD_TRANSLATION_MODE_S,(WCHAR*)text);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateFiles));
if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.TranslateFiles(TRUE);
}
else
{
m_Args.TranslateFiles(FALSE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateShares));
if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.TranslateShares(TRUE);
}
else
{
m_Args.TranslateShares(FALSE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslatePrinters));
if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.TranslatePrinters(TRUE);
}
else
{
m_Args.TranslatePrinters(FALSE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateUserProfiles));
if ( ! UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.TranslateUserProfiles(TRUE);
m_Args.TranslateRecycler(TRUE);
}
else
{
m_Args.TranslateUserProfiles(FALSE);
m_Args.TranslateRecycler(FALSE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateLocalGroups));
if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.TranslateLocalGroups(TRUE);
}
else
{
m_Args.TranslateLocalGroups(FALSE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateRegistry));
if (! UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.TranslateRegistry(TRUE);
}
else
{
m_Args.TranslateRegistry(FALSE);
}
val = (LONG)pVarSet->get(GET_BSTR(DCTVS_Servers_NumItems));
for ( int i = 0 ; i < (int)val ; i++ )
{
WCHAR key[MAX_PATH];
DWORD flags = 0;
_bstr_t bStr;
swprintf(key,GET_STRING(DCTVSFmt_Servers_D),i);
bStr = key;
text = pVarSet->get(bStr);
if ( text.length() )
{
m_Args.PathList()->AddPath(text,flags);
}
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_GatherInformation));
if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.Cache()->AddIfNotFound(TRUE);
m_Args.SetWriteChanges(FALSE);
m_Args.SetLogging(m_Args.LogSettings() & ~FILESTATS);
}
else
{
m_Args.Cache()->AddIfNotFound(FALSE);
}
// Exchange Security Translation settings
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateMailboxes));
if ( text.length() )
{
m_Args.TranslateMailboxes(TRUE);
safecopy(m_Container,(WCHAR*)text);
text = pVarSet->get(GET_BSTR(DCTVS_Security_MapiProfile));
safecopy(m_Profile,(WCHAR*)text);
}
else
{
m_Args.TranslateMailboxes(FALSE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateContainers));
if ( text.length() )
{
m_Args.TranslateContainers(TRUE);
if ( ((WCHAR*)text)[0] == L'\\' && ((WCHAR*)text)[1] == L'\\' )
safecopy(m_exchServer,(WCHAR*)text+2);
else
safecopy(m_exchServer,(WCHAR*)text);
}
else
{
m_Args.TranslateContainers(FALSE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_TranslateUserRights));
if ( !UStrICmp(text,GET_STRING(IDS_YES)) )
{
m_Args.TranslateUserRights(TRUE);
}
text = pVarSet->get(GET_BSTR(DCTVS_Security_BuildCacheFile));
if ( text.length() )
{
safecopy(m_CacheFile,(WCHAR*)text);
}
// Check for inconsistent arguments
// Load the cache
// There are 4 possible ways to populate the cache
// 1. Use the list from the migrated objects table in our database
// 2. We are given a list of accounts in the VarSet, under "Accounts.". This allows for renaming, but requires the most space
// 3. We are given an input file that was generated by AR, in "Accounts.InputFile". This also allows for renaming, with less overall memory use.
// 4. We are given a sid mapping, comma-seperated, file with source and target sids.
text = pVarSet->get(GET_BSTR(DCTVS_Security_BuildCacheFile));
text2 = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SecurityInputMOT));
//if list is in the migrated objects table
if ((!m_LocalOnly) && (!UStrICmp(text2,GET_STRING(IDS_YES))))
{
LoadMigratedObjects(pVarSet);
}
//else if a sid mapping file is being used
else if ((!m_LocalOnly) && (UStrICmp(text2,GET_STRING(IDS_YES))))
{
m_Args.SetUsingMapFile(TRUE); //set the arg flag to indicate use of map file
text2 = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SecurityMapFile));
LoadCacheFromMapFile(text2, pVarSet);
}
// took out the not because gather information sets this to false.
//else if ( !m_Args.Cache()->AddIfNotFound() ) // skip loading the cache if we're gathering information
else if ( m_Args.Cache()->AddIfNotFound() ) // skip loading the cache if we're gathering information
{
if ( m_LocalOnly )
{
m_Args.Cache()->SetSourceAndTargetDomainsWithSids(m_Args.Source(),m_SourceSid,m_Args.Target(),m_TargetSid);
}
else
{
m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
}
}
else
{
text = pVarSet->get(GET_BSTR(DCTVS_Accounts_InputFile));
if ( text.length() )
{
LoadCacheFromFile(text,pVarSet);
}
else
{
LoadCacheFromVarSet(pVarSet);
}
}
}
catch ( ... )
{
err.MsgWrite(ErrS,DCT_MSG_EXCEPTION_READING_VARSET);
throw;
}
}
void
CSecTranslator::ExportStatsToVarSet(
IVarSet * pVarSet, // in - varset to write stats to
TSDResolveStats * stat // in - object containing stats
)
{
_bstr_t filename;
_bstr_t domain = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Domain));
_bstr_t username = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_UserName));
_bstr_t password = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Password));
_bstr_t server = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Server));
_bstr_t share = pVarSet->get(GET_BSTR(DCTVS_Options_Credentials_Share));
BOOL bSessEstablished;
if ( username.length() && server.length() && share.length() )
{
bSessEstablished = EstablishSession(server, domain, username, password, TRUE);
}
filename = pVarSet->get(GET_BSTR(DCTVS_Security_ReportAccountReferences));
stat->Report(m_Args.LogSummary(),m_Args.LogAccountDetails(),m_Args.LogPathDetails());
if ( m_Args.NoChange() )
{
err.MsgWrite(0,DCT_MSG_NO_CHANGE_MODE);
}
stat->ReportToVarSet(pVarSet,m_Args.LogSettings() & SUMMARYSTATS);
if ( filename.length() )
{
err.MsgWrite(0,DCT_MSG_EXPORTING_ACCOUNT_REFS_S,(WCHAR*)filename);
m_Args.Cache()->ReportAccountReferences((WCHAR*)filename);
}
// if session was established, unestablish
if (bSessEstablished)
{
EstablishSession(server, domain, username, password, FALSE);
}
long level = pVarSet->get(GET_BSTR(DCTVS_Results_ErrorLevel));
if ( level < err.GetMaxSeverityLevel() )
{
pVarSet->put(GET_BSTR(DCTVS_Results_ErrorLevel),(LONG)err.GetMaxSeverityLevel());
}
}
void
CSecTranslator::DoResolution(
TSDResolveStats * stat // in - object to write translation stats to
)
{
// display confirmation message if writing changes
int result;
result = ResolveAll(&m_Args,stat);
}
void
CSecTranslator::DoLocalGroupResolution(
TSDResolveStats * stat // in - object to write translation stats to
)
{
DWORD rc;
TNodeListEnum tenum;
TPathNode * tnode;
if ( m_LocalOnly )
{
err.MsgWrite(0,DCT_MSG_TRANSLATING_LOCAL_GROUPS);
rc = TranslateLocalGroups(NULL,&m_Args,m_Args.Cache(),stat);
}
else
{ // Enumerate the machines in the pathlist
for (tnode = (TPathNode *)tenum.OpenFirst((TNodeList *)m_Args.PathList())
; tnode
; tnode = (TPathNode *)tenum.Next() )
{
if ( IsMachineName(tnode->GetPathName()) )
{
err.MsgWrite(0,DCT_MSG_TRANSLATING_LOCAL_GROUPS_ON_S,tnode->GetPathName());
rc = TranslateLocalGroups(tnode->GetPathName(),&m_Args,m_Args.Cache(),stat);
}
}
}
tenum.Close();
}
void
CSecTranslator::DoUserRightsTranslation(
TSDResolveStats * stat // in - object to write stats to
)
{
DWORD rc;
TNodeListEnum tenum;
TPathNode * tnode;
if ( m_LocalOnly )
{
err.MsgWrite(0,DCT_MSG_TRANSLATING_USER_RIGHTS);
rc = TranslateUserRights(NULL,&m_Args,m_Args.Cache(),stat);
}
else
{ // Enumerate the machines in the pathlist
for (tnode = (TPathNode *)tenum.OpenFirst((TNodeList *)m_Args.PathList())
; tnode
; tnode = (TPathNode *)tenum.Next() )
{
if ( IsMachineName(tnode->GetPathName()) )
{
err.MsgWrite(0,DCT_MSG_TRANSLATING_RIGHTS_ON_S,tnode->GetPathName());
rc = TranslateUserRights(tnode->GetPathName(),&m_Args,m_Args.Cache(),stat);
}
}
}
tenum.Close();
}
BOOL
CSecTranslator::LoadCacheFromVarSet(
IVarSet * pVarSet // in - varset containing account mapping
)
{
BOOL bSuccess = TRUE;
_bstr_t text;
if ( m_LocalOnly )
{
m_Args.Cache()->SetSourceAndTargetDomainsWithSids(m_Args.Source(),m_SourceSid,m_Args.Target(),m_TargetSid);
}
else
{
m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
}
m_Args.Cache()->ToSorted();
// no wildcard filter specified. Use the explicit list of accounts
long numAccounts = pVarSet->get(GET_BSTR(DCTVS_Accounts_NumItems));
for ( int i = 0 ; i < numAccounts ; i++ )
{
WCHAR key[LEN_Path];
WCHAR name[LEN_Account];
WCHAR targetName[LEN_Account];
WCHAR type[LEN_Path];
short sType;
swprintf(key,GET_STRING(DCTVSFmt_Accounts_D),i);
text = pVarSet->get(key);
safecopy(name,(WCHAR*)text);
swprintf(key,GET_STRING(DCTVSFmt_Accounts_TargetName_D),i);
text = pVarSet->get(key);
safecopy(targetName,(WCHAR*)text);
swprintf(key,GET_STRING(DCTVSFmt_Accounts_Type_D),i);
text = pVarSet->get(key);
safecopy(type,(WCHAR*)text);
if (! UStrICmp(type,L"user") )
sType = EA_AccountUser;
else if (! UStrICmp(type,L"group") )
sType = EA_AccountGroup;
else
sType = 0;
m_Args.Cache()->InsertLast(name,0,targetName,0,sType);
}
if ( bSuccess && ! m_LocalOnly )
{
bSuccess = GetRIDsFromEA();
}
return bSuccess;
}
HRESULT CSecTranslator::LoadMigratedObjects(IVarSet * pVarSetIn)
{
HRESULT hr = S_OK;
// this reads the migrated objects table from the database, and
// constructs a mapping file to be used for security translation
IIManageDBPtr pDB;
IUnknown * pUnk = NULL;
IVarSetPtr pVarSet(CLSID_VarSet);
WCHAR strKey[MAX_PATH];
long ndx = 0;
_bstr_t srcSam = L"?";
_bstr_t tgtSam = L"?";
_bstr_t type;
_bstr_t srcDom;
_bstr_t tgtDom;
// FILE * pFile = NULL;
// BOOL bSuccess = TRUE;
UCHAR srcEaServer[LEN_Computer];
UCHAR tgtEaServer[LEN_Computer];
_bstr_t text;
safecopy(srcEaServer,m_Args.Source());
safecopy(tgtEaServer,m_Args.Target());
if ( m_LocalOnly )
{
m_Args.Cache()->SetSourceAndTargetDomainsWithSids(m_Args.Source(),m_SourceSid,m_Args.Target(),m_TargetSid);
}
else
{
m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
}
m_Args.Cache()->ToSorted();
hr = pDB.CreateInstance(CLSID_IManageDB);
if ( SUCCEEDED(hr) )
{
hr = pVarSet->QueryInterface(IID_IUnknown,(void**)&pUnk);
if ( SUCCEEDED(hr) )
{
hr = pDB->raw_GetMigratedObjects(-1,&pUnk);
}
if ( SUCCEEDED(hr) )
{
pVarSet = pUnk;
pUnk->Release();
short sType;
long rid = 0;
long rid2 = 0;
// GetMigratedObjects returns the migrated objects in the varset as:
// MigratedObjects.%ld.*
for ( ndx = 0 ;srcSam.length() && tgtSam.length() ; ndx++ )
{
swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_SourceDomain));
srcDom = pVarSet->get(strKey);
swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_TargetDomain));
tgtDom = pVarSet->get(strKey);
swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_SourceSamName));
srcSam = pVarSet->get(strKey);
swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_TargetSamName));
tgtSam = pVarSet->get(strKey);
swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_Type));
type = pVarSet->get(strKey);
swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_SourceRid));
rid = pVarSet->get(strKey);
swprintf(strKey,L"MigratedObjects.%ld.%s",ndx,GET_STRING(DB_TargetRid));
rid2 = pVarSet->get(strKey);
if ( !UStrICmp(srcDom, m_Args.Source()) && !UStrICmp(tgtDom, m_Args.Target()) )
{
if ( !UStrICmp(type,L"user") || !UStrICmp(type,L"group") )
{
if (! UStrICmp(type,L"user") )
sType = EA_AccountUser;
else if (! UStrICmp(type,L"group") )
sType = EA_AccountGroup;
else
sType = 0;
m_Args.Cache()->InsertLast((WCHAR*)srcSam,rid,(WCHAR*)tgtSam,rid2,sType);
}
}
}
}
}
/* if ( SUCCEEDED(hr) )
{
GetRIDsFromEA();
}
*/ return hr;
}
BOOL
CSecTranslator::BuildCacheFile(
WCHAR const * filename // in - file to write account mapping to
)
{
BOOL bSuccess = TRUE;
FILE * pFile;
m_Args.Cache()->ToSorted();
TNodeListEnum e;
TRidNode * node;
WCHAR type[LEN_Path];
pFile = _wfopen(filename,L"wb");
if ( pFile )
{
for ( node = (TRidNode*) e.OpenFirst(m_Args.Cache() ); node ; node = (TRidNode*)e.Next() )
{
switch ( node->Type() )
{
case EA_AccountUser:
safecopy(type,L"user");
break;
case EA_AccountGroup:
case EA_AccountGGroup:
case EA_AccountLGroup:
safecopy(type,L"group");
break;
default:
type[0] = 0;
break;
}
// if (!UStrICmp(node->GetAcctName(),node->GetTargetAcctName()))
if ((UStrICmp(node->GetSrcDomSid(),L"")) && (UStrICmp(node->GetTgtDomSid(),L"")))
{
//account and domain names could be empty when using a sid
//mapping file for security translation. A later scanf by
//the agent will fail on a NULL name, so we will store "(UnKnown)"
//instead and deal with that on the scanf-side
WCHAR ssname[MAX_PATH];
wcscpy(ssname, node->GetAcctName());
if (!wcslen(ssname))
wcscpy(ssname, GET_STRING(IDS_UnknownSid));
WCHAR stname[MAX_PATH];
wcscpy(stname, node->GetTargetAcctName());
if (!wcslen(stname))
wcscpy(stname, GET_STRING(IDS_UnknownSid));
WCHAR ssdname[MAX_PATH];
wcscpy(ssdname, node->GetSrcDomName());
if (!wcslen(ssdname))
wcscpy(ssdname, GET_STRING(IDS_UnknownSid));
WCHAR stdname[MAX_PATH];
wcscpy(stdname, node->GetTgtDomName());
if (!wcslen(stdname))
wcscpy(stdname, GET_STRING(IDS_UnknownSid));
fwprintf(pFile,L"%s\t%s\t%s\t%lx\t%lx\t%lx\t%s\t%s\t%s\t%s\r\n",ssname,stname,type,
0, node->SrcRid(), node->TgtRid(), node->GetSrcDomSid(), node->GetTgtDomSid(),
ssdname, stdname);
}
else
{
fwprintf(pFile,L"%s\t%s\t%s\t%lx\t%lx\t%lx\r\n",node->GetAcctName(),node->GetTargetAcctName(),type,
0, node->SrcRid(), node->TgtRid());
}
}
e.Close();
fclose(pFile);
}
else
{
bSuccess = FALSE;
// DWORD rc = GetLastError();
}
return bSuccess;
}
BOOL
CSecTranslator::LoadCacheFromFile(
WCHAR const * filename, // in - file to read account mapping from
IVarSet * pVarSet // in - pointer to varset
)
{
BOOL bSuccess = TRUE;
_bstr_t text;
FILE * pFile;
WCHAR sourceName[LEN_Account];
WCHAR targetName[LEN_Account];
WCHAR sourceDomSid[MAX_PATH];
WCHAR targetDomSid[MAX_PATH];
WCHAR sourceDomName[MAX_PATH];
WCHAR targetDomName[MAX_PATH];
WCHAR type[LEN_Account];
DWORD status;
int count = 0;
BOOL bNeedRids = FALSE;
WCHAR path[MAX_PATH];
WCHAR temp[MAX_PATH];
BOOL bUseMapFile = FALSE;
if ( m_LocalOnly )
{
m_Args.Cache()->SetSourceAndTargetDomainsWithSids(m_Args.Source(),m_SourceSid,m_Args.Target(),m_TargetSid);
// find the module path
DWORD rc = GetModuleFileName(NULL,temp,DIM(temp));
if ( rc )
{
// Generally, our DCTCache file will be in the same directory as our EXE.
// This is true 1) when agent is dispatched to clean machine (all will be in OnePointDomainAgent directory)
// and also 2) when agent is dispatched to the local ADMT machine (all will be in Program Files\ADMT directory)
// The exception is when the agent is dispatched to a remote machine where ADMT is also installed.
WCHAR * slash = wcsrchr(temp,L'\\');
UStrCpy(slash+1,filename);
// Check whether ADMT is locally installed here
if ( IsLocallyInstalled() && !IsThisDispatcherMachine(pVarSet) )
{
// ADMT is installed here, so we're running from the binaries
// in the Program files\ADMT directory
// However, our cache file should be in %Program Files%\\OnePOintDomainAgent
GetProgramFilesDirectory(temp,NULL);
UStrCpy(temp+UStrLen(temp),L"\\OnePointDomainAgent\\");
UStrCpy(temp+UStrLen(temp),filename);
}
}
else
{
rc = GetLastError();
err.DbgMsgWrite(0,L"Couldn't get the module filename, rc=%ld",rc);
swprintf(temp,L"..\\OnePointDomainAgent\\%ls",filename);
}
_wfullpath(path,temp,MAX_PATH);
}
else
{
m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
_wfullpath(path,filename,MAX_PATH);
}
m_Args.Cache()->ToSorted();
text = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SecurityInputMOT));
if (UStrICmp(text,GET_STRING(IDS_YES)))
{
m_Args.SetUsingMapFile(TRUE); //set the arg flag to indicate use of map file
bUseMapFile = TRUE;
}
// The input file should have the format:
// SourceName, TargetName, Type, Status [,rid1, rid2]
pFile = _wfopen(path,L"rb");
if ( pFile )
{
int result;
do
{
DWORD rid1 = 0;
DWORD rid2 = 0;
if (!bUseMapFile)
{
result = fwscanf(pFile,L"%[^\t]\t%[^\t]\t%[^\t]\t%lx\t%lx\t%lx\r\n",
sourceName,targetName,type,&status,&rid1,&rid2);
if ( result < 4 )
break;
}
else
{
result = fwscanf(pFile,L"%[^\t]\t%[^\t]\t%[^\t]\t%lx\t%lx\t%lx\t%[^\t]\t%[^\t]\t%[^\t]\t%[^\r]\r\n",
sourceName,targetName,type,&status,&rid1,&rid2,sourceDomSid,targetDomSid,
sourceDomName, targetDomName);
if ( result < 8 )
break;
}
short lType = 0;
if ( !UStrICmp(type,L"user") )
lType = EA_AccountUser;
else if ( ! UStrICmp(type,L"group") )
lType = EA_AccountGroup;
if (!bUseMapFile)
m_Args.Cache()->InsertLast(sourceName,rid1,targetName,rid2,lType);
else
m_Args.Cache()->InsertLastWithSid(sourceName,sourceDomSid,sourceDomName,rid1,
targetName,targetDomSid,targetDomName,rid2,lType);
count++;
if ( ! rid1 | ! rid2 )
{
bNeedRids = TRUE;
}
} while ( result >= 4 ); // 4 fields read and assigned
if ( result )
{
err.MsgWrite(ErrS,DCT_MSG_ERROR_READING_INPUT_FILE_S,path);
}
err.MsgWrite(0,DCT_MSG_ACCOUNTS_READ_FROM_FILE_DS,count,path);
fclose(pFile);
}
else
{
err.MsgWrite(ErrS,DCT_MSG_ERROR_OPENING_FILE_S,path);
bSuccess = FALSE;
}
if ( bSuccess && bNeedRids && ! m_LocalOnly)
{
bSuccess = GetRIDsFromEA();
}
return bSuccess;
}
// This doesn't get RIDs from EA any more, since we have removed dependencies on MCS products.
// Instead, we use the Net APIs to get this information
BOOL CSecTranslator::GetRIDsFromEA()
{
BOOL bSuccess = TRUE;
// set the cache to a tree sorted by name
m_Args.Cache()->SortedToScrambledTree();
m_Args.Cache()->Sort(&CompN);
// do NQDI to get RIDS for accounts
DWORD rc = 0;
NET_DISPLAY_USER * pUser = NULL;
NET_DISPLAY_GROUP * pGroup = NULL;
DWORD count = 0;
DWORD resume = 0;
TRidNode * pNode = NULL;
// Get source rids for users
do
{
rc = NetQueryDisplayInformation(m_Args.Cache()->GetSourceDCName(),1,resume,5000,100000,&count,(void**)&pUser);
if ( 0 == rc || ERROR_MORE_DATA == rc )
{
for ( DWORD i = 0 ; i < count ; i++ )
{
// see if this account is in the cache
pNode = (TRidNode*)m_Args.Cache()->Find(&vNameComp,pUser[i].usri1_name);
if ( pNode )
{
pNode->SrcRid(pUser[i].usri1_user_id);
}
}
if ( count )
{
resume = pUser[count-1].usri1_next_index;
}
else
{
// no items were returned - get out of here
break;
}
NetApiBufferFree(pUser);
}
} while ( rc == ERROR_MORE_DATA );
count = 0;
resume = 0;
// Get source rids for global groups
do
{
rc = NetQueryDisplayInformation(m_Args.Cache()->GetSourceDCName(),3,resume,5000,100000,&count,(void**)&pGroup);
if ( 0 == rc || ERROR_MORE_DATA == rc )
{
for ( DWORD i = 0 ; i < count ; i++ )
{
// see if this account is in the cache
pNode = (TRidNode*)m_Args.Cache()->Find(&vNameComp,pGroup[i].grpi3_name);
if ( pNode )
{
pNode->SrcRid(pGroup[i].grpi3_group_id);
}
}
if ( count )
{
resume = pGroup[count-1].grpi3_next_index;
}
else
{
// no items were returned - get out of here
break;
}
NetApiBufferFree(pGroup);
}
} while ( rc == ERROR_MORE_DATA );
count = 0;
resume = 0;
// Get target rids for users
// set the cache to a tree sorted by target name
m_Args.Cache()->ToSorted();
m_Args.Cache()->SortedToScrambledTree();
m_Args.Cache()->Sort(&CompTargetN);
do
{
rc = NetQueryDisplayInformation(m_Args.Cache()->GetTargetDCName(),1,resume,5000,100000,&count,(void**)&pUser);
if ( 0 == rc || ERROR_MORE_DATA == rc )
{
for ( DWORD i = 0 ; i < count ; i++ )
{
// see if this account is in the cache
pNode = (TRidNode*)m_Args.Cache()->Find(&vTargetNameComp,pUser[i].usri1_name);
if ( pNode )
{
pNode->TgtRid(pUser[i].usri1_user_id);
}
}
if ( count )
{
resume = pUser[count-1].usri1_next_index;
}
else
{
// no items were returned - get out of here
break;
}
NetApiBufferFree(pUser);
}
} while ( rc == ERROR_MORE_DATA );
// TODO: Add error message if rc != 0
count = 0;
resume = 0;
// Get target rids for global groups
do
{
rc = NetQueryDisplayInformation(m_Args.Cache()->GetTargetDCName(),3,resume,5000,100000,&count,(void**)&pGroup);
if ( 0 == rc || ERROR_MORE_DATA == rc )
{
for ( DWORD i = 0 ; i < count ; i++ )
{
// see if this account is in the cache
pNode = (TRidNode*)m_Args.Cache()->Find(&vTargetNameComp,pGroup[i].grpi3_name);
if ( pNode )
{
pNode->TgtRid(pGroup[i].grpi3_group_id);
}
}
if ( count )
{
resume = pGroup[count-1].grpi3_next_index;
}
else
{
// no items were returned - get out of here
break;
}
NetApiBufferFree(pGroup);
}
} while ( rc == ERROR_MORE_DATA );
// sort back to regular source name order
m_Args.Cache()->ToSorted();
m_Args.Cache()->SortedToScrambledTree();
m_Args.Cache()->Sort(&CompN);
// get source and target rids for local groups
TNodeTreeEnum tEnum;
BYTE sid[LEN_SID];
DWORD lenSid;
WCHAR domain[LEN_Domain];
DWORD lenDomain;
SID_NAME_USE snu;
for ( pNode = (TRidNode*)tEnum.OpenFirst(m_Args.Cache()) ; pNode ; pNode = (TRidNode*) tEnum.Next() )
{
if ( ! pNode->SrcRid() )
{
// we don't have a rid for this account, possibly because it is a local group
lenSid = DIM(sid);
lenDomain = DIM(domain);
if ( LookupAccountName(m_Args.Cache()->GetSourceDCName(),pNode->GetAcctName(),sid,&lenSid,domain,&lenDomain,&snu) )
{
if (! UStrICmp(m_Args.Source(),domain) )
{
// found the source SID
// get the last sub-id
PUCHAR pCount = GetSidSubAuthorityCount(&sid);
if ( pCount )
{
LPDWORD pRid = GetSidSubAuthority(&sid,(*pCount) - 1 );
if ( pRid )
{
pNode->SrcRid(*pRid);
}
}
}
}
}
if ( pNode->SrcRid() && !pNode->TgtRid() )
{
// we got the source RID, now try to get the target RID
lenSid = DIM(sid);
lenDomain = DIM(domain);
if ( LookupAccountName(m_Args.Cache()->GetTargetDCName(),pNode->GetTargetAcctName(),sid,&lenSid,domain,&lenDomain,&snu) )
{
if (! UStrICmp(m_Args.Target(),domain) )
{
// found the source SID
// get the last sub-id
PUCHAR pCount = GetSidSubAuthorityCount(&sid);
if ( pCount )
{
LPDWORD pRid = GetSidSubAuthority(&sid,(*pCount) - 1 );
if ( pRid )
{
pNode->TgtRid(*pRid);
}
}
}
}
}
}
tEnum.Close();
return bSuccess;
}
// We remove the Exchange server service accont from the cache before translating,
// since it is not recommended to change the service account from exchange
// in any event, the service account for exchange cannot be changed simply by granting
// exchange permissions to the new account. It also requires configuration changes within
// exchange that must be performed manually
BOOL
CSecTranslator::RemoveExchangeServiceAccountFromCache()
{
WCHAR const * exServiceName = L"MSExchangeDS";
SC_HANDLE hSCM;
DWORD rc = 0; // return code
BOOL result = FALSE;
BOOL bUseMapFile = m_Args.UsingMapFile();
if ( m_Args.TranslateContainers() )
{
// get the service account name for the exchange directory service on exchServer
// BOOL retval=FALSE; // returned value
SC_HANDLE hSvc; // Service handle
DWORD lenQsc; // required qsc info len
union
{
QUERY_SERVICE_CONFIG qsc; // Exchange Directory service information
BYTE padding[1000];
} bufQsc;
hSCM = OpenSCManager( m_exchServer, NULL, GENERIC_READ );
if ( !hSCM )
{
rc = GetLastError();
err.SysMsgWrite( ErrW, rc,
DCT_MSG_SCM_OPEN_FAILED_SD, m_exchServer,rc );
}
else
{
hSvc = OpenService( hSCM, exServiceName, SERVICE_QUERY_CONFIG );
if ( !hSvc )
{
rc = GetLastError();
switch ( rc )
{
case ERROR_SERVICE_DOES_NOT_EXIST: // 1060
default:
err.SysMsgWrite( ErrW, rc, DCT_MSG_OPEN_SERVICE_FAILED_SSD,
m_exchServer , exServiceName, rc );
break;
}
}
else
{
if ( !QueryServiceConfig( hSvc, &bufQsc.qsc, sizeof bufQsc, &lenQsc ) )
{
rc = GetLastError();
err.SysMsgWrite( ErrW, rc, DCT_MSG_QUERY_SERVICE_CONFIG_FAILED_SSD,
m_exchServer, exServiceName, rc );
}
else
{
// We've found the account
result = TRUE;
// bufQsc.qsc.lpServiceStartName is DOMAIN\Account or .\Account
WCHAR * domAcct = bufQsc.qsc.lpServiceStartName;
WCHAR * domName; // domain-name
WCHAR * acctName; // account-name
for ( domName = domAcct ; *domName && *domName != _T('\\') ; domName++ )
;
if ( *domName == _T('\\') )
{
*domName = 0;
acctName = domName+1;
domName = domAcct;
}
// Is the account from the source domain?
WCHAR szSourceDomain[LEN_Domain];
WCHAR wszAccountName[LEN_Account];
safecopy(wszAccountName,acctName);
//use the domain name from the cache if we are not using a sID mapping
//file
if (!bUseMapFile)
{
safecopy(szSourceDomain,m_Args.Cache()->GetSourceDomainName());
if ( !UStrICmp(domName,szSourceDomain ) )
{
// if so, is it in the cache?
TAcctNode * tnode;
TNodeTreeEnum tEnum;
// the cache is a tree, sorted by RID
for ( tnode = (TAcctNode *)tEnum.OpenFirst(m_Args.Cache()) ; tnode ; tnode = (TAcctNode *)tEnum.Next() )
{
if ( !UStrICmp(tnode->GetAcctName(),wszAccountName) )
{
// remove it from the cache, and notify the user
err.MsgWrite(ErrW,DCT_MSG_SKIPPING_EXCHANGE_ACCOUNT_SS,domName,acctName);
m_Args.Cache()->Remove(tnode);
}
}
tEnum.Close();
}
}//end if not using mapping file
else //else using sID mapping file, get the source domain name from the
{ //node itself
//is this account in the cache?
TAcctNode * tnode;
TNodeTreeEnum tEnum;
// the cache is a tree, sorted by RID
for ( tnode = (TAcctNode *)tEnum.OpenFirst(m_Args.Cache()) ; tnode ; tnode = (TAcctNode *)tEnum.Next() )
{
if (( !UStrICmp(tnode->GetAcctName(),wszAccountName) ) &&
( !UStrICmp(((TRidNode*)tnode)->GetSrcDomName(),domName) ))
{
// remove it from the cache, and notify the user
err.MsgWrite(ErrW,DCT_MSG_SKIPPING_EXCHANGE_ACCOUNT_SS,domName,acctName);
m_Args.Cache()->Remove(tnode);
}
}
tEnum.Close();
}//end if using mapping file
CloseServiceHandle( hSvc );
}
}
CloseServiceHandle(hSCM);
}
}
if ( !result )
{
// couldn't get the service account name
err.SysMsgWrite(ErrW,rc,DCT_MSG_CANT_FIND_EXCHANGE_ACCOUNT_SD,
m_exchServer,rc);
}
return result;
}
void
CSecTranslator::DoExchangeResolution(
TSDResolveStats * stat, // in - stats object to record stats
IVarSet * pVarSet
)
{
{
TGlobalDirectory m_exDir;
_bstr_t domain = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_Domain));
_bstr_t username = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_UserName));
_bstr_t password = pVarSet->get(GET_BSTR(DCTVS_AccountOptions_SidHistoryCredentials_Password));
_bstr_t mode = pVarSet->get(GET_BSTR(DCTVS_Security_TranslationMode));
_bstr_t mbquery = pVarSet->get(L"ExchangeMigration.LdapQuery");
WCHAR creds[LEN_Account + LEN_Domain + 6];
WCHAR query[LEN_Path] = L"(objectClass=*)";
if ( m_exchServer[0] )
{
if (! RemoveExchangeServiceAccountFromCache() )
goto end;
}
if ( mbquery.length() )
{
UStrCpy(query,(WCHAR*)mbquery);
}
if ( m_Args.TranslateMailboxes() || m_Args.TranslateContainers() )
{
// make sure we have some accts in the cache
m_exDir.SetStats(stat);
m_Args.Cache()->UnCancel();
swprintf(creds,L"cn=%ls,cn=%ls",(WCHAR*)username,(WCHAR*)domain);
err.MsgWrite(0,DCT_MSG_EXCHANGE_TRANSLATION_MODE_S,(WCHAR*)mode);
m_exDir.DoLdapTranslation(m_exchServer,creds,password,&m_Args,NULL,query);
stat->DisplayPath(L"");
}
}
end:
// destructor for m_exDir must be called before we release the MAPI library!
ReleaseMAPI();
ReleaseDAPI();
return;
}
/*********************************************************************
* *
* Written by: Paul Thompson *
* Date: 4 OCT 2000 *
* *
* This function is responsible for retrieving account sIDs from *
* the given sID mapping file and adding these sids to the cache. *
* *
*********************************************************************/
//BEGIN LoadCacheFromMapFile
BOOL
CSecTranslator::LoadCacheFromMapFile(
WCHAR const * filename, // in - file to read sid mapping from
IVarSet * pVarSet // in - pointer to varset
)
{
FILE * pFile = NULL;
WCHAR path[MAX_PATH];
WCHAR sourceSid[MAX_PATH];
WCHAR targetSid[MAX_PATH];
int count = 0;
BOOL bSuccess = TRUE;
// m_Args.Cache()->SetSourceAndTargetDomains(m_Args.Source(),m_Args.Target());
_wfullpath(path,filename,MAX_PATH);
m_Args.Cache()->ToSorted();
// The input file should have the format:
// srcSid,tgtSid
pFile = OpenMappingFile(path);
// pFile = _wfopen(path,L"rb");
if ( pFile )
{
int result;
//move past the UNICODE Byte Order Mark
// fgetwc(pFile);
do
{
result = fwscanf(pFile,L"%[^,], %[^\r\n]\n",sourceSid,targetSid);
if ( result < 2 )
break;
short lType = EA_AccountUser;
//divide the sids into domain sids and rids
WCHAR srcDomainSid[MAX_PATH] = L"";
WCHAR tgtDomainSid[MAX_PATH] = L"";
WCHAR srcDomainName[MAX_PATH] = L"";
WCHAR tgtDomainName[MAX_PATH] = L"";
DWORD srcRid = 0;
DWORD tgtRid = 0;
WCHAR srcName[MAX_PATH] = L"";
WCHAR tgtName[MAX_PATH] = L"";
WCHAR domainName[MAX_PATH] = L"";
DWORD cb = MAX_PATH;
DWORD cbDomain = MAX_PATH;
SID_NAME_USE sid_Use;
PSID srcSid = NULL;
PSID tgtSid = NULL;
WCHAR * slash;
LPWSTR pdomc;
WCHAR DCName[MAX_PATH];
BYTE ssid[200];
BYTE tsid[200];
DWORD lenSid = DIM(ssid);
BOOL bNeedToFreeSrc = FALSE;
BOOL bNeedToFreeTgt = FALSE;
//see if the source is given by domain\account format or
//decimal-style sid format
if (wcschr(sourceSid,L'\\'))
{
//seperate domain and account names
wcscpy(srcDomainName,sourceSid);
slash = wcschr(srcDomainName,L'\\');
if ( slash )
{
*slash = 0;
wcscpy(srcName,slash+1);
}
//get a DC for the given domain
HRESULT res = NetGetDCName(NULL,srcDomainName,(LPBYTE *)&pdomc);
if (res!=NERR_Success)
{
err.MsgWrite(0,DCT_MSG_SRC_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, sourceSid);
continue;
}
wcscpy(DCName, pdomc);
NetApiBufferFree(pdomc);
//get the sid for this account
if(!LookupAccountName(DCName,srcName,(PSID)ssid,&lenSid,srcDomainName,&cbDomain,&sid_Use))
{
err.MsgWrite(0,DCT_MSG_SRC_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, sourceSid);
continue;
}
srcSid = (PSID)ssid;
if (sid_Use == SidTypeGroup)
lType = EA_AccountGroup;
else
lType = EA_AccountUser;
}//end if domain\account format
else
{
srcSid = SidFromString(sourceSid);
if (!srcSid)
{
err.MsgWrite(0,DCT_MSG_SRC_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, sourceSid);
continue;
}
bNeedToFreeSrc = TRUE;
if (LookupAccountSid(NULL, srcSid, srcName, &cb, srcDomainName, &cbDomain, &sid_Use))
{
if (sid_Use == SidTypeGroup)
lType = EA_AccountGroup;
else
lType = EA_AccountUser;
}
}//end else sid format
//see if the target is given by domain\account format or
//decimal-style sid format
lenSid = DIM(tsid);
cb = cbDomain = MAX_PATH;
if (wcschr(targetSid,L'\\'))
{
//seperate domain and account names
wcscpy(tgtDomainName,targetSid);
slash = wcschr(tgtDomainName,L'\\');
if ( slash )
{
*slash = 0;
wcscpy(tgtName,slash+1);
}
//get a DC for the given domain
HRESULT res = NetGetDCName(NULL,tgtDomainName,(LPBYTE *)&pdomc);
if (res!=NERR_Success)
{
if (bNeedToFreeSrc)
FreeSid(srcSid);
err.MsgWrite(0,DCT_MSG_TGT_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, targetSid);
continue;
}
wcscpy(DCName, pdomc);
NetApiBufferFree(pdomc);
//get the sid for this account
if(!LookupAccountName(DCName,tgtName,(PSID)tsid,&lenSid,tgtDomainName,&cbDomain,&sid_Use))
{
if (bNeedToFreeSrc)
FreeSid(srcSid);
err.MsgWrite(0,DCT_MSG_TGT_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, targetSid);
continue;
}
tgtSid = (PSID)tsid;
if (sid_Use == SidTypeGroup)
lType = EA_AccountGroup;
else
lType = EA_AccountUser;
}//end if domain\account format
else
{
tgtSid = SidFromString(targetSid);
if (!tgtSid)
{
if (bNeedToFreeSrc)
FreeSid(srcSid);
err.MsgWrite(0,DCT_MSG_TGT_ACCOUNT_NOT_READ_FROM_FILE_DS, sourceSid, targetSid, path, targetSid);
continue;
}
bNeedToFreeTgt = TRUE;
if (LookupAccountSid(NULL, tgtSid, tgtName, &cb, tgtDomainName, &cbDomain, &sid_Use))
{
if (sid_Use == SidTypeGroup)
lType = EA_AccountGroup;
else
lType = EA_AccountUser;
}
}//end else sid format
//if the source account is not already in the cache, then add it
if ((m_Args.Cache()->GetNumAccts() == 0) || (m_Args.Cache()->LookupWODomain(srcSid) == NULL))
{
//get the domain sids and account rids from the account sids
SplitAccountSids(srcSid, srcDomainSid, &srcRid, tgtSid, tgtDomainSid, &tgtRid);
//insert this node into the cache
m_Args.Cache()->InsertLastWithSid(srcName,srcDomainSid,srcDomainName,srcRid,tgtName,
tgtDomainSid,tgtDomainName,tgtRid,lType);
count++;
}
else
err.MsgWrite(0,DCT_MSG_SRC_ACCOUNT_DUPLICATE_IN_FILE_DS, sourceSid, targetSid, path, sourceSid);
if (bNeedToFreeSrc)
FreeSid(srcSid);
if (bNeedToFreeTgt)
FreeSid(tgtSid);
} while ( result >= 2 ); // 2 fields read and assigned
err.MsgWrite(0,DCT_MSG_ACCOUNTS_READ_FROM_FILE_DS,count,path);
fclose(pFile);
}
else
{
err.MsgWrite(ErrS,DCT_MSG_ERROR_OPENING_FILE_S,path);
bSuccess = FALSE;
}
return bSuccess;
}
//END LoadCacheFromMapFile
/*********************************************************************
* *
* Written by: Paul Thompson *
* Date: 11 OCT 2000 *
* *
* This function is responsible for opening the sid mapping file *
* whether it is anm ANSI or UNICODE file and return the file *
* pointer. *
* *
*********************************************************************/
//BEGIN OpenMappingFile
FILE* CSecTranslator::OpenMappingFile(LPCTSTR pszFileName)
{
// open in binary mode first in order to check for UNICODE byte order
// mark if the file is UNICODE then it must be read in binary mode
// with the stream i/o functions
FILE* fp = _tfopen(pszFileName, _T("rb"));
if (fp == NULL)
{
return NULL;
// _com_issue_error(E_INVALIDARG);
}
// check if file is ANSI or UNICODE or UTF-8
BYTE byteSignature[3];
if (fread(byteSignature, sizeof(BYTE), 3, fp) == 3)
{
static BYTE byteUtf8[] = { 0xEF, 0xBB, 0xBF };
static BYTE byteUnicodeLE[] = { 0xFF, 0xFE };
static BYTE byteUnicodeBE[] = { 0xFE, 0xFF };
// check for signature or byte order mark
if (memcmp(byteSignature, byteUtf8, sizeof(byteUtf8)) == 0)
{
// UTF-8 signature
// TODO: not currently supported
return NULL;
// _com_issue_error(E_INVALIDARG);
}
else if (memcmp(byteSignature, byteUnicodeLE, sizeof(byteUnicodeLE)) == 0)
{
// UNICODE Little Endian Byte Order Mark
// supported
// must read in binary mode
// move file pointer back one byte because we read 3 bytes
fseek(fp, -1, SEEK_CUR);
}
else if (memcmp(byteSignature, byteUnicodeBE, sizeof(byteUnicodeBE)) == 0)
{
// UNICODE Big Endian Byte Order Mark
// TODO: not currently supported
return NULL;
// _com_issue_error(E_INVALIDARG);
}
else
{
// assume ANSI
// re-open file in text mode as the stream i/o functions will
// treat the file as multi-byte characters and will convert them
// to UNICODE
fclose(fp);
fp = _tfopen(pszFileName, _T("rt"));
}
}
else
{
return NULL;
// _com_issue_error(E_INVALIDARG);
}
return fp;
}
//END OpenMappingFile