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

622 lines
15 KiB

#include "headers.hxx"
#include "dspecup.hpp"
#include "Analysis.hpp"
#include "repair.hpp"
#include "AnalysisResults.hpp"
#include "resourceDspecup.h"
#include "CSVDSReader.hpp"
#include "constants.hpp"
#include "AdsiHelpers.hpp"
#include "guids.inc"
HRESULT
FindCsvFile(
String& csvFilePath,
String& csv409Path
)
{
LOG_FUNCTION(FindCsvFile);
csvFilePath.erase();
csv409Path.erase();
HRESULT hr = S_OK;
do
{
// look for dcpromo.csv and 409.csv file in system
// or current directory
// check the default of
// %windir%\system32\mui\dispspec\dcpromo.csv and
// .\dcpromo.csv
String csvname=L"dcpromo.csv";
String sys32dir = Win::GetSystemDirectory();
String csvPath = sys32dir + L"\\debug\\adprep\\data\\" + csvname;
if (FS::FileExists(csvPath))
{
csvFilePath = csvPath;
}
else
{
error=String::format(IDS_COULD_NOT_FIND_FILE,csvPath.c_str());
hr=E_FAIL;
break;
}
csvname=L"409.csv";
csvPath = sys32dir + L"\\debug\\adprep\\data\\" + csvname;
if (FS::FileExists(csvPath))
{
csv409Path = csvPath;
}
else
{
error=String::format(IDS_COULD_NOT_FIND_FILE,csvPath.c_str());
hr=E_FAIL;
break;
}
}
while(0);
LOG_HRESULT(hr);
LOG(csvFilePath);
LOG(csv409Path);
return hr;
}
HRESULT
InitializeADSI(
const String &targetDcName,
String &ldapPrefix,
String &rootContainerDn,
String &domainName,
String &completeDcName,
SmartInterface<IADs>& rootDse
)
{
LOG_FUNCTION(InitializeADSI);
HRESULT hr=S_OK;
do
{
Computer targetDc(targetDcName);
hr = targetDc.Refresh();
if (FAILED(hr))
{
error = String::format(
IDS_CANT_TARGET_MACHINE,
targetDcName.c_str());
break;
}
if (!targetDc.IsDomainController())
{
error=String::format(
IDS_TARGET_IS_NOT_DC,
targetDcName.c_str());
hr=E_FAIL;
break;
}
completeDcName = targetDc.GetActivePhysicalFullDnsName();
ldapPrefix = L"LDAP://" + completeDcName + L"/";
//
// Find the DN of the configuration container.
//
// Bind to the rootDSE object. We will keep this binding handle
// open for the duration of the analysis and repair phases in order
// to keep a server session open. If we decide to pass creds to the
// AdsiOpenObject call in a later revision, then by keeping the
// session open we will not need to pass the password to subsequent
// AdsiOpenObject calls.
hr = AdsiOpenObject<IADs>(ldapPrefix + L"RootDSE", rootDse);
if (FAILED(hr))
{
error=String::format(
IDS_UNABLE_TO_CONNECT_TO_DC,
completeDcName.c_str());
hr=E_FAIL;
break;
}
// read the configuration naming context.
_variant_t variant;
hr =
rootDse->Get(
AutoBstr(LDAP_OPATT_CONFIG_NAMING_CONTEXT_W),
&variant);
if (FAILED(hr))
{
LOG(L"can't read config NC");
error=String::format(IDS_UNABLE_TO_READ_DIRECTORY_INFO);
break;
}
String configNc = V_BSTR(&variant);
ASSERT(!configNc.empty());
LOG(configNc);
wchar_t *domain=wcschr(configNc.c_str(),L',');
ASSERT(domain!=NULL);
domainName=domain+1;
rootContainerDn = L"CN=DisplaySpecifiers," + configNc;
}
while (0);
LOG_HRESULT(hr);
return hr;
}
HRESULT
GetInitialInformation(
String &targetDomainControllerName,
String &csvFilename,
String &csv409Name
)
{
LOG_FUNCTION(GetInitialInformation);
HRESULT hr = S_OK;
do
{
//
// find the dcpromo.csv file to use
//
hr = FindCsvFile(csvFilename, csv409Name);
BREAK_ON_FAILED_HRESULT(hr);
//
// Determine the target domain controller
//
if (targetDomainControllerName.empty())
{
// no target specified, default to the current machine
targetDomainControllerName =
Win::GetComputerNameEx(ComputerNameDnsFullyQualified);
if (targetDomainControllerName.empty())
{
// no DNS name? that's not right...
LOG(L"no default DNS computer name found. Using netbios name.");
targetDomainControllerName =
Win::GetComputerNameEx(ComputerNameNetBIOS);
ASSERT(!targetDomainControllerName.empty());
}
}
}
while (0);
LOG_HRESULT(hr);
return hr;
}
///////////////////////////////////////////////////////////////////
// Function: cchLoadHrMsg
//
// Given an HRESULT error,
// it loads the string for the error. It returns the # of characters returned
int cchLoadHrMsg( HRESULT hr, String &message )
{
if(hr == S_OK) return 0;
wchar_t *msgPtr = NULL;
// Try from the system table
int cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msgPtr,
0,
NULL);
if (!cch)
{
//try ads errors
static HMODULE g_adsMod = 0;
if (0 == g_adsMod)
{
g_adsMod = GetModuleHandle (L"activeds.dll");
}
cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
g_adsMod,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msgPtr,
0,
NULL);
}
if (!cch)
{
// Try NTSTATUS error codes
hr = HRESULT_FROM_WIN32(RtlNtStatusToDosError(hr));
cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&msgPtr,
0,
NULL);
}
message.erase();
if(cch!=0)
{
if(msgPtr==NULL)
{
cch=0;
}
else
{
message=msgPtr;
::LocalFree(msgPtr);
}
}
return cch;
}
// allocates error with src and a message formated from hr
void AllocError(HRESULT &hr,PWSTR *error,const String& src)
{
ASSERT(error!=NULL);
ASSERT(FAILED(hr));
if (error==NULL) return;
// There is no use in formating a message if hr didn't fail
if(!FAILED(hr)) return;
String msg;
if(hr!=E_FAIL)
{
// We ignore the error since it is possible that
// we don't find a message
cchLoadHrMsg(hr,msg);
}
// Under any conditions(no mesage,E_FAIL or good message)
// we print the hr.
msg+=String::format(L" (0x%1!x!).",hr);
// we also add src
msg=src+L" "+msg;
*error=static_cast<PWSTR>(
LocalAlloc
(
LMEM_FIXED,
(msg.size()+1)*sizeof(wchar_t)
)
);
if(*error==NULL)
{
hr = Win32ToHresult(ERROR_NOT_ENOUGH_MEMORY);
}
else
{
wcscpy(*error,msg.c_str());
}
return;
}
HRESULT
RunAnalysis
(
GUID guid,
PWSTR logFilesPath,
void *caleeStruct/*=NULL*/,
progressFunction stepIt/*=NULL*/,
progressFunction totalSteps/*=NULL*/
)
{
LOG_FUNCTION(RunAnalysis);
hResourceModuleHandle=::GetModuleHandle(NULL);
HRESULT hr=S_OK;
try
{
goodAnalysis=false;
results.createContainers.clear();
results.conflictingWhistlerObjects.clear();
results.createWhistlerObjects.clear();
results.createW2KObjects.clear();
results.objectActions.clear();
results.customizedValues.clear();
results.extraneousValues.clear();
hr = ::CoInitialize(0);
ASSERT(SUCCEEDED(hr));
do
{
String normalPath=FS::NormalizePath(logFilesPath);
if (!FS::PathExists(normalPath) || FS::FileExists(normalPath))
{
hr=E_FAIL;
error=String::load(IDS_NO_LOG_FILE_PATH);
break;
}
hr=GetInitialInformation(
targetDomainControllerName,
csvFileName,
csv409Name
);
BREAK_ON_FAILED_HRESULT(hr);
hr=csvReaderIntl.read(csvFileName.c_str(),LOCALEIDS);
BREAK_ON_FAILED_HRESULT(hr);
hr=csvReader409.read(csv409Name.c_str(),LOCALE409);
BREAK_ON_FAILED_HRESULT(hr);
SmartInterface<IADs> rootDse(0);
hr=InitializeADSI
(
targetDomainControllerName,
ldapPrefix,
rootContainerDn,
domainName,
completeDcName,
rootDse
);
BREAK_ON_FAILED_HRESULT(hr);
String reportName;
GetWorkFileName(
normalPath,
String::load(IDS_FILE_NAME_REPORT),
L"txt",
reportName
);
Analysis analysis(
guid,
csvReader409,
csvReaderIntl,
ldapPrefix,
rootContainerDn,
results,
reportName,
caleeStruct,
stepIt,
totalSteps
);
hr=analysis.run();
BREAK_ON_FAILED_HRESULT(hr);
} while(0);
CoUninitialize();
if(SUCCEEDED(hr))
{
goodAnalysis=true;
}
}
catch( const std::bad_alloc& )
{
// Since we are in an out of memory condition.
// we will not show allocate messages.
hr=Win32ToHresult(ERROR_OUTOFMEMORY);
}
LOG_HRESULT(hr);
return hr;
}
HRESULT
RunRepair
(
PWSTR logFilesPath,
void *caleeStruct/*=NULL*/,
progressFunction stepIt/*=NULL*/,
progressFunction totalSteps/*=NULL*/
)
{
hResourceModuleHandle=::GetModuleHandle(NULL);
LOG_FUNCTION(RunRepair);
HRESULT hr=S_OK;
try
{
hr = ::CoInitialize(0);
ASSERT(SUCCEEDED(hr));
do
{
String normalPath=FS::NormalizePath(logFilesPath);
if (!FS::PathExists(normalPath) || FS::FileExists(normalPath))
{
hr=E_FAIL;
error=String::load(IDS_NO_LOG_FILE_PATH);
break;
}
if (!goodAnalysis)
{
hr=E_FAIL;
error=String::load(IDS_NO_ANALYSIS);
break;
}
String ldiffName;
GetWorkFileName(
normalPath,
String::load(IDS_FILE_NAME_LDIF_ACTIONS),
L"ldf",
ldiffName
);
BREAK_ON_FAILED_HRESULT(hr);
String csvName;
GetWorkFileName(
normalPath,
String::load(IDS_FILE_NAME_CSV_ACTIONS),
L"csv",
csvName
);
BREAK_ON_FAILED_HRESULT(hr);
String saveName;
GetWorkFileName(
normalPath,
String::load(IDS_FILE_NAME_UNDO),
L"ldf",
saveName
);
BREAK_ON_FAILED_HRESULT(hr);
String logPath;
Repair repair
(
csvReader409,
csvReaderIntl,
domainName,
rootContainerDn,
results,
ldiffName,
csvName,
saveName,
normalPath,
completeDcName,
caleeStruct,
stepIt,
totalSteps
);
hr=repair.run();
BREAK_ON_FAILED_HRESULT(hr);
} while(0);
CoUninitialize();
}
catch( const std::bad_alloc& )
{
// Since we are in an out of memory condition.
// we will not show allocate messages.
hr=Win32ToHresult(ERROR_OUTOFMEMORY);
}
LOG_HRESULT(hr);
return hr;
}
extern "C"
HRESULT
UpgradeDisplaySpecifiers
(
PWSTR logFilesPath,
GUID *OperationGuid,
BOOL dryRun,
PWSTR *errorMsg,//=NULL
void *caleeStruct,//=NULL
progressFunction stepIt,//=NULL
progressFunction totalSteps//=NULL
)
{
LOG_FUNCTION(UpgradeDisplaySpecifiers);
hResourceModuleHandle=::GetModuleHandle(NULL);
HRESULT hr=S_OK;
do
{
hr = ::CoInitialize(0);
ASSERT(SUCCEEDED(hr));
GUID guid;
if(OperationGuid==NULL)
{
hr = E_INVALIDARG;
error = String::format(IDS_NO_GUID);
break;
}
guid=*OperationGuid;
int sizeGuids=sizeof(guids)/sizeof(*guids);
bool found=false;
for(int t=0;(t<sizeGuids) && (!found);t++)
{
if (guids[t]==guid) found=true;
}
if(!found)
{
hr = E_INVALIDARG;
error = String::format(IDS_NO_OPERATION_GUID);
break;
}
hr=RunAnalysis(guid,logFilesPath,caleeStruct,stepIt,totalSteps);
BREAK_ON_FAILED_HRESULT(hr);
if(dryRun==false)
{
hr=RunRepair(logFilesPath,caleeStruct,stepIt,totalSteps);
BREAK_ON_FAILED_HRESULT(hr);
}
CoUninitialize();
} while(0);
if(FAILED(hr))
{
AllocError(hr,errorMsg,error);
}
LOG_HRESULT(hr);
return hr;
}