mirror of https://github.com/tongzx/nt5src
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.
477 lines
10 KiB
477 lines
10 KiB
|
|
#include "headers.hxx"
|
|
#include "dspecup.hpp"
|
|
#include "Analisys.hpp"
|
|
#include "repair.hpp"
|
|
#include "AnalisysResults.hpp"
|
|
#include "resource.h"
|
|
#include "CSVDSReader.hpp"
|
|
#include "constants.hpp"
|
|
#include "AdsiHelpers.hpp"
|
|
|
|
|
|
|
|
// Variables kept from analisys to repair
|
|
bool goodAnalisys=false;
|
|
AnalisysResults results;
|
|
String targetDomainControllerName;
|
|
String csvFileName,csv409Name;
|
|
CSVDSReader csvReaderIntl;
|
|
CSVDSReader csvReader409;
|
|
String rootContainerDn,ldapPrefix,domainName;
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
FindCsvFile(
|
|
String& csvFilePath,
|
|
String& csv409Path
|
|
)
|
|
{
|
|
LOG_FUNCTION(FindCsvFile);
|
|
|
|
csvFilePath.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"\\mui\\dispspec\\" + csvname;
|
|
|
|
if (FS::FileExists(csvPath))
|
|
{
|
|
csvFilePath = csvPath;
|
|
}
|
|
else
|
|
{
|
|
csvPath = L".\\" + csvname;
|
|
|
|
if (FS::FileExists(FS::NormalizePath(csvPath)))
|
|
{
|
|
csvFilePath = csvPath;
|
|
}
|
|
else
|
|
{
|
|
hr=S_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
csvname=L"409.csv";
|
|
csvPath = sys32dir + L"\\mui\\dispspec\\" + csvname;
|
|
|
|
if (FS::FileExists(csvPath))
|
|
{
|
|
csv409Path = csvPath;
|
|
}
|
|
else
|
|
{
|
|
csvPath = L".\\" + csvname;
|
|
if (FS::FileExists(FS::NormalizePath(csvPath)))
|
|
{
|
|
csv409Path = csvPath;
|
|
}
|
|
else
|
|
{
|
|
hr=S_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while(0);
|
|
|
|
|
|
LOG_HRESULT(hr);
|
|
LOG(csvFilePath);
|
|
LOG(csv409Path);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
InitializeADSI(
|
|
const String &targetDcName,
|
|
String &ldapPrefix,
|
|
String &rootContainerDn,
|
|
String &domainName
|
|
)
|
|
{
|
|
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());
|
|
hr=E_FAIL;
|
|
break;
|
|
}
|
|
|
|
if (!targetDc.IsDomainController())
|
|
{
|
|
error=String::format(
|
|
IDS_TARGET_IS_NOT_DC,
|
|
targetDcName.c_str());
|
|
hr=E_FAIL;
|
|
break;
|
|
}
|
|
|
|
String dcName = targetDc.GetActivePhysicalFullDnsName();
|
|
ldapPrefix = L"LDAP://" + dcName + 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.
|
|
|
|
SmartInterface<IADs> rootDse;
|
|
|
|
hr = AdsiOpenObject<IADs>(ldapPrefix + L"RootDSE", rootDse);
|
|
if (FAILED(hr))
|
|
{
|
|
error=String::format(
|
|
IDS_UNABLE_TO_CONNECT_TO_DC,
|
|
dcName.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);
|
|
hr=E_FAIL;
|
|
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);
|
|
|
|
if (hr == S_FALSE)
|
|
{
|
|
// no error looking, just not found.
|
|
error=String::format(IDS_DCPROMO_CSV_FILE_MISSING);
|
|
hr=E_FAIL;
|
|
break;
|
|
}
|
|
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;
|
|
}
|
|
|
|
|
|
void AllocError(HRESULT &hr,PWSTR *error,const String& src)
|
|
{
|
|
if (error==NULL) return;
|
|
*error=static_cast<PWSTR>(
|
|
CoTaskMemAlloc
|
|
(
|
|
(src.size()+1)*sizeof(wchar_t)
|
|
)
|
|
);
|
|
if(*error==NULL)
|
|
{
|
|
hr = Win32ToHresult(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
else
|
|
{
|
|
wcscpy(*error,src.c_str());
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
RunAnalisys
|
|
(
|
|
PWSTR *errorMsg/*=NULL*/,
|
|
void *caleeStruct/*=NULL*/,
|
|
progressFunction stepIt/*=NULL*/,
|
|
progressFunction totalSteps/*=NULL*/
|
|
)
|
|
{
|
|
LOG_FUNCTION(RunAnalisys);
|
|
HRESULT hr=S_OK;
|
|
|
|
goodAnalisys=false;
|
|
results.createContainers.clear();
|
|
results.conflictingXPObjects.clear();
|
|
results.createXPObjects.clear();
|
|
results.createW2KObjects.clear();
|
|
results.objectActions.clear();
|
|
results.customizedValues.clear();
|
|
results.extraneousValues.clear();
|
|
|
|
do
|
|
{
|
|
|
|
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);
|
|
|
|
hr=InitializeADSI(
|
|
targetDomainControllerName,
|
|
ldapPrefix,
|
|
rootContainerDn,
|
|
domainName);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
String reportName;
|
|
|
|
hr=GetWorkFileName(
|
|
String::load(IDS_FILE_NAME_REPORT),
|
|
L"txt",
|
|
reportName
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
|
|
Analisys analisys(
|
|
csvReader409,
|
|
csvReaderIntl,
|
|
ldapPrefix,
|
|
rootContainerDn,
|
|
results,
|
|
reportName,
|
|
caleeStruct,
|
|
stepIt,
|
|
totalSteps
|
|
);
|
|
|
|
hr=analisys.run();
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
} while(0);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
AllocError(hr,errorMsg,error);
|
|
}
|
|
else
|
|
{
|
|
goodAnalisys=true;
|
|
}
|
|
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
RunRepair
|
|
(
|
|
PWSTR *errorMsg/*=NULL*/,
|
|
void *caleeStruct/*=NULL*/,
|
|
progressFunction stepIt/*=NULL*/,
|
|
progressFunction totalSteps/*=NULL*/
|
|
)
|
|
{
|
|
LOG_FUNCTION(RunRepair);
|
|
HRESULT hr=S_OK;
|
|
do
|
|
{
|
|
if (!goodAnalisys)
|
|
{
|
|
hr=E_FAIL;
|
|
AllocError(hr,errorMsg,String::load(IDS_NO_ANALISYS));
|
|
break;
|
|
}
|
|
|
|
String ldiffName;
|
|
|
|
hr=GetWorkFileName(
|
|
String::load(IDS_FILE_NAME_LDIF_ACTIONS),
|
|
L"ldf",
|
|
ldiffName
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
String csvName;
|
|
|
|
hr=GetWorkFileName(
|
|
String::load(IDS_FILE_NAME_CSV_ACTIONS),
|
|
L"csv",
|
|
csvName
|
|
);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
String saveName;
|
|
|
|
hr=GetWorkFileName(
|
|
String::load(IDS_FILE_NAME_UNDO),
|
|
L"ldf",
|
|
saveName
|
|
);
|
|
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
String logPath;
|
|
|
|
hr=GetMyDocuments(logPath);
|
|
BREAK_ON_FAILED_HRESULT_ERROR(hr,String::format(IDS_NO_WORK_PATH));
|
|
|
|
Repair repair
|
|
(
|
|
csvReader409,
|
|
csvReaderIntl,
|
|
domainName,
|
|
rootContainerDn,
|
|
results,
|
|
ldiffName,
|
|
csvName,
|
|
saveName,
|
|
logPath,
|
|
caleeStruct,
|
|
stepIt,
|
|
totalSteps
|
|
);
|
|
|
|
hr=repair.run();
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
} while(0);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
AllocError(hr,errorMsg,error);
|
|
}
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
UpgradeDisplaySpecifiers
|
|
(
|
|
BOOL dryRun,
|
|
PWSTR *errorMsg/*=NULL*/,
|
|
void *caleeStruct/*=NULL*/,
|
|
progressFunction stepIt/*=NULL*/,
|
|
progressFunction totalSteps/*=NULL*/
|
|
)
|
|
{
|
|
LOG_FUNCTION(UpgradeDisplaySpecifiers);
|
|
HRESULT hr=S_OK;
|
|
do
|
|
{
|
|
hr=RunAnalisys(errorMsg,caleeStruct,stepIt,totalSteps);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
|
|
if(dryRun==false)
|
|
{
|
|
hr=RunRepair(errorMsg,caleeStruct,stepIt,totalSteps);
|
|
BREAK_ON_FAILED_HRESULT(hr);
|
|
}
|
|
} while(0);
|
|
|
|
LOG_HRESULT(hr);
|
|
return hr;
|
|
}
|