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.
 
 
 
 
 
 

3891 lines
116 KiB

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <winldap.h>
#include <ntldap.h>
#include <schedule.h>
#include <mkdso.h>
#include <frsrpc.h>
#include <ntdsapi.h>
#include <winber.h>
//Global data
BOOL bVerboseMode = FALSE;
PWCHAR DcName = NULL;
PLDAP pLdap = NULL;
BOOL bDebugMode = FALSE;
BOOL bAffectAll = FALSE;
PBYTE SchedMask = NULL;
PBYTE SchedOverride = NULL;
BOOL bCreateSet = FALSE;
BOOL bUpdateSet = FALSE;
BOOL bDelSet = FALSE;
BOOL bCreateMember = FALSE;
BOOL bUpdateMember = FALSE;
BOOL bDelMember = FALSE;
BOOL bCreateSubscriber = FALSE;
BOOL bUpdateSubscriber = FALSE;
BOOL bDelSubscriber = FALSE;
BOOL bDump = FALSE;
BOOL bSchedule = FALSE;
//
// Static array to print the replica set type.
//
WCHAR ReplicaSetTypeStr[][MAX_PATH] = {L"Invalid type",
L"Invalid type",
L"Sysvol",
L"Dfs",
L"Other"};
VOID
PrintScheduleGrid(
PUCHAR ScheduleData,
DWORD Mask
);
VOID
PrintSchedule(
PSCHEDULE Schedule,
DWORD Mask
);
DWORD
BindToDC (
IN PWCHAR pszDC,
OUT PLDAP *ppLDAP
)
/*++
Routine Description:
Sets up an LDAP connection to the specified server
Arguments:
pwszDC - DS DC to bind to
ppLDAP - The LDAP connection information is returned here
Return Value:
ERROR_SUCCESS - Success
--*/
{
DWORD dwErr = ERROR_SUCCESS;
ULONG ulOptions;
//
// if ldap_open is called with a server name the api will call DsGetDcName
// passing the server name as the domainname parm...bad, because
// DsGetDcName will make a load of DNS queries based on the server name,
// it is designed to construct these queries from a domain name...so all
// these queries will be bogus, meaning they will waste network bandwidth,
// time to fail, and worst case cause expensive on demand links to come up
// as referrals/forwarders are contacted to attempt to resolve the bogus
// names. By setting LDAP_OPT_AREC_EXCLUSIVE to on using ldap_set_option
// after the ldap_init but before any other operation using the ldap
// handle from ldap_init, the delayed connection setup will not call
// DsGetDcName, just gethostbyname, or if an IP is passed, the ldap client
// will detect that and use the address directly.
//
// *ppLDAP = ldap_open(pszDC, LDAP_PORT);
*ppLDAP = ldap_init(pszDC, LDAP_PORT);
if(*ppLDAP == NULL)
{
dwErr = ERROR_PATH_NOT_FOUND;
}
else
{
//
// set the options.
//
ulOptions = PtrToUlong(LDAP_OPT_ON);
ldap_set_option(*ppLDAP, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions);
//
// Do a bind...
//
dwErr = ldap_bind_s(*ppLDAP,
NULL,
NULL,
LDAP_AUTH_NEGOTIATE);
}
return(dwErr);
}
PWCHAR
FrsWcsDup(
PWCHAR OldStr
)
/*++
Routine Description:
Duplicate a string using our memory allocater
Arguments:
OldArg - string to duplicate
Return Value:
Duplicated string. Free with FrsFree().
--*/
{
PWCHAR NewStr;
//
// E.g., when duplicating NodePartner when none exists
//
if (OldStr == NULL)
return NULL;
NewStr = (PWCHAR)malloc((wcslen(OldStr) + 1) * sizeof(WCHAR));
wcscpy(NewStr, OldStr);
return NewStr;
}
VOID
AddMod(
PWCHAR AttrType,
PWCHAR AttrValue,
LDAPMod ***pppMod
)
/*++
Routine Description:
Add an attribute (plus values) to a structure that will eventually be
used in an ldap_add() function to add an object to the DS. The null-
terminated array referenced by pppMod grows with each call to this
routine. The array is freed by the caller using FreeMod().
Arguments:
AttrType - The object class of the object.
AttrValue - The value of the attribute.
pppMod - Address of an array of pointers to "attributes". Don't
give me that look -- this is an LDAP thing.
Return Value:
The pppMod array grows by one entry. The caller must free it with
FreeMod().
--*/
{
DWORD NumMod; // Number of entries in the Mod array
LDAPMod **ppMod; // Address of the first entry in the Mod array
LDAPMod *Attr; // An attribute structure
PWCHAR *Values; // An array of pointers to bervals
if (AttrValue == NULL)
return;
//
// The null-terminated array doesn't exist; create it
//
if (*pppMod == NULL) {
*pppMod = (LDAPMod **)malloc(sizeof (*pppMod));
**pppMod = NULL;
}
//
// Increase the array's size by 1
//
for (ppMod = *pppMod, NumMod = 2; *ppMod != NULL; ++ppMod, ++NumMod);
*pppMod = (LDAPMod **)realloc(*pppMod, sizeof (*pppMod) * NumMod);
//
// Add the new attribute + value to the Mod array
//
Values = (PWCHAR *)malloc(sizeof (PWCHAR) * 2);
Values[0] = _wcsdup(AttrValue);
Values[1] = NULL;
Attr = (LDAPMod *)malloc(sizeof (*Attr));
Attr->mod_values = Values;
Attr->mod_type = _wcsdup(AttrType);
// Attr->mod_op = LDAP_MOD_ADD;
Attr->mod_op = LDAP_MOD_REPLACE;
(*pppMod)[NumMod - 1] = NULL;
(*pppMod)[NumMod - 2] = Attr;
}
VOID
AddBerMod(
PWCHAR AttrType,
PCHAR AttrValue,
DWORD AttrValueLen,
LDAPMod ***pppMod
)
/*++
Routine Description:
Add an attribute (plus values) to a structure that will eventually be
used in an ldap_add() function to add an object to the DS. The null-
terminated array referenced by pppMod grows with each call to this
routine. The array is freed by the caller using FreeMod().
Arguments:
AttrType - The object class of the object.
AttrValue - The value of the attribute.
AttrValueLen - length of the attribute
pppMod - Address of an array of pointers to "attributes". Don't
give me that look -- this is an LDAP thing.
Return Value:
The pppMod array grows by one entry. The caller must free it with
FreeMod().
--*/
{
DWORD NumMod; // Number of entries in the Mod array
LDAPMod **ppMod; // Address of the first entry in the Mod array
LDAPMod *Attr; // An attribute structure
PLDAP_BERVAL Berval;
PLDAP_BERVAL *Values; // An array of pointers to bervals
if (AttrValue == NULL)
return;
//
// The null-terminated array doesn't exist; create it
//
if (*pppMod == NULL) {
*pppMod = (LDAPMod **)malloc(sizeof (*pppMod));
**pppMod = NULL;
}
//
// Increase the array's size by 1
//
for (ppMod = *pppMod, NumMod = 2; *ppMod != NULL; ++ppMod, ++NumMod);
*pppMod = (LDAPMod **)realloc(*pppMod, sizeof (*pppMod) * NumMod);
//
// Construct a berval
//
Berval = (PLDAP_BERVAL)malloc(sizeof(LDAP_BERVAL));
Berval->bv_len = AttrValueLen;
Berval->bv_val = (PCHAR)malloc(AttrValueLen);
CopyMemory(Berval->bv_val, AttrValue, AttrValueLen);
//
// Add the new attribute + value to the Mod array
//
Values = (PLDAP_BERVAL *)malloc(sizeof (PLDAP_BERVAL) * 2);
Values[0] = Berval;
Values[1] = NULL;
Attr = (LDAPMod *)malloc(sizeof (*Attr));
Attr->mod_bvalues = Values;
Attr->mod_type = _wcsdup(AttrType);
Attr->mod_op = LDAP_MOD_BVALUES | LDAP_MOD_REPLACE;
(*pppMod)[NumMod - 1] = NULL;
(*pppMod)[NumMod - 2] = Attr;
}
VOID
FreeMod(
LDAPMod ***pppMod
)
/*++
Routine Description:
Free the structure built by successive calls to AddMod().
Arguments:
pppMod - Address of a null-terminated array.
Return Value:
*pppMod set to NULL.
--*/
{
DWORD i, j;
LDAPMod **ppMod;
if (!pppMod || !*pppMod) {
return;
}
//
// For each attibute
//
ppMod = *pppMod;
for (i = 0; ppMod[i] != NULL; ++i) {
//
// For each value of the attribute
//
for (j = 0; (ppMod[i])->mod_values[j] != NULL; ++j) {
//
// Free the value
//
if (ppMod[i]->mod_op & LDAP_MOD_BVALUES) {
free(ppMod[i]->mod_bvalues[j]->bv_val);
}
free((ppMod[i])->mod_values[j]);
}
free((ppMod[i])->mod_values); // Free the array of pointers to values
free((ppMod[i])->mod_type); // Free the string identifying the attribute
free(ppMod[i]); // Free the attribute
}
free(ppMod); // Free the array of pointers to attributes
*pppMod = NULL; // Now ready for more calls to AddMod()
}
BOOL
LdapSearch(
PLDAP ldap,
PWCHAR Base,
ULONG Scope,
PWCHAR Filter,
PWCHAR Attrs[],
ULONG AttrsOnly,
LDAPMessage **Res,
BOOL Quiet
)
/*++
Routine Description:
Issue the ldap ldap_search_s call, check for errors, and check for
a shutdown in progress.
Arguments:
ldap
Base
Scope
Filter
Attrs
AttrsOnly
Res
Return Value:
The ldap array of values or NULL if the Base, DesiredAttr, or its values
does not exist. The ldap array is freed with ldap_value_free().
--*/
{
DWORD LStatus;
//
// Issue the ldap search
//
LStatus = ldap_search_s(ldap,
Base,
Scope,
Filter,
Attrs,
AttrsOnly,
Res);
//
// Check for errors
//
if (LStatus != LDAP_SUCCESS) {
if (!Quiet) {
DPRINT4("WARN - Error searching %ws for %ws; LStatus %d: %ws\n",
Base, Filter, LStatus, ldap_err2string(LStatus));
}
return FALSE;
}
//
// Return TRUE if not shutting down
//
return TRUE;
}
PWCHAR *
GetValues(
IN PLDAP Ldap,
IN PWCHAR Dn,
IN PWCHAR DesiredAttr,
IN BOOL Quiet
)
/*++
Routine Description:
Return the DS values for one attribute in an object.
Arguments:
ldap - An open, bound ldap port.
Base - The "pathname" of a DS object.
DesiredAttr - Return values for this attribute.
Quiet
Return Value:
An array of char pointers that represents the values for the attribute.
The caller must free the array with ldap_value_free(). NULL if unsuccessful.
--*/
{
PWCHAR Attr;
BerElement *Ber;
PLDAPMessage LdapMsg;
PLDAPMessage LdapEntry;
PWCHAR Attrs[2];
PWCHAR *Values = NULL;
//
// Search Base for all of its attributes + values
//
Attrs[0] = DesiredAttr;
Attrs[1] = NULL;
//
// Issue the ldap search
//
if (!LdapSearch(Ldap,
Dn,
LDAP_SCOPE_BASE,
CLASS_ANY,
Attrs,
0,
&LdapMsg,
Quiet)) {
return NULL;
}
LdapEntry = ldap_first_entry(Ldap, LdapMsg);
if (LdapEntry) {
Attr = ldap_first_attribute(Ldap, LdapEntry, &Ber);
if (Attr) {
Values = ldap_get_values(Ldap, LdapEntry, Attr);
}
}
ldap_msgfree(LdapMsg);
return Values;
}
BOOL
LdapSearchInit(
PLDAP ldap,
PWCHAR Base,
ULONG Scope,
PWCHAR Filter,
PWCHAR Attrs[],
ULONG AttrsOnly,
PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext,
BOOL Quiet
)
/*++
Routine Description:
Issue the ldap ldap_search_s call, check for errors, and check for
a shutdown in progress.
Arguments:
ldap
Base
Scope
Filter
Attrs
AttrsOnly
Res
FrsSearchContext
Return Value:
The ldap array of values or NULL if the Base, DesiredAttr, or its values
does not exist. The ldap array is freed with ldap_value_free().
--*/
{
DWORD LStatus = LDAP_SUCCESS;
PLDAPControl ServerControls[2];
berval cookie1 = { 0, NULL };
FrsSearchContext->bOpen = FALSE;
FrsSearchContext->LdapMsg = NULL;
FrsSearchContext->EntriesInPage = 0;
FrsSearchContext->CurrentEntry = 0;
FrsSearchContext->TotalEntries = 0;
FrsSearchContext->Filter = FrsWcsDup(Filter);
FrsSearchContext->BaseDn = FrsWcsDup(Base);
FrsSearchContext->Scope = Scope;
FrsSearchContext->PageSize = FRS_LDAP_SEARCH_PAGESIZE;
FrsSearchContext->Attrs = Attrs;
LStatus = ldap_create_page_control(ldap,
FrsSearchContext->PageSize,
&cookie1,
FALSE, // is critical
&ServerControls[0]
);
ServerControls[1] = NULL;
if (LStatus != LDAP_SUCCESS) {
DPRINT1("ldap_create_page_control returned error. LStatus = 0x%x\n", LStatus);
}
LStatus = ldap_search_ext_s(ldap,
FrsSearchContext->BaseDn,
FrsSearchContext->Scope,
FrsSearchContext->Filter,
FrsSearchContext->Attrs,
FALSE,
ServerControls,
NULL,
NULL,
0,
&FrsSearchContext->LdapMsg);
if (LStatus == LDAP_SUCCESS) {
FrsSearchContext->EntriesInPage = ldap_count_entries(ldap, FrsSearchContext->LdapMsg);
FrsSearchContext->CurrentEntry = 0;
FrsSearchContext->bOpen = TRUE;
}
return (LStatus == LDAP_SUCCESS);
}
PLDAPMessage
LdapSearchGetNextEntry(
PLDAP ldap,
PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext
)
/*++
Routine Description:
Issue the ldap ldap_search_s call, check for errors, and check for
a shutdown in progress.
Arguments:
ldap
FrsSearchContext
Return Value:
The ldap array of values or NULL if the Base, DesiredAttr, or its values
does not exist. The ldap array is freed with ldap_value_free().
--*/
{
FrsSearchContext->CurrentEntry += 1;
if ( FrsSearchContext->CurrentEntry == 1 ) {
FrsSearchContext->CurrentLdapMsg = ldap_first_entry(ldap ,FrsSearchContext->LdapMsg);
} else {
FrsSearchContext->CurrentLdapMsg = ldap_next_entry(ldap ,FrsSearchContext->CurrentLdapMsg);
}
return FrsSearchContext->CurrentLdapMsg;
}
DWORD
LdapSearchGetNextPage(
PLDAP ldap,
PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext
)
/*++
Routine Description:
Issue the ldap ldap_search_s call, check for errors, and check for
a shutdown in progress.
Arguments:
ldap
FrsSearchContext
Return Value:
The ldap array of values or NULL if the Base, DesiredAttr, or its values
does not exist. The ldap array is freed with ldap_value_free().
--*/
{
DWORD LStatus = LDAP_SUCCESS;
berval * CurrCookie = NULL;
PLDAPControl * CurrControls = NULL;
ULONG retcode = 0;
PLDAPControl ServerControls[2];
// Get the server control from the message, and make a new control with the cookie from the server
LStatus = ldap_parse_result(ldap, FrsSearchContext->LdapMsg, &retcode,NULL,NULL,NULL,&CurrControls,FALSE);
ldap_msgfree(FrsSearchContext->LdapMsg);
FrsSearchContext->LdapMsg = NULL;
if (LStatus == LDAP_SUCCESS) {
LStatus = ldap_parse_page_control(ldap, CurrControls, &FrsSearchContext->TotalEntries, &CurrCookie);
// under Exchange 5.5, before SP 2, this will fail with LDAP_CONTROL_NOT_FOUND when there are
// no more search results. With Exchange 5.5 SP 2, this succeeds, and gives us a cookie that will
// cause us to start over at the beginning of the search results.
}
if (LStatus == LDAP_SUCCESS) {
if ( CurrCookie->bv_len == 0 && CurrCookie->bv_val == 0 ) {
// under Exchange 5.5, SP 2, this means we're at the end of the results.
// if we pass in this cookie again, we will start over at the beginning of the search results.
LStatus = LDAP_CONTROL_NOT_FOUND;
}
ServerControls[0] = NULL;
ServerControls[1] = NULL;
if (LStatus == LDAP_SUCCESS) {
LStatus = ldap_create_page_control(ldap,
FrsSearchContext->PageSize,
CurrCookie,
FALSE,
ServerControls);
}
ldap_controls_free(CurrControls);
CurrControls = NULL;
ber_bvfree(CurrCookie);
CurrCookie = NULL;
}
// continue the search with the new cookie
if (LStatus == LDAP_SUCCESS) {
LStatus = ldap_search_ext_s(ldap,
FrsSearchContext->BaseDn,
FrsSearchContext->Scope,
FrsSearchContext->Filter,
FrsSearchContext->Attrs,
FALSE,
ServerControls,
NULL,
NULL,
0,
&FrsSearchContext->LdapMsg);
if ( (LStatus != LDAP_SUCCESS) && (LStatus != LDAP_CONTROL_NOT_FOUND) )
{
// LDAP_CONTROL_NOT_FOUND means that we have reached the end of the search results
// in Exchange 5.5, before SP 2 (the server doesn't return a page control when there
// are no more pages, so we get LDAP_CONTROL_NOT_FOUND when we try to extract the page
// control from the search results).
}
}
if (LStatus == LDAP_SUCCESS) {
FrsSearchContext->EntriesInPage = ldap_count_entries(ldap, FrsSearchContext->LdapMsg);
FrsSearchContext->CurrentEntry = 0;
}
return LdapMapErrorToWin32(LStatus);
}
PLDAPMessage
LdapSearchNext(
PLDAP ldap,
PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext
)
/*++
Routine Description:
Issue the ldap ldap_search_s call, check for errors, and check for
a shutdown in progress.
Arguments:
ldap
FrsSearchContext
Return Value:
The ldap array of values or NULL if the Base, DesiredAttr, or its values
does not exist. The ldap array is freed with ldap_value_free().
--*/
{
DWORD WStatus = ERROR_SUCCESS;
PLDAPMessage NextEntry = NULL;
if (FrsSearchContext->bOpen != TRUE)
{
NextEntry = NULL;
}
else
{
if (FrsSearchContext->EntriesInPage > FrsSearchContext->CurrentEntry )
{
// return the next entry from the current page
return LdapSearchGetNextEntry(ldap, FrsSearchContext);
}
else
{
// see if there are more pages of results to get
WStatus = LdapSearchGetNextPage(ldap, FrsSearchContext);
if (WStatus == ERROR_SUCCESS)
{
return LdapSearchGetNextEntry(ldap, FrsSearchContext);
}
}
}
return NextEntry;
}
VOID
LdapSearchClose(
PFRS_LDAP_SEARCH_CONTEXT FrsSearchContext
)
/*++
Routine Description:
Issue the ldap ldap_search_s call, check for errors, and check for
a shutdown in progress.
Arguments:
ldap
FrsSearchContext
Return Value:
The ldap array of values or NULL if the Base, DesiredAttr, or its values
does not exist. The ldap array is freed with ldap_value_free().
--*/
{
FrsSearchContext->bOpen = FALSE;
FrsSearchContext->EntriesInPage = 0;
FrsSearchContext->CurrentEntry = 0;
FrsSearchContext->TotalEntries = 0;
FREE(FrsSearchContext->Filter);
FREE(FrsSearchContext->BaseDn);
if (FrsSearchContext->LdapMsg != NULL) {
ldap_msgfree(FrsSearchContext->LdapMsg);
}
}
PWCHAR
GetRootDn(
PLDAP Ldap,
PWCHAR NamingContext
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PWCHAR Root; // DS pathname of configuration container
PWCHAR *Values; // values from the attribute "namingContexts"
DWORD NumVals; // number of values
//
// Return all of the values for the attribute namingContexts
//
Values = GetValues(Ldap, ATTR_ROOT, ATTR_NAMING_CONTEXTS, FALSE);
if (Values == NULL)
return NULL;
//
// Find the naming context that begins with CN=Configuration
//
NumVals = ldap_count_values(Values);
while (NumVals--) {
Root = wcsstr(Values[NumVals], NamingContext);
if (Root != NULL && Root == Values[NumVals]) {
Root = FrsWcsDup(Root);
ldap_value_free(Values);
return Root;
}
}
DPRINT1("ERROR - COULD NOT FIND %ws\n", NamingContext);
ldap_value_free(Values);
return NULL;
}
PWCHAR
ExtendDn(
PWCHAR Dn,
PWCHAR Cn
)
/*++
Routine Description:
Extend an existing DN with a new CN= component.
Arguments:
Dn - distinguished name
Cn - common name
Return Value:
CN=Cn,Dn
--*/
{
ULONG Len;
PWCHAR NewDn;
Len = wcslen(L"CN=,") + wcslen(Dn) + wcslen(Cn) + 1;
NewDn = (PWCHAR)malloc(Len * sizeof(WCHAR));
wcscpy(NewDn, L"CN=");
wcscat(NewDn, Cn);
wcscat(NewDn, L",");
wcscat(NewDn, Dn);
return NewDn;
}
PVOID *
FindValues(
PLDAPMessage LdapEntry,
PWCHAR DesiredAttr,
BOOL DoBerValues
)
/*++
Routine Description:
Return the DS values for one attribute in an entry.
Arguments:
Ldap - An open, bound ldap port.
LdapEntry - An ldap entry returned by ldap_search_s()
DesiredAttr - Return values for this attribute.
DoVerValues - Return the bervals
Return Value:
An array of char pointers that represents the values for the attribute.
The caller must free the array with ldap_value_free(). NULL if unsuccessful.
--*/
{
PWCHAR LdapAttr; // Retrieved from an ldap entry
BerElement *Ber; // Needed for scanning attributes
//
// Search the entry for the desired attribute
//
for (LdapAttr = ldap_first_attribute(pLdap, LdapEntry, &Ber);
LdapAttr != NULL;
LdapAttr = ldap_next_attribute(pLdap, LdapEntry, Ber)) {
if (_wcsicmp(DesiredAttr, LdapAttr) == 0) {
//
// Return the values for DesiredAttr
//
if (DoBerValues) {
return (PVOID *)ldap_get_values_len(pLdap, LdapEntry, LdapAttr);
} else {
return (PVOID *)ldap_get_values(pLdap, LdapEntry, LdapAttr);
}
}
}
return NULL;
}
PWCHAR
FindValue(
PLDAPMessage LdapEntry,
PWCHAR DesiredAttr
)
/*++
Routine Description:
Return a copy of the first DS value for one attribute in an entry.
Arguments:
Ldap - An open, bound ldap port.
LdapEntry - An ldap entry returned by ldap_search_s()
DesiredAttr - Return values for this attribute.
Return Value:
A zero-terminated string or NULL if the attribute or its value
doesn't exist. The string is freed with FREE().
--*/
{
PWCHAR Val;
PWCHAR *Values;
// Get ldap's array of values
Values = (PWCHAR *)FindValues(LdapEntry, DesiredAttr, FALSE);
// Copy the first value (if any)
if (Values) {
Val = new WCHAR[wcslen(Values[0]) + 1];
wcscpy(Val, Values[0]);
} else {
Val = NULL;
}
// Free ldap's array of values
ldap_value_free(Values);
return Val;
}
BOOL
FindBerValue(
PLDAPMessage Entry,
PWCHAR DesiredAttr,
ULONG *Len,
VOID **Value
)
/*++
Routine Description:
Return a copy of the attributes object's schedule
Arguments:
ldap - An open, bound ldap port.
Entry - An ldap entry returned by ldap_search_s()
DesiredAttr - desired attribute
Len - length of Value
Value - binary value
Return Value:
The address of a schedule or NULL. Free with FrsFree().
--*/
{
PLDAP_BERVAL *Values;
*Len = 0;
*Value = NULL;
//
// Get ldap's array of values
//
Values = (PLDAP_BERVAL *)FindValues(Entry, DesiredAttr, TRUE);
if (!Values) {
return FALSE;
}
//
// Return a copy of the schedule
//
*Len = Values[0]->bv_len;
if (*Len) {
*Value = new WCHAR[*Len];
CopyMemory(*Value, Values[0]->bv_val, *Len);
}
ldap_value_free_len(Values);
return TRUE;
}
PBYTE
ReadScheduleFile(
PWCHAR FileName
)
/*++
Routine Description:
Read a Hex formated byte array for a 7x24 schedule from a file.
Convert to a 7x24 binary schedule.
Arguments:
FileName - Name of schedule file.
Return Value:
ptr to schedule data array or NULL if invalid param.
--*/
{
HANDLE FileHandle;
PBYTE SchedData;
DWORD WStatus;
DWORD BytesRead;
DWORD DataByte, i, Day, Hour;
ULONG Remaining;
PCHAR pTC;
CHAR SchedText[FRST_SIZE_OF_SCHEDULE_GRID*3 + 50];
SchedData = new BYTE[FRST_SIZE_OF_SCHEDULE_GRID];
if (SchedData == NULL) {
printf("Error allocating memory.\n");
return NULL;
}
FileHandle = CreateFileW(
FileName, // lpszName
GENERIC_READ | GENERIC_WRITE, // fdwAccess
FILE_SHARE_READ | FILE_SHARE_WRITE, // fdwShareMode
NULL, // lpsa
OPEN_EXISTING, // fdwCreate
FILE_ATTRIBUTE_NORMAL, // fdwAttrAndFlags
NULL); // hTemplateFile
if (!HANDLE_IS_VALID(FileHandle)) {
WStatus = GetLastError();
printf("Error opening %ws WStatus: %d\n", FileName, WStatus);
FREE(SchedData);
return NULL;
}
if (!ReadFile(FileHandle, SchedText, sizeof(SchedText), &BytesRead, NULL)) {
WStatus = GetLastError();
printf("Error reading %ws WStatus: %d\n", FileName, WStatus);
FREE(SchedData);
FRS_CLOSE(FileHandle);
return NULL;
}
//
// remove any white-space chars, including CR-LF, used for formatting.
//
Remaining = BytesRead;
pTC = SchedText;
while (Remaining > 0) {
if (isspace((LONG) *pTC)) {
memcpy(pTC, pTC+1, Remaining-1);
} else {
pTC++;
}
Remaining -= 1;
}
BytesRead = pTC - SchedText;
if (BytesRead < FRST_SIZE_OF_SCHEDULE_GRID*2) {
printf("Error reading %ws Expecting %d bytes, Actual was %d bytes. Could be too much whitespace.\n",
FileName, FRST_SIZE_OF_SCHEDULE_GRID*2, BytesRead);
FREE(SchedData);
FRS_CLOSE(FileHandle);
return NULL;
}
//
// Result should be exactly the right size.
//
if (BytesRead != FRST_SIZE_OF_SCHEDULE_GRID*2) {
printf("Error reading %ws Expecting %d bytes, Actual was %d bytes\n",
FileName, FRST_SIZE_OF_SCHEDULE_GRID*2, BytesRead);
FREE(SchedData);
FRS_CLOSE(FileHandle);
return NULL;
}
//
// Convert to binary.
//
for (i=0; i<FRST_SIZE_OF_SCHEDULE_GRID; i++) {
if (sscanf(&SchedText[i*2], "%2x", &DataByte) != 1) {
SchedText[i*2+2] = '\0';
printf("Error reading %ws Invalid hex data (%s) for schedule byte %d.\n",
FileName, &SchedText[i*2], i);
FREE(SchedData);
FRS_CLOSE(FileHandle);
return NULL;
}
SchedData[i] = (BYTE) DataByte;
}
FRS_CLOSE(FileHandle);
return SchedData;
}
DWORD
BuildSchedule(
PBYTE *ppSchedule,
DWORD Interval,
DWORD Stagger,
DWORD Offset
)
/*++
Routine Description:
Build the schedule structure.
Arguments:
ppSchedule - pointer to return the schedule in.
Return Value:
winerror.
--*/
{
BYTE ScheduleData[FRST_SIZE_OF_SCHEDULE_GRID];
UINT i, Day, Hour;
DWORD Status = ERROR_SUCCESS;
*ppSchedule = new BYTE[FRST_SIZE_OF_SCHEDULE];
if (*ppSchedule == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// Set the values for the elements of the SCHEDULE structure.
//
((PSCHEDULE)*ppSchedule)->Size = FRST_SIZE_OF_SCHEDULE;
((PSCHEDULE)*ppSchedule)->Bandwidth = 0;
((PSCHEDULE)*ppSchedule)->NumberOfSchedules = 1;
((PSCHEDULE)*ppSchedule)->Schedules->Type = SCHEDULE_INTERVAL;
((PSCHEDULE)*ppSchedule)->Schedules->Offset = sizeof(SCHEDULE);
//
// Building the ScheduleData array depending on the requested schedule.
//
for (i=0 ; i<FRST_SIZE_OF_SCHEDULE_GRID ; ++i) {
if (Interval == 0) {
ScheduleData[i] = 0x00;
} else if (i < (Offset*Interval)) {
ScheduleData[i] = 0x00;
} else if ((i-(Offset*Interval))%(Interval * Stagger) == 0) {
ScheduleData[i] = 0x01;
} else {
ScheduleData[i] = 0x00;
}
}
//
// Use the supplied schedule mask to turn off regions of the above schedule.
//
if (SchedMask != NULL) {
for (i=0 ; i<FRST_SIZE_OF_SCHEDULE_GRID ; ++i) {
ScheduleData[i] &= ~SchedMask[i];
}
}
//
// Apply the supplied override schedule to regions of the above schedule.
//
if (SchedOverride != NULL) {
for (i=0 ; i<FRST_SIZE_OF_SCHEDULE_GRID ; ++i) {
ScheduleData[i] |= SchedOverride[i];
}
}
memcpy((*ppSchedule)+sizeof(SCHEDULE),ScheduleData, FRST_SIZE_OF_SCHEDULE_GRID);
return Status;
}
DWORD
DeleteSubscriber(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName,
PWCHAR MemberName,
PWCHAR ComputerDn
)
/*++
Routine Description:
Delete a subscriber.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR ReplicaSetDn = NULL;
PWCHAR MemberDn = NULL;
PWCHAR SubscriberDn = NULL;
PWCHAR MemberAttrs[3];
PWCHAR SubscriberAttrs[3];
PWCHAR SearchFilter = NULL;
DWORD NoOfMembers;
DWORD NoOfSubscribers;
PWCHAR LocalComputerDn = NULL;
PLDAPMessage LdapEntry = NULL;
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
MemberAttrs[0] = ATTR_DN;
MemberAttrs[1] = ATTR_COMPUTER_REF;
MemberAttrs[2] = NULL;
SubscriberAttrs[0] = ATTR_DN;
SubscriberAttrs[1] = ATTR_MEMBER_REF;
SubscriberAttrs[2] = NULL;
//
// We need to get to the member object and the computer
// object.
// To get to the member object we need the member name or
// the computer dn.
// To get to the computer object we need a member with
// valid computerref or the computerdn parameter.
//
if ((MemberName == NULL) && (ComputerDn == NULL)) {
Status = MKDSOE_BAD_ARG;
return Status;
}
SearchFilter = (PWCHAR) malloc(
(max((ComputerDn != NULL)?wcslen(ComputerDn):0,
(MemberDn != NULL)?wcslen(MemberDn):0)
+ MAX_PATH)
* sizeof(WCHAR));
ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
if (MemberName != NULL) {
MemberDn = ExtendDn(ReplicaSetDn, MemberName);
} else {
//
// Use computerdn to get the memberdn.
//
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_COMPUTER_REF);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, ComputerDn);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_MEMBER);
wcscat(SearchFilter, L")");
if (!LdapSearchInit(pLdap,
ReplicaSetDn,
LDAP_SCOPE_ONELEVEL,
SearchFilter,
MemberAttrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SUBSCRIBER_DELETE_FAILED;
goto CLEANUP;
}
NoOfMembers = FrsSearchContext.EntriesInPage;
if (NoOfMembers == 0) {
DPRINT0("Error deleting subscriber; member not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE;
goto CLEANUP;
}
if (NoOfMembers > 1) {
DPRINT0("Error deleting subscriber; duplicate members found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_DUPS_FOUND_DELETE;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
MemberDn = FindValue(LdapEntry, ATTR_DN);
}
LdapSearchClose(&FrsSearchContext);
}
DPRINT1("MemberDn:%ws\n", MemberDn);
if (ComputerDn == NULL) {
//
// Use MemberDn to find the computerDn. We will come here
// only if MemberName is supplied but computerdn is not.
//
if (!LdapSearchInit(pLdap,
MemberDn,
LDAP_SCOPE_BASE,
NULL,
MemberAttrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SUBSCRIBER_DELETE_FAILED;
goto CLEANUP;
}
NoOfMembers = FrsSearchContext.EntriesInPage;
if (NoOfMembers == 0) {
DPRINT0("Error deleting subscriber; member not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
LocalComputerDn = FindValue(LdapEntry, ATTR_COMPUTER_REF);
if (LocalComputerDn == NULL) {
DPRINT0("Error deleting subscriber; computerdn not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE;
goto CLEANUP;
}
}
LdapSearchClose(&FrsSearchContext);
} else {
LocalComputerDn = FrsWcsDup(ComputerDn);
}
//
// We have the computerdn and the memberdn. Now check if a subscriber
// already exists.
//
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_MEMBER_REF);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, MemberDn);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_SUBSCRIBER);
wcscat(SearchFilter, L")");
if (!LdapSearchInit(pLdap,
LocalComputerDn,
LDAP_SCOPE_SUBTREE,
SearchFilter,
SubscriberAttrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SUBSCRIBER_DELETE_FAILED;
goto CLEANUP;
}
NoOfSubscribers = FrsSearchContext.EntriesInPage;
if ((NoOfSubscribers > 1) && (bAffectAll != TRUE)) {
DPRINT0("Duplicate subscribers found. Deleting all.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_DUPS_FOUND_DELETE;
goto CLEANUP;
}
if (NoOfSubscribers != 0) {
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
SubscriberDn = FindValue(LdapEntry, ATTR_DN);
DPRINT1("Deleting Dn:%ws\n", SubscriberDn);
if (bDebugMode) {
DPRINT1("LStatus = ldap_delete_s(pLdap, %ws);\n", SubscriberDn);
} else {
LStatus = ldap_delete_s(pLdap, SubscriberDn);
if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't delete %ws: %ws\n",
SubscriberDn, ldap_err2string(LStatus));
Status = MKDSOE_SUBSCRIBER_DELETE_FAILED;
}
}
FREE(SubscriberDn);
}
} else {
DPRINT0("Warning deleting; subscriber not found.\n");
Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE;
}
LdapSearchClose(&FrsSearchContext);
CLEANUP:
FREE(SearchFilter);
FREE(ReplicaSetDn);
FREE(MemberDn);
FREE(LocalComputerDn);
FREE(SubscriberDn);
FreeMod(&Mod);
return Status;
}
DWORD
UpdateSubscriber(
PWCHAR SubscriberDn,
PWCHAR MemberRef,
PWCHAR RootPath,
PWCHAR StagePath
)
/*++
Routine Description:
Update the subscriber.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR Attrs[5];
PLDAPMessage LdapEntry = NULL;
PWCHAR CurMemberRef = NULL;
PWCHAR CurRootPath = NULL;
PWCHAR CurStagePath = NULL;
DWORD NoOfSubscribers;
BOOL bNeedsUpdate = FALSE;
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
Attrs[0] = ATTR_DN;
Attrs[1] = ATTR_MEMBER_REF;
Attrs[2] = ATTR_REPLICA_ROOT;
Attrs[3] = ATTR_REPLICA_STAGE;
Attrs[4] = NULL;
if (!LdapSearchInit(pLdap,
SubscriberDn,
LDAP_SCOPE_BASE,
NULL,
Attrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SUBSCRIBER_OBJ_UPDATE_FAILED;
goto CLEANUP;
}
NoOfSubscribers = FrsSearchContext.EntriesInPage;
if (NoOfSubscribers == 0) {
DPRINT0("Error updating; subscriber not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_NOT_FOUND_UPDATE;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
CurMemberRef = FindValue(LdapEntry, ATTR_MEMBER_REF);
CurRootPath = FindValue(LdapEntry, ATTR_REPLICA_ROOT);
CurStagePath = FindValue(LdapEntry, ATTR_REPLICA_STAGE);
}
LdapSearchClose(&FrsSearchContext);
DPRINT1("SubscriberDn:%ws\n", SubscriberDn);
// Check ATTR_MEMBER_REF
// if a ref is supplied then make sure it is same as the current ref.
// if a ref is not supplied then leave it as it is.
if (MemberRef != NULL) {
if ((CurMemberRef == NULL) ||
((CurMemberRef != NULL) && wcscmp(MemberRef, CurMemberRef))) {
AddMod(ATTR_MEMBER_REF, MemberRef, &Mod);
bNeedsUpdate = TRUE;
DPRINT1(" New FrsMemberReference:%ws\n", MemberRef);
}
}
// Check ATTR_REPLICA_ROOT
// if a path is supplied then make sure it is same as the current path.
// if a path is not supplied then leave it as it is.
if (RootPath != NULL) {
if ((CurRootPath == NULL) ||
((CurRootPath != NULL) && wcscmp(RootPath, CurRootPath))) {
AddMod(ATTR_REPLICA_ROOT, RootPath, &Mod);
bNeedsUpdate = TRUE;
DPRINT1(" New FrsRootPath:%ws\n", RootPath);
}
}
// Check ATTR_REPLICA_STAGE
// if a path is supplied then make sure it is same as the current path.
// if a path is not supplied then leave it as it is.
if (StagePath != NULL) {
if ((CurStagePath == NULL) ||
((CurStagePath != NULL) && wcscmp(StagePath, CurStagePath))) {
AddMod(ATTR_REPLICA_STAGE, StagePath, &Mod);
bNeedsUpdate = TRUE;
DPRINT1(" New FrsRootPath:%ws\n", StagePath);
}
}
if (bNeedsUpdate) {
if (bDebugMode) {
DPRINT1("LStatus = ldap_modify_s(pLdap, %ws, Mod);\n", SubscriberDn);
} else {
LStatus = ldap_modify_s(pLdap, SubscriberDn, Mod);
if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't update %ws: %ws\n",
SubscriberDn, ldap_err2string(LStatus));
Status = MKDSOE_SUBSCRIBER_OBJ_UPDATE_FAILED;
}
}
} else {
DPRINT0("No update required\n");
}
CLEANUP:
FREE(CurMemberRef);
FREE(CurRootPath);
FREE(CurStagePath);
FreeMod(&Mod);
return Status;
}
DWORD
CreateNewSubscriber(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName,
PWCHAR MemberName,
PWCHAR ComputerDn,
PWCHAR RootPath,
PWCHAR StagePath,
PWCHAR RefDCName
)
/*++
Routine Description:
Create a new subscriber.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR ReplicaSetDn = NULL;
PWCHAR MemberDn = NULL;
PWCHAR SubscriberDn = NULL;
PWCHAR SubscriptionDn = NULL;
PWCHAR MemberAttrs[3];
PWCHAR SubscriberAttrs[3];
PWCHAR SearchFilter = NULL;
DWORD NoOfMembers;
DWORD NoOfSubscribers;
PWCHAR LocalComputerDn = NULL;
PLDAPMessage LdapEntry = NULL;
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
MemberAttrs[0] = ATTR_DN;
MemberAttrs[1] = ATTR_COMPUTER_REF;
MemberAttrs[2] = NULL;
SubscriberAttrs[0] = ATTR_DN;
SubscriberAttrs[1] = ATTR_MEMBER_REF;
SubscriberAttrs[2] = NULL;
//
// We need to get to the member object and the computer
// object.
// To get to the member object we need the member name or
// the computer dn.
// To get to the computer object we need a member with
// valid computerref or the computerdn parameter.
//
if ((MemberName == NULL) && (ComputerDn == NULL)) {
Status = MKDSOE_BAD_ARG;
return Status;
}
SearchFilter = (PWCHAR) malloc(
(max((ComputerDn != NULL)?wcslen(ComputerDn):0,
(MemberDn != NULL)?wcslen(MemberDn):0)
+ MAX_PATH)
* sizeof(WCHAR));
ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
if (MemberName != NULL) {
MemberDn = ExtendDn(ReplicaSetDn, MemberName);
} else {
//
// Use computerdn to get the memberdn.
//
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_COMPUTER_REF);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, ComputerDn);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_MEMBER);
wcscat(SearchFilter, L")");
if (!LdapSearchInit(pLdap,
ReplicaSetDn,
LDAP_SCOPE_ONELEVEL,
SearchFilter,
MemberAttrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
NoOfMembers = FrsSearchContext.EntriesInPage;
if (NoOfMembers == 0) {
DPRINT0("Error creating subscriber; member not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
if (NoOfMembers > 1) {
DPRINT0("Error creating subscriber; duplicate members found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_DUPS_FOUND_UPDATE;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
MemberDn = FindValue(LdapEntry, ATTR_DN);
}
LdapSearchClose(&FrsSearchContext);
}
DPRINT1("MemberDn:%ws\n", MemberDn);
if (ComputerDn == NULL) {
//
// Use MemberDn to find the computerDn. We will come here
// only if MemberName is supplied but computerdn is not.
//
if (!LdapSearchInit(pLdap,
MemberDn,
LDAP_SCOPE_BASE,
NULL,
MemberAttrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
NoOfMembers = FrsSearchContext.EntriesInPage;
if (NoOfMembers == 0) {
DPRINT0("Error creating subscriber; member not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
LocalComputerDn = FindValue(LdapEntry, ATTR_COMPUTER_REF);
if (LocalComputerDn == NULL) {
DPRINT0("Error creating subscriber; computerdn not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
}
LdapSearchClose(&FrsSearchContext);
} else {
LocalComputerDn = FrsWcsDup(ComputerDn);
}
//
// We have the computerdn and the memberdn. Now check if a subscriber
// already exists.
//
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_MEMBER_REF);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, MemberDn);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_SUBSCRIBER);
wcscat(SearchFilter, L")");
if (!LdapSearchInit(pLdap,
LocalComputerDn,
LDAP_SCOPE_SUBTREE,
SearchFilter,
SubscriberAttrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
NoOfSubscribers = FrsSearchContext.EntriesInPage;
if (NoOfSubscribers > 1) {
DPRINT0("Error creating subscriber; duplicate found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SUBSCRIBER_DUPS_FOUND_UPDATE;
goto CLEANUP;
}
if (NoOfSubscribers == 1) {
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
SubscriberDn = FindValue(LdapEntry, ATTR_DN);
}
Status = UpdateSubscriber(SubscriberDn, MemberDn, RootPath, StagePath);
} else {
SubscriptionDn = ExtendDn(LocalComputerDn, MKDSOE_SUBSCRIPTION);
// ATTR_DN
DPRINT1("SubscriptionDn:%ws\n", SubscriptionDn);
AddMod(ATTR_CLASS, ATTR_SUBSCRIPTIONS, &Mod);
if (bDebugMode) {
DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriptionDn);
} else {
LStatus = ldap_add_s(pLdap, SubscriptionDn, Mod);
if ((LStatus != LDAP_ALREADY_EXISTS) && (LStatus != LDAP_SUCCESS)) {
DPRINT2("ERROR - Can't create %ws: %ws\n",
SubscriptionDn, ldap_err2string(LStatus));
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
}
FreeMod(&Mod);
SubscriberDn = ExtendDn(SubscriptionDn, ReplicaSetName);
// ATTR_DN
DPRINT1("SubscriberDn:%ws\n", SubscriberDn);
AddMod(ATTR_CLASS, ATTR_SUBSCRIBER, &Mod);
// ATTR_MEMBER_REF
AddMod(ATTR_MEMBER_REF, MemberDn, &Mod);
DPRINT1(" FrsMemberReference:%ws\n", MemberDn);
// ATTR_REPLICA_ROOT
AddMod(ATTR_REPLICA_ROOT, RootPath, &Mod);
DPRINT1(" FrsRootPath:%ws\n", RootPath);
// ATTR_REPLICA_STAGE
AddMod(ATTR_REPLICA_STAGE, StagePath, &Mod);
DPRINT1(" FrsStagePath:%ws\n", StagePath);
if (bDebugMode) {
DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", SubscriberDn);
} else {
LStatus = ldap_add_s(pLdap, SubscriberDn, Mod);
if ((LStatus == LDAP_CONSTRAINT_VIOLATION) && RefDCName != NULL) {
//
// prepare the server hint. Needed in case the member object
// is just created on another DC than the one on which the
// subscriber is being created.
//
LDAPControl simpleControl;
PLDAPControl controlArray[2];
INT rc;
BERVAL* pBerVal = NULL;
BerElement* pBer;
pBer = ber_alloc_t(LBER_USE_DER);
if (!pBer)
{
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
DPRINT1("Sending binding DC Name %ws\n",RefDCName);
rc = ber_printf(pBer,"{io}", 0, RefDCName, wcslen(RefDCName) * sizeof(WCHAR));
if ( rc == -1 ) {
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
rc = ber_flatten(pBer, &pBerVal);
if (rc == -1)
{
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
ber_free(pBer,1);
controlArray[0] = &simpleControl;
controlArray[1] = NULL;
// simpleControl.ldctl_oid = LDAP_SERVER_GC_VERIFY_NAME_OID_W;
simpleControl.ldctl_oid = LDAP_SERVER_VERIFY_NAME_OID_W;
simpleControl.ldctl_iscritical = TRUE;
simpleControl.ldctl_value = *pBerVal;
LStatus = ldap_add_ext_s(
pLdap,
SubscriberDn,
Mod,
(PLDAPControl *)&controlArray, //ServerControls,
NULL //ClientControls,
);
}
if (LStatus == LDAP_ALREADY_EXISTS) {
//
// If the object already exists then convert the create to an update.
// This is to allow the user to run the data file with creates twice without
// generating errors but only fixing the objects that have changed.
//
Status = UpdateSubscriber(SubscriberDn, MemberDn, RootPath, StagePath);
} else if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't create %ws: %ws\n",
SubscriberDn, ldap_err2string(LStatus));
Status = MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED;
}
}
}
LdapSearchClose(&FrsSearchContext);
CLEANUP:
FreeMod(&Mod);
FREE(ReplicaSetDn);
FREE(MemberDn);
FREE(SubscriberDn);
FREE(SubscriptionDn);
FREE(SearchFilter);
FREE(LocalComputerDn);
return Status;
}
DWORD
DeleteReplicaMember(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName,
PWCHAR MemberName,
PWCHAR ComputerDn
)
/*++
Routine Description:
Delete the replica member.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR ReplicaSetDn = NULL;
PWCHAR MemberDn = NULL;
PWCHAR MemberCn = NULL;
PWCHAR ComputerRef = NULL;
PWCHAR Attrs[5];
PLDAPMessage LdapEntry = NULL;
PWCHAR SearchFilter = NULL;
DWORD NoOfMembers;
BOOL bNeedsUpdate = FALSE;
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
Attrs[0] = ATTR_DN;
Attrs[1] = ATTR_CN;
Attrs[2] = ATTR_COMPUTER_REF;
Attrs[3] = ATTR_SERVER_REF;
Attrs[4] = NULL;
SearchFilter = (PWCHAR) malloc(
(((ComputerDn != NULL)?wcslen(ComputerDn):0)
+ MAX_PATH)
* sizeof(WCHAR));
ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
if (MemberName != NULL) {
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_CN);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, MemberName);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_MEMBER);
wcscat(SearchFilter, L")");
} else if (ComputerDn != NULL){
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_COMPUTER_REF);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, ComputerDn);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_MEMBER);
wcscat(SearchFilter, L")");
} else {
wcscpy(SearchFilter, CLASS_MEMBER);
}
if (!LdapSearchInit(pLdap,
ReplicaSetDn,
LDAP_SCOPE_ONELEVEL,
SearchFilter,
Attrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_MEMBER_DELETE_FAILED;
goto CLEANUP;
}
NoOfMembers = FrsSearchContext.EntriesInPage;
if ((NoOfMembers > 1) && (bAffectAll != TRUE)) {
DPRINT0("Duplicate members found. Deleting all.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_MEMBER_DUPS_FOUND_DELETE;
goto CLEANUP;
}
if (NoOfMembers != 0) {
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
MemberDn = FindValue(LdapEntry, ATTR_DN);
MemberCn = FindValue(LdapEntry, ATTR_CN);
ComputerRef = FindValue(LdapEntry, ATTR_COMPUTER_REF);
//
// If asked to delete the corresponding subscriber then
// do that first.
//
if (bDelSubscriber && ((ComputerRef != NULL) || (ComputerDn != NULL))) {
Status = DeleteSubscriber(NTFRSSettingsDn, ReplicaSetName,
MemberCn,
(ComputerRef != NULL)?ComputerRef:ComputerDn);
if (Status != MKDSOE_SUCCESS) {
LdapSearchClose(&FrsSearchContext);
goto CLEANUP;
}
}
DPRINT1("Deleting Dn:%ws\n", MemberDn);
if (bDebugMode) {
DPRINT1("LStatus = ldap_delete_s(pLdap, %ws);\n", MemberDn);
} else {
LStatus = ldap_delete_s(pLdap, MemberDn);
if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't delete %ws: %ws\n",
MemberDn, ldap_err2string(LStatus));
Status = MKDSOE_MEMBER_DELETE_FAILED;
}
}
FREE(MemberDn);
FREE(MemberCn);
FREE(ComputerRef);
}
} else {
DPRINT0("Warning deleting; member not found.\n");
Status = MKDSOE_MEMBER_NOT_FOUND_DELETE;
}
LdapSearchClose(&FrsSearchContext);
CLEANUP:
FreeMod(&Mod);
FREE(ReplicaSetDn);
FREE(MemberDn);
FREE(MemberCn);
FREE(ComputerRef);
FREE(SearchFilter);
return Status;
}
DWORD
UpdateReplicaMember(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName,
PWCHAR MemberName,
PWCHAR ComputerDn,
PWCHAR ServerRef,
PWCHAR RefDCName
)
/*++
Routine Description:
Update the replica member parameters.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR ReplicaSetDn = NULL;
PWCHAR MemberDn = NULL;
PWCHAR Attrs[4];
PLDAPMessage LdapEntry = NULL;
PWCHAR SearchFilter = NULL;
PWCHAR CurComputerRef = NULL;
PWCHAR CurServerRef = NULL;
DWORD NoOfMembers;
BOOL bNeedsUpdate = FALSE;
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
Attrs[0] = ATTR_DN;
Attrs[1] = ATTR_COMPUTER_REF;
Attrs[2] = ATTR_SERVER_REF;
Attrs[3] = NULL;
SearchFilter = (PWCHAR) malloc(
(((ComputerDn != NULL)?wcslen(ComputerDn):0)
+ MAX_PATH)
* sizeof(WCHAR));
ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
if (MemberName != NULL) {
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_CN);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, MemberName);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_MEMBER);
wcscat(SearchFilter, L")");
} else {
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_COMPUTER_REF);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, ComputerDn);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_MEMBER);
wcscat(SearchFilter, L")");
}
if (!LdapSearchInit(pLdap,
ReplicaSetDn,
LDAP_SCOPE_ONELEVEL,
SearchFilter,
Attrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
goto CLEANUP;
}
NoOfMembers = FrsSearchContext.EntriesInPage;
if (NoOfMembers == 0) {
DPRINT0("Error updating; member not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_MEMBER_NOT_FOUND_UPDATE;
goto CLEANUP;
}
if (NoOfMembers > 1) {
DPRINT0("Error updating; duplicate members found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_MEMBER_DUPS_FOUND_UPDATE;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
MemberDn = FindValue(LdapEntry, ATTR_DN);
CurComputerRef = FindValue(LdapEntry, ATTR_COMPUTER_REF);
CurServerRef = FindValue(LdapEntry, ATTR_SERVER_REF);
}
LdapSearchClose(&FrsSearchContext);
DPRINT1("MemberDn:%ws\n", MemberDn);
// Check ATTR_COMPUTER_REF
// if a ref is supplied then make sure it is same as the current ref.
// if a ref is not supplied then leave it as it is.
if (ComputerDn != NULL) {
if ((CurComputerRef == NULL) ||
((CurComputerRef != NULL) && wcscmp(ComputerDn, CurComputerRef))) {
AddMod(ATTR_COMPUTER_REF, ComputerDn, &Mod);
bNeedsUpdate = TRUE;
DPRINT1(" New FrsComputerReference:%ws\n", ComputerDn);
}
}
// Check ATTR_SERVER_REF
// if a ref is supplied then make sure it is same as the current ref.
// if a ref is not supplied then leave it as it is.
if (ServerRef != NULL) {
if ((CurServerRef == NULL) ||
((CurServerRef != NULL) && wcscmp(ServerRef, CurServerRef))) {
AddMod(ATTR_SERVER_REF, ServerRef, &Mod);
bNeedsUpdate = TRUE;
DPRINT1(" New ServerReference:%ws\n", ServerRef);
}
}
if (bNeedsUpdate) {
if (bDebugMode) {
DPRINT1("LStatus = ldap_modify_s(pLdap, %ws, Mod);\n", MemberDn);
} else {
LStatus = ldap_modify_s(pLdap, MemberDn, Mod);
if ((LStatus == LDAP_CONSTRAINT_VIOLATION) && RefDCName != NULL) {
//
// prepare the server hint. Needed in case the member object
// is just created on another DC than the one on which the
// subscriber is being created.
//
LDAPControl simpleControl;
PLDAPControl controlArray[2];
INT rc;
BERVAL* pBerVal = NULL;
BerElement* pBer;
pBer = ber_alloc_t(LBER_USE_DER);
if (!pBer)
{
Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
goto CLEANUP;
}
DPRINT1("Sending binding DC Name %ws\n",RefDCName);
rc = ber_printf(pBer,"{io}", 0, RefDCName, wcslen(RefDCName) * sizeof(WCHAR));
if ( rc == -1 ) {
Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
goto CLEANUP;
}
rc = ber_flatten(pBer, &pBerVal);
if (rc == -1)
{
Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
goto CLEANUP;
}
ber_free(pBer,1);
controlArray[0] = &simpleControl;
controlArray[1] = NULL;
// simpleControl.ldctl_oid = LDAP_SERVER_GC_VERIFY_NAME_OID_W;
simpleControl.ldctl_oid = LDAP_SERVER_VERIFY_NAME_OID_W;
simpleControl.ldctl_iscritical = TRUE;
simpleControl.ldctl_value = *pBerVal;
LStatus = ldap_modify_ext_s(
pLdap,
MemberDn,
Mod,
(PLDAPControl *)&controlArray, //ServerControls,
NULL //ClientControls,
);
}
if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't update %ws: %ws\n",
MemberDn, ldap_err2string(LStatus));
Status = MKDSOE_MEMBER_OBJ_UPDATE_FAILED;
}
}
} else {
DPRINT0("No update required\n");
}
CLEANUP:
FreeMod(&Mod);
FREE(ReplicaSetDn);
FREE(MemberDn);
FREE(SearchFilter);
FREE(CurComputerRef);
FREE(CurServerRef);
return Status;
}
DWORD
CreateNewReplicaMember(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName,
PWCHAR MemberName,
PWCHAR ComputerDn,
PWCHAR ServerRef,
PWCHAR RefDCName
)
/*++
Routine Description:
Create a new replica member.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR ReplicaSetDn = NULL;
PWCHAR MemberDn = NULL;
ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
MemberDn = ExtendDn(ReplicaSetDn, MemberName);
// ATTR_DN
DPRINT1("MemberDn:%ws\n", MemberDn);
AddMod(ATTR_CLASS, ATTR_MEMBER, &Mod);
// ATTR_COMPUTER_REF
if (ComputerDn != NULL) {
AddMod(ATTR_COMPUTER_REF, ComputerDn, &Mod);
DPRINT1(" FrsComputerReference:%ws\n", ComputerDn);
}
// ATTR_SERVER_REF
if (ServerRef != NULL) {
AddMod(ATTR_SERVER_REF, ServerRef, &Mod);
DPRINT1(" ServerReference:%ws\n", ServerRef);
}
if (bDebugMode) {
DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", MemberDn);
} else {
LStatus = ldap_add_s(pLdap, MemberDn, Mod);
if ((LStatus == LDAP_CONSTRAINT_VIOLATION) && RefDCName != NULL) {
//
// prepare the server hint. Needed in case the member object
// is just created on another DC than the one on which the
// subscriber is being created.
//
LDAPControl simpleControl;
PLDAPControl controlArray[2];
INT rc;
BERVAL* pBerVal = NULL;
BerElement* pBer;
pBer = ber_alloc_t(LBER_USE_DER);
if (!pBer)
{
Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
DPRINT1("Sending binding DC Name %ws\n",RefDCName);
rc = ber_printf(pBer,"{io}", 0, RefDCName, wcslen(RefDCName) * sizeof(WCHAR));
if ( rc == -1 ) {
Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
rc = ber_flatten(pBer, &pBerVal);
if (rc == -1)
{
Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
goto CLEANUP;
}
ber_free(pBer,1);
controlArray[0] = &simpleControl;
controlArray[1] = NULL;
// simpleControl.ldctl_oid = LDAP_SERVER_GC_VERIFY_NAME_OID_W;
simpleControl.ldctl_oid = LDAP_SERVER_VERIFY_NAME_OID_W;
simpleControl.ldctl_iscritical = TRUE;
simpleControl.ldctl_value = *pBerVal;
LStatus = ldap_add_ext_s(
pLdap,
MemberDn,
Mod,
(PLDAPControl *)&controlArray, //ServerControls,
NULL //ClientControls,
);
}
if (LStatus == LDAP_ALREADY_EXISTS) {
//
// If the object already exists then convert the create to an update.
// This is to allow the user to run the data file with creates twice without
// generating errors but only fixing the objects that have changed.
//
Status = UpdateReplicaMember(NTFRSSettingsDn,
ReplicaSetName,
MemberName,
ComputerDn,
ServerRef,
RefDCName);
} else if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't create %ws: %ws\n",
MemberDn, ldap_err2string(LStatus));
Status = MKDSOE_MEMBER_OBJ_CRE_FAILED;
}
}
CLEANUP:
FreeMod(&Mod);
FREE(ReplicaSetDn);
FREE(MemberDn);
return Status;
}
DWORD
DeleteReplicaSet(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName
)
/*++
Routine Description:
delete replica set.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR ReplicaSetDn = NULL;
PWCHAR Attrs[2];
PLDAPMessage LdapEntry = NULL;
WCHAR SearchFilter[MAX_PATH];
DWORD NoOfSets;
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
Attrs[0] = ATTR_DN;
Attrs[1] = NULL;
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_CN);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, ReplicaSetName);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_NTFRS_REPLICA_SET);
wcscat(SearchFilter, L")");
if (!LdapSearchInit(pLdap,
NTFRSSettingsDn,
LDAP_SCOPE_SUBTREE,
SearchFilter,
Attrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SET_DELETE_FAILED;
goto CLEANUP;
}
NoOfSets = FrsSearchContext.EntriesInPage;
if (NoOfSets == 0) {
DPRINT0("Error deleting; connection not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SET_NOT_FOUND_DELETE;
goto CLEANUP;
}
if (NoOfSets > 1) {
DPRINT0("Error deleting; duplicate sets found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SET_DUPS_FOUND_DELETE;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
ReplicaSetDn = FindValue(LdapEntry, ATTR_DN);
DPRINT1("Deleting Dn:%ws\n", ReplicaSetDn);
if (bDebugMode) {
DPRINT1("LStatus = ldap_delete_s(pLdap, %ws);\n", ReplicaSetDn);
} else {
LStatus = ldap_delete_s(pLdap, ReplicaSetDn);
if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't delete %ws: %ws\n",
ReplicaSetDn, ldap_err2string(LStatus));
Status = MKDSOE_SET_DELETE_FAILED;
}
}
}
LdapSearchClose(&FrsSearchContext);
CLEANUP:
FreeMod(&Mod);
FREE(ReplicaSetDn);
return Status;
}
DWORD
UpdateReplicaSet(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName,
PWCHAR ReplicaSetType,
PWCHAR FileFilter,
PWCHAR DirectoryFilter,
PBYTE pSchedule
)
/*++
Routine Description:
Update the replica set parameters.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR ReplicaSetDn = NULL;
PWCHAR Attrs[6];
PLDAPMessage LdapEntry = NULL;
WCHAR SearchFilter[MAX_PATH];
PWCHAR CurSetType = NULL;
PWCHAR CurFileFilter = NULL;
PWCHAR CurDirectoryFilter = NULL;
DWORD NoOfSets;
PSCHEDULE Schedule = NULL;
DWORD ScheduleLen;
BOOL bNeedsUpdate = FALSE;
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
Attrs[0] = ATTR_DN;
Attrs[1] = ATTR_SET_TYPE;
Attrs[2] = ATTR_FILE_FILTER;
Attrs[3] = ATTR_DIRECTORY_FILTER;
Attrs[4] = ATTR_SCHEDULE;
Attrs[5] = NULL;
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_CN);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, ReplicaSetName);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_NTFRS_REPLICA_SET);
wcscat(SearchFilter, L")");
if (!LdapSearchInit(pLdap,
NTFRSSettingsDn,
LDAP_SCOPE_SUBTREE,
SearchFilter,
Attrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SET_OBJ_UPDATE_FAILED;
goto CLEANUP;
}
NoOfSets = FrsSearchContext.EntriesInPage;
if (NoOfSets == 0) {
DPRINT0("Error updating; connection not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SET_NOT_FOUND_UPDATE;
goto CLEANUP;
}
if (NoOfSets > 1) {
DPRINT0("Error updating; duplicate connections found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SET_DUPS_FOUND_UPDATE;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
ReplicaSetDn = FindValue(LdapEntry, ATTR_DN);
CurSetType = FindValue(LdapEntry, ATTR_SET_TYPE);
CurFileFilter = FindValue(LdapEntry, ATTR_FILE_FILTER);
CurDirectoryFilter = FindValue(LdapEntry, ATTR_DIRECTORY_FILTER);
FindBerValue(LdapEntry, ATTR_SCHEDULE, &ScheduleLen, (VOID **)&Schedule);
}
LdapSearchClose(&FrsSearchContext);
DPRINT1("ReplicaSetDn:%ws\n", ReplicaSetDn);
// Check ATTR_SET_TYPE
// if a type is supplied then make sure it is same as the current type.
// if a type is not supplied then leave it as it is.
if (ReplicaSetType != NULL) {
if ((CurSetType == NULL) ||
((CurSetType != NULL) && wcscmp(ReplicaSetType, CurSetType))) {
AddMod(ATTR_SET_TYPE, ReplicaSetType, &Mod);
bNeedsUpdate = TRUE;
DPRINT1(" New FrsReplicaSetType:%ws\n", ReplicaSetType);
}
}
// Check ATTR_FILE_FILTER
// if a filter is supplied then make sure it is same as the current filter.
// if a filter is not supplied then leave it as it is.
if (FileFilter != NULL) {
if ((CurFileFilter == NULL) ||
((CurFileFilter != NULL) && wcscmp(FileFilter, CurFileFilter))) {
AddMod(ATTR_FILE_FILTER, FileFilter, &Mod);
bNeedsUpdate = TRUE;
DPRINT1(" New FrsFileFilter:%ws\n", FileFilter);
}
}
// Check ATTR_DIRECTORY_FILTER
// if a filter is supplied then make sure it is same as the current filter.
// if a filter is not supplied then leave it as it is.
if (DirectoryFilter != NULL) {
if ((CurDirectoryFilter == NULL) ||
((CurDirectoryFilter != NULL) && wcscmp(DirectoryFilter, CurDirectoryFilter))) {
AddMod(ATTR_DIRECTORY_FILTER, DirectoryFilter, &Mod);
bNeedsUpdate = TRUE;
DPRINT1(" New FrsDirectoryFilter:%ws\n", DirectoryFilter);
}
}
// Check ATTR_SCHEDULE
if (pSchedule != NULL) {
if ((Schedule == NULL) ||
(FRST_SIZE_OF_SCHEDULE != ScheduleLen) ||
(memcmp(Schedule, pSchedule, FRST_SIZE_OF_SCHEDULE))) {
bNeedsUpdate = TRUE;
AddBerMod(ATTR_SCHEDULE,(PCHAR)pSchedule,FRST_SIZE_OF_SCHEDULE,&Mod);
DPRINT0(" New schedule:\n");
PrintSchedule((PSCHEDULE)pSchedule, 0x0F);
}
}
if (bNeedsUpdate) {
if (bDebugMode) {
DPRINT1("LStatus = ldap_modify_s(pLdap, %ws, Mod);\n", ReplicaSetDn);
} else {
LStatus = ldap_modify_s(pLdap, ReplicaSetDn, Mod);
if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't update %ws: %ws\n",
ReplicaSetDn, ldap_err2string(LStatus));
Status = MKDSOE_SET_OBJ_UPDATE_FAILED;
}
}
} else {
DPRINT0("No update required\n");
}
CLEANUP:
FreeMod(&Mod);
FREE(ReplicaSetDn);
FREE(CurSetType);
FREE(CurFileFilter);
FREE(CurDirectoryFilter);
FREE(Schedule);
return Status;
}
DWORD
CreateNewReplicaSet(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName,
PWCHAR ReplicaSetType,
PWCHAR FileFilter,
PWCHAR DirectoryFilter,
PBYTE pSchedule
)
/*++
Routine Description:
Create a new replica Set.
Arguments:
Return Value:
--*/
{
LDAPMod **Mod = NULL;
DWORD LStatus = LDAP_SUCCESS;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR ReplicaSetDn = NULL;
UINT i;
ReplicaSetDn = ExtendDn(NTFRSSettingsDn, ReplicaSetName);
// ATTR_DN
DPRINT1("ReplicaSetDn:%ws\n", ReplicaSetDn);
AddMod(ATTR_CLASS, ATTR_REPLICA_SET, &Mod);
// ATTR_SET_TYPE
AddMod(ATTR_SET_TYPE, ReplicaSetType, &Mod);
DPRINT1(" FrsReplicaSetType:%ws\n", ReplicaSetType);
// ATTR_FILE_FILTER
if (FileFilter != NULL) {
AddMod(ATTR_FILE_FILTER, FileFilter, &Mod);
DPRINT1(" FrsFileFilter:%ws\n", FileFilter);
}
// ATTR_DIRECTORY_FILTER
if (DirectoryFilter != NULL) {
AddMod(ATTR_DIRECTORY_FILTER, DirectoryFilter, &Mod);
DPRINT1(" FrsDirectoryFilter:%ws\n", DirectoryFilter);
}
if (pSchedule != NULL) {
AddBerMod(ATTR_SCHEDULE,(PCHAR)pSchedule,FRST_SIZE_OF_SCHEDULE,&Mod);
PrintSchedule((PSCHEDULE)pSchedule, 0x0F);
}
if (bDebugMode) {
DPRINT1("LStatus = ldap_add_s(pLdap, %ws, Mod);\n", ReplicaSetDn);
} else {
LStatus = ldap_add_s(pLdap, ReplicaSetDn, Mod);
if (LStatus == LDAP_ALREADY_EXISTS) {
//
// If the object already exists then convert the create to an update.
// This is to allow the user to run the data file with creates twice without
// generating errors but only fixing the objects that have changed.
//
Status = UpdateReplicaSet(NTFRSSettingsDn,
ReplicaSetName,
ReplicaSetType,
FileFilter,
DirectoryFilter,
pSchedule);
} else if (LStatus != LDAP_SUCCESS) {
DPRINT2("ERROR - Can't create %ws: %ws\n",
ReplicaSetDn, ldap_err2string(LStatus));
Status = MKDSOE_SET_OBJ_CRE_FAILED;
}
}
FreeMod(&Mod);
FREE(ReplicaSetDn);
return Status;
}
VOID
PrintScheduleGrid(
PUCHAR ScheduleData,
DWORD Mask
)
/*++
Routine Description:
Print the schedule grid.
Arguments:
Schedule
Mask for each byte.
Return Value:
NONE
--*/
{
DWORD Day, Hour;
for (Day = 0; Day < 7; ++Day) {
printf(" Day %1d: ",Day + 1);
for (Hour = 0; Hour < 24; ++Hour) {
printf("%1x", *(ScheduleData + (Day * 24) + Hour) & Mask);
}
printf("\n");
}
}
VOID
PrintSchedule(
PSCHEDULE Schedule,
DWORD Mask
)
/*++
Routine Description:
Print the schedule.
Arguments:
Schedule
Mask for each byte.
Return Value:
NONE
--*/
{
PUCHAR ScheduleData;
DWORD i;
if (bVerboseMode) {
printf(" schedule:\n");
for (i = 0; i < Schedule->NumberOfSchedules; ++i) {
ScheduleData = ((PUCHAR)Schedule) + Schedule->Schedules[i].Offset;
if (Schedule->Schedules[i].Type != SCHEDULE_INTERVAL) {
continue;
}
PrintScheduleGrid(ScheduleData, Mask);
}
}
}
DWORD
DumpSubscribers(
PWCHAR ComputerDn,
PWCHAR MemberDn
)
/*++
Routine Description:
Dump the frs member object.
Arguments:
Return Value:
--*/
{
DWORD LStatus;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR Attrs[5];
PLDAPMessage LdapEntry = NULL;
PWCHAR Val = NULL;
PWCHAR SearchFilter = NULL;
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
DWORD NoOfSubscribers;
Attrs[0] = ATTR_DN;
Attrs[1] = ATTR_MEMBER_REF;
Attrs[2] = ATTR_REPLICA_ROOT;
Attrs[3] = ATTR_REPLICA_STAGE;
Attrs[4] = NULL;
SearchFilter = (PWCHAR) malloc(
(((MemberDn != NULL)?wcslen(MemberDn):0)
+ MAX_PATH)
* sizeof(WCHAR));
if (MemberDn != NULL) {
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_MEMBER_REF);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, MemberDn);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_SUBSCRIBER);
wcscat(SearchFilter, L")");
} else {
wcscpy(SearchFilter, CLASS_SUBSCRIBER);
}
if (!LdapSearchInit(pLdap,
ComputerDn,
LDAP_SCOPE_SUBTREE,
SearchFilter,
Attrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SUBSCRIBER_DUMP_FAILED;
goto CLEANUP;
}
NoOfSubscribers = FrsSearchContext.EntriesInPage;
if (NoOfSubscribers == 0) {
LdapSearchClose(&FrsSearchContext);
if (MemberDn != NULL) {
//
// This error return only makes sense when we were asked to dump
// a specific subscriber.
//
DPRINT0("Error dumping; subscriber not found.\n");
Status = MKDSOE_SUBSCRIBER_NOT_FOUND_DUMP;
}
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
// ATTR_DN
Val = FindValue(LdapEntry, ATTR_DN);
printf("\n SubscriberDn:%ws\n", Val);
FREE(Val);
//
// ATTR_CLASS
// We know the class
printf(" ObjectClass:nTFRSSubscriber\n");
// ATTR_MEMBER_REF
Val = FindValue(LdapEntry, ATTR_MEMBER_REF);
printf(" FrsMemberReference:%ws\n", Val);
FREE(Val);
// ATTR_REPLICA_ROOT
Val = FindValue(LdapEntry, ATTR_REPLICA_ROOT);
printf(" FrsRootPath:%ws\n", Val);
FREE(Val);
// ATTR_REPLICA_STAGE
Val = FindValue(LdapEntry, ATTR_REPLICA_STAGE);
printf(" FrsStagingPath:%ws\n", Val);
FREE(Val);
}
LdapSearchClose(&FrsSearchContext);
CLEANUP:
FREE(SearchFilter);
return Status;
}
DWORD
DumpReplicaMembers(
PWCHAR NTFRSReplicaSetDn,
PWCHAR MemberName
)
/*++
Routine Description:
Dump the frs member object.
Arguments:
Return Value:
--*/
{
DWORD LStatus;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR Attrs[4];
PLDAPMessage LdapEntry = NULL;
PWCHAR Val = NULL;
PWCHAR ComputerRef = NULL;
PWCHAR MemberDn = NULL;
WCHAR SearchFilter[MAX_PATH];
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
DWORD NoOfMembers;
Attrs[0] = ATTR_DN;
Attrs[1] = ATTR_COMPUTER_REF;
Attrs[2] = ATTR_SERVER_REF;
Attrs[3] = NULL;
if (MemberName != NULL) {
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_CN);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, MemberName);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_MEMBER);
wcscat(SearchFilter, L")");
} else {
wcscpy(SearchFilter, CLASS_MEMBER);
}
if (!LdapSearchInit(pLdap,
NTFRSReplicaSetDn,
LDAP_SCOPE_ONELEVEL,
SearchFilter,
Attrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_MEMBER_DUMP_FAILED;
goto CLEANUP;
}
NoOfMembers = FrsSearchContext.EntriesInPage;
if (NoOfMembers == 0) {
LdapSearchClose(&FrsSearchContext);
if (MemberName != NULL) {
//
// This error return only makes sense when we were asked to dump
// a specific member object.
//
DPRINT0("Error dumping; member not found.\n");
Status = MKDSOE_MEMBER_NOT_FOUND_DUMP;
}
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
// ATTR_DN
MemberDn = FindValue(LdapEntry, ATTR_DN);
printf("\n MemberDn:%ws\n", MemberDn);
//
// ATTR_CLASS
// We know the class
printf(" ObjectClass:nTFRSMember\n");
// ATTR_COMPUTER_REF
ComputerRef = FindValue(LdapEntry, ATTR_COMPUTER_REF);
printf(" FrsComputerReference:%ws\n", ComputerRef);
// ATTR_SERVER_REF
Val = FindValue(LdapEntry, ATTR_SERVER_REF);
printf(" ServerReference:%ws\n", Val);
FREE(Val);
if (bAffectAll && ComputerRef != NULL) {
DumpSubscribers(ComputerRef, MemberDn);
}
FREE(ComputerRef);
FREE(MemberDn);
}
LdapSearchClose(&FrsSearchContext);
CLEANUP:
return Status;
}
DWORD
DumpReplicaSet(
PWCHAR NTFRSSettingsDn,
PWCHAR ReplicaSetName
)
/*++
Routine Description:
Dump the replica set object.
Arguments:
Return Value:
--*/
{
DWORD LStatus;
DWORD Status = MKDSOE_SUCCESS;
PWCHAR Attrs[6];
PLDAPMessage LdapEntry = NULL;
PWCHAR Val = NULL;
PWCHAR ReplicaSetDn = NULL;
WCHAR SearchFilter[MAX_PATH];
FRS_LDAP_SEARCH_CONTEXT FrsSearchContext;
DWORD ReplicaSetType;
DWORD NoOfSets;
DWORD ScheduleLen;
PSCHEDULE Schedule = NULL;
BOOL SaveVerbose;
Attrs[0] = ATTR_DN;
Attrs[1] = ATTR_SET_TYPE;
Attrs[2] = ATTR_FILE_FILTER;
Attrs[3] = ATTR_DIRECTORY_FILTER;
Attrs[4] = ATTR_SCHEDULE;
Attrs[5] = NULL;
if (ReplicaSetName != NULL) {
wcscpy(SearchFilter, L"(&(");
wcscat(SearchFilter, ATTR_CN);
wcscat(SearchFilter, L"=");
wcscat(SearchFilter, ReplicaSetName);
wcscat(SearchFilter, L")");
wcscat(SearchFilter, CLASS_NTFRS_REPLICA_SET);
wcscat(SearchFilter, L")");
} else {
wcscpy(SearchFilter, CLASS_NTFRS_REPLICA_SET);
}
if (!LdapSearchInit(pLdap,
NTFRSSettingsDn,
LDAP_SCOPE_SUBTREE,
SearchFilter,
Attrs,
0,
&FrsSearchContext,
FALSE)) {
Status = MKDSOE_SET_DUMP_FAILED;
goto CLEANUP;
}
NoOfSets = FrsSearchContext.EntriesInPage;
if (NoOfSets == 0) {
DPRINT0("Error dumping; replica set not found.\n");
LdapSearchClose(&FrsSearchContext);
Status = MKDSOE_SET_NOT_FOUND_DUMP;
goto CLEANUP;
}
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext);
LdapEntry != NULL;
LdapEntry = LdapSearchNext(pLdap, &FrsSearchContext)) {
// ATTR_DN
ReplicaSetDn = FindValue(LdapEntry, ATTR_DN);
printf("\nReplicaSetDn:%ws\n", ReplicaSetDn);
//
// ATTR_CLASS
// We know the class
printf(" ObjectClass:nTFRSReplicaSet\n");
// ATTR_SET_TYPE
Val = FindValue(LdapEntry, ATTR_SET_TYPE);
ReplicaSetType = _wtoi(Val);
printf(" FrsReplicaSetType:%ws ", Val);
if (ReplicaSetType > MKDSOE_RSTYPE_MAX) {
printf("[ Invalid Type ");
} else {
printf("[ %ws ", ReplicaSetTypeStr[ReplicaSetType]);
}
printf("]\n");
FREE(Val);
// ATTR_FILE_FILTER
Val = FindValue(LdapEntry, ATTR_FILE_FILTER);
printf(" FrsFileFilter:%ws\n", Val);
FREE(Val);
// ATTR_DIRECTORY_FILTER
Val = FindValue(LdapEntry, ATTR_DIRECTORY_FILTER);
printf(" FrsDirectoryFilter:%ws\n", Val);
FREE(Val);
// ATTR_SCHEDULE
FindBerValue(LdapEntry, ATTR_SCHEDULE, &ScheduleLen, (VOID **)&Schedule);
if (Schedule) {
SaveVerbose = bVerboseMode;
bVerboseMode = TRUE;
PrintSchedule(Schedule, 0x0F);
bVerboseMode = SaveVerbose;
delete(Schedule);
}
//
// Dump the members if asked.
//
if (bAffectAll) {
DumpReplicaMembers(ReplicaSetDn, NULL);
}
FREE(ReplicaSetDn);
}
LdapSearchClose(&FrsSearchContext);
CLEANUP:
return Status;
}
PWCHAR *
ConvertArgv(
DWORD argc,
PCHAR *argv
)
/*++
Routine Description:
Convert short char argv into wide char argv
Arguments:
argc - From main
argv - From main
Return Value:
Address of the new argv
--*/
{
PWCHAR *wideargv;
wideargv = new PWCHAR[argc + 1];
wideargv[argc] = NULL;
while (argc-- >= 1) {
wideargv[argc] = new WCHAR[strlen(argv[argc]) + 1];
wsprintf(wideargv[argc], L"%hs", argv[argc]);
}
return wideargv;
}
VOID
FreeArgv(
DWORD Argc,
PWCHAR *Argv
)
/*++
Routine Description:
Free the converted arguments.
Arguments:
Argc - No of arguments.
Argv - Converted arguments returned from ConvertArgv.
Return Value:
None.
--*/
{
while (Argc-- >= 1) {
FREE(Argv[Argc]);
}
FREE(Argv);
}
VOID
Usage(
PWCHAR *Argv
)
/*++
Routine Description:
Tell the user how to use the program.
Arguments:
Argv Argument array.
Return Value:
None
--*/
{
printf("%-60s\n", "This tool creates, adds, updates, dumps, and deletes replica set, member, and subscriber objects.\n");
printf("%-60s%ws /?\n", "Help", Argv[0]);
printf("%-60s%ws /v\n", "Verbose mode.", Argv[0]);
printf("%-60s%ws /debug\n", "Debug mode. No Writes to the DC.", Argv[0]);
printf("%-60s%ws /dc\n", "Name of the DC to connect to.", Argv[0]);
printf("%-60s%ws /ntfrssettingsdn\n", "Dn for the FRS settings container.", Argv[0]);
printf("%-60s%ws /setname\n", "Name of the replica set.", Argv[0]);
printf("%-60s%ws /settype\n", "Type of the replica set.", Argv[0]);
printf("%-60s\n", "Sysvol = 2");
printf("%-60s\n", "Dfs = 3");
printf("%-60s\n\n", "Other = 4");
printf("%-60s%ws /filefilter\n", "Filter to use against files.e.g. *.bak,*.tmp", Argv[0]);
printf("%-60s%ws /directoryfilter\n", "Filter to use against directories.", Argv[0]);
printf("%-60s%ws /membername\n", "Name of the member.", Argv[0]);
printf("%-60s%ws /computerdn\n", "Dn for the computer object.", Argv[0]);
printf("%-60s%ws /computername\n", "NT4 style computer name. e.g. NTDEV\\SUDARCTEST$.", Argv[0]);
printf("%-60s%ws /serverref\n", "Dn of NTDSSettings object for DCs.", Argv[0]);
printf("%-60s%ws /rootpath\n", "Replica root path. Has to be absolute.", Argv[0]);
printf("%-60s%ws /stagepath\n", "Replica staging path. Has to be absolute.", Argv[0]);
printf("%-60s%ws /refdcname <dnsname>\n", "Reference DC to use while creating subscriber.", Argv[0]);
printf("%-60s%ws /[create<object> update<object> del<object> dump]\n", "Operation to be performed.", Argv[0]);
printf("%-60s%ws \n\n", "<object> can be one of [set member subscriber].", Argv[0]);
printf("%-60s%ws /all\n", "Perform the operation on all the objects.", Argv[0]);
printf("%-60s%ws \n\n", "/all only works with /dump and /del.", Argv[0]);
printf("%-60s%ws /schedule <Interval> <Stagger> <Offset>\n", "Schedule to create for the replica set.", Argv[0]);
printf("%-60s%ws <Interval>\n", "The desired interval between each sync with one source.", Argv[0]);
printf("%-60s%ws <Stagger>\n", "Typically number of source DCs.", Argv[0]);
printf("%-60s%ws <Offset>\n\n", "Typically the number of the source DC.", Argv[0]);
printf("%-60s%ws /schedoverride\n", "File with 7x24 vector of schedule override data.", Argv[0]);
printf("%-60s%ws /schedmask\n", "File with 7x24 vector of schedule mask off data.", Argv[0]);
printf("%-60s\n", "SchedOverride and SchedMask data are formatted");
printf("%-60s\n\n", "as 2 ascii hex digits for each schedule byte.");
DPRINT0("\n");
DPRINT0("mkdsx.exe error return codes\n");
DPRINT0("100 = Success\n");
DPRINT0("101 = Invalid Arguments\n");
DPRINT0("102 = Could not bind to the DC\n");
DPRINT0("103 = Could not find 'NTFRS Settings' object. Check the /settingsdn parameter\n");
DPRINT0("104 = Error creating replica set\n");
DPRINT0("105 = Error updating replica set\n");
DPRINT0("106 = Error updating replica set; set not found\n");
DPRINT0("107 = Error updating replica set; duplicate sets found\n");
DPRINT0("108 = Error deleting replica set; duplicate sets found.\n");
DPRINT0("109 = Error deleting replica set\n");
DPRINT0("110 = Error deleting replica set; set not found\n");
DPRINT0("111 = Deleting multiple sets\n");
DPRINT0("112 = Error dumping replica set\n");
DPRINT0("113 = Error dumping replica set; set not found\n");
DPRINT0("114 = Dumping duplicate sets\n");
DPRINT0("115 = Error creating replica member\n");
DPRINT0("116 = Error updating replica member\n");
DPRINT0("117 = Error updating replica member; member not found\n");
DPRINT0("118 = Error updating replica member; duplicate members found\n");
DPRINT0("119 = Error deleting member; duplicate subscribers found.\n");
DPRINT0("120 = Error deleting replica member\n");
DPRINT0("121 = Error deleting replica member; member not found\n");
DPRINT0("122 = Deleting multiple members\n");
DPRINT0("123 = Error dumping replica member\n");
DPRINT0("124 = Error dumping replica member; member not found\n");
DPRINT0("125 = Dumping duplicate members\n");
DPRINT0("126 = Error creating subscriber\n");
DPRINT0("127 = Error updating subscriber\n");
DPRINT0("128 = Error updating subscriber; subscriber not found\n");
DPRINT0("129 = Error updating subscriber; duplicate subscribers found\n");
DPRINT0("130 = Error deleting subscriber\n");
DPRINT0("131 = Error deleting subscriber; subscriber not found\n");
DPRINT0("132 = Deleting multiple subscribers\n");
DPRINT0("133 = Error deleting subscriber; duplicate subscribers found.\n");
DPRINT0("134 = Error dumping subscriber\n");
DPRINT0("135 = Error dumping subscriber; subscriber not found\n");
DPRINT0("136 = Dumping duplicate subscribers\n");
DPRINT0("\n");
fflush(stdout);
}
DWORD __cdecl
main(
DWORD argc,
PCHAR *argv
)
/*++
Routine Description:
Arguments:
None.
Return Value:
Exits with 0 if everything went okay. Otherwise returns a error code.
MKDSOE_SUCCESS "Success."
MKDSOE_BAD_ARG "Invalid Arguments."
MKDSOE_CANT_BIND "Could not bind to the DC."
MKDSOE_NO_NTFRS_SETTINGS "Could not find 'NTFRS Settings' object. Check the /settingsdn parameter."
MKDSOE_SET_OBJ_CRE_FAILED "Error creating replica set."
MKDSOE_SET_OBJ_UPDATE_FAILED "Error updating replica set."
MKDSOE_SET_NOT_FOUND_UPDATE "Error updating replica set; set not found."
MKDSOE_SET_DUPS_FOUND_UPDATE "Error updating replica set; duplicate sets found."
MKDSOE_SET_DUPS_FOUND_DELETE "Error deleting replica set; duplicate sets found."
MKDSOE_SET_DELETE_FAILED "Error deleting replica set."
MKDSOE_SET_NOT_FOUND_DELETE "Error deleting replica set; set not found."
MKDSOE_MULTIPLE_SETS_DELETED "Deleting multiple sets."
MKDSOE_SET_DUMP_FAILED "Error dumping replica set."
MKDSOE_SET_NOT_FOUND_DUMP "Error dumping replica set; set not found."
MKDSOE_MULTIPLE_SETS_DUMPED "Dumping duplicate sets."
MKDSOE_MEMBER_OBJ_CRE_FAILED "Error creating replica member."
MKDSOE_MEMBER_OBJ_UPDATE_FAILED "Error updating replica member."
MKDSOE_MEMBER_NOT_FOUND_UPDATE "Error updating replica member; member not found."
MKDSOE_MEMBER_DUPS_FOUND_UPDATE "Error updating replica member; duplicate members found."
MKDSOE_MEMBER_DUPS_FOUND_DELETE "Error deleting member; duplicate subscribers found."
MKDSOE_MEMBER_DELETE_FAILED "Error deleting replica member."
MKDSOE_MEMBER_NOT_FOUND_DELETE "Error deleting replica member; member not found."
MKDSOE_MULTIPLE_MEMBERS_DELETED "Deleting multiple members."
MKDSOE_MEMBER_DUMP_FAILED "Error dumping replica member."
MKDSOE_MEMBER_NOT_FOUND_DUMP "Error dumping replica member; member not found."
MKDSOE_MULTIPLE_MEMBERS_DUMPED "Dumping duplicate members."
MKDSOE_SUBSCRIBER_OBJ_CRE_FAILED "Error creating subscriber."
MKDSOE_SUBSCRIBER_OBJ_UPDATE_FAILED "Error updating subscriber."
MKDSOE_SUBSCRIBER_NOT_FOUND_UPDATE "Error updating subscriber; subscriber not found."
MKDSOE_SUBSCRIBER_DUPS_FOUND_UPDATE "Error updating subscriber; duplicate subscribers found."
MKDSOE_SUBSCRIBER_DELETE_FAILED "Error deleting subscriber."
MKDSOE_SUBSCRIBER_NOT_FOUND_DELETE "Error deleting subscriber; subscriber not found."
MKDSOE_MULTIPLE_SUBSCRIBERS_DELETED "Deleting multiple subscribers."
MKDSOE_SUBSCRIBER_DUPS_FOUND_DELETE "Error deleting subscriber; duplicate subscribers found."
MKDSOE_SUBSCRIBER_DUMP_FAILED "Error dumping subscriber."
MKDSOE_SUBSCRIBER_NOT_FOUND_DUMP "Error dumping subscriber; subscriber not found."
MKDSOE_MULTIPLE_SUBSCRIBERS_DUMPED "Dumping duplicate subscribers."
--*/
{
PWCHAR *Argv;
ULONG i, j;
ULONG OptLen;
DWORD Status = MKDSOE_SUCCESS;
DWORD WStatus = ERROR_SUCCESS;
PWCHAR NTFRSSettingsDn = NULL;
PWCHAR ReplicaSetName = NULL;
PWCHAR ReplicaSetType = NULL;
PWCHAR FileFilter = NULL;
PWCHAR DirectoryFilter = NULL;
PBYTE pSchedule = NULL;
DWORD Interval = 1;
DWORD Stagger = 1;
DWORD Offset = 0;
PWCHAR NT4ComputerName = NULL;
PWCHAR ComputerDn = NULL;
PWCHAR MemberName = NULL;
PWCHAR ServerRef = NULL;
PWCHAR RootPath = NULL;
PWCHAR StagePath = NULL;
PWCHAR RefDCName = NULL;
PWCHAR *Values = NULL;
BOOL ClassFound = FALSE;
DWORD Commands = 0;
DS_NAME_RESULT *Cracked = NULL;
HANDLE hDs = INVALID_HANDLE_VALUE;
Argv = ConvertArgv(argc, argv);
if (argc <= 1) {
Usage(Argv);
Status = MKDSOE_SUCCESS;
goto ARG_CLEANUP;
}
for (i = 1; i < argc; ++i) {
OptLen = wcslen(Argv[i]);
if (OptLen == 2 &&
((wcsstr(Argv[i], L"/v") == Argv[i]) ||
(wcsstr(Argv[i], L"-v") == Argv[i]))) {
bVerboseMode=TRUE;
} else if (OptLen == 2 &&
((wcsstr(Argv[i], L"/?") == Argv[i]) ||
(wcsstr(Argv[i], L"-?") == Argv[i]))) {
Usage(Argv);
Status = MKDSOE_SUCCESS;
goto ARG_CLEANUP;
} else if (OptLen == 6 &&
((wcsstr(Argv[i], L"/debug") == Argv[i]) ||
(wcsstr(Argv[i], L"-debug") == Argv[i]))) {
bDebugMode = TRUE;
bVerboseMode=TRUE;
} else if (OptLen == 3 && (i+1 < argc) &&
((wcsstr(Argv[i], L"/dc") == Argv[i]) ||
(wcsstr(Argv[i], L"-dc") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
DcName = new WCHAR[wcslen(Argv[i])+1];
wcscpy(DcName, Argv[i]);
} else if (OptLen == 16 &&
((wcsstr(Argv[i], L"/ntfrssettingsdn") == Argv[i]) ||
(wcsstr(Argv[i], L"-ntfrssettingsdn") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
NTFRSSettingsDn = new WCHAR[wcslen(Argv[i])+1];
wcscpy(NTFRSSettingsDn, Argv[i]);
} else if (OptLen == 8 &&
((wcsstr(Argv[i], L"/setname") == Argv[i]) ||
(wcsstr(Argv[i], L"-setname") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
ReplicaSetName = new WCHAR[wcslen(Argv[i])+1];
wcscpy(ReplicaSetName, Argv[i]);
} else if (OptLen == 11 &&
((wcsstr(Argv[i], L"/computerdn") == Argv[i]) ||
(wcsstr(Argv[i], L"-computerdn") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
ComputerDn = new WCHAR[wcslen(Argv[i])+1];
wcscpy(ComputerDn, Argv[i]);
} else if (OptLen == 13 &&
((wcsstr(Argv[i], L"/computername") == Argv[i]) ||
(wcsstr(Argv[i], L"-computername") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
NT4ComputerName = new WCHAR[wcslen(Argv[i])+1];
wcscpy(NT4ComputerName, Argv[i]);
} else if (OptLen == 11 &&
((wcsstr(Argv[i], L"/membername") == Argv[i]) ||
(wcsstr(Argv[i], L"-membername") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
MemberName = new WCHAR[wcslen(Argv[i])+1];
wcscpy(MemberName, Argv[i]);
} else if (OptLen == 10 &&
((wcsstr(Argv[i], L"/serverref") == Argv[i]) ||
(wcsstr(Argv[i], L"-serverref") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
ServerRef = new WCHAR[wcslen(Argv[i])+1];
wcscpy(ServerRef, Argv[i]);
} else if (OptLen == 9 &&
((wcsstr(Argv[i], L"/rootpath") == Argv[i]) ||
(wcsstr(Argv[i], L"-rootpath") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
RootPath = new WCHAR[wcslen(Argv[i])+1];
wcscpy(RootPath, Argv[i]);
} else if (OptLen == 10 &&
((wcsstr(Argv[i], L"/stagepath") == Argv[i]) ||
(wcsstr(Argv[i], L"-stagepath") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
StagePath = new WCHAR[wcslen(Argv[i])+1];
wcscpy(StagePath, Argv[i]);
} else if (OptLen == 10 &&
((wcsstr(Argv[i], L"/refdcname") == Argv[i]) ||
(wcsstr(Argv[i], L"-refdcname") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
RefDCName = new WCHAR[wcslen(Argv[i])+1];
wcscpy(RefDCName, Argv[i]);
} else if (OptLen == 10 &&
((wcsstr(Argv[i], L"/createset") == Argv[i]) ||
(wcsstr(Argv[i], L"-createset") == Argv[i]))) {
bCreateSet = TRUE;
++Commands;
} else if (OptLen == 10 &&
((wcsstr(Argv[i], L"/updateset") == Argv[i]) ||
(wcsstr(Argv[i], L"-updateset") == Argv[i]))) {
bUpdateSet = TRUE;
++Commands;
} else if (OptLen == 7 &&
((wcsstr(Argv[i], L"/delset") == Argv[i]) ||
(wcsstr(Argv[i], L"-delset") == Argv[i]))) {
bDelSet = TRUE;
++Commands;
} else if (OptLen == 13 &&
((wcsstr(Argv[i], L"/createmember") == Argv[i]) ||
(wcsstr(Argv[i], L"-createmember") == Argv[i]))) {
bCreateMember = TRUE;
++Commands;
} else if (OptLen == 13 &&
((wcsstr(Argv[i], L"/updatemember") == Argv[i]) ||
(wcsstr(Argv[i], L"-updatemember") == Argv[i]))) {
bUpdateMember = TRUE;
++Commands;
} else if (OptLen == 10 &&
((wcsstr(Argv[i], L"/delmember") == Argv[i]) ||
(wcsstr(Argv[i], L"-delmember") == Argv[i]))) {
bDelMember = TRUE;
++Commands;
} else if (OptLen == 17 &&
((wcsstr(Argv[i], L"/createsubscriber") == Argv[i]) ||
(wcsstr(Argv[i], L"-createsubscriber") == Argv[i]))) {
bCreateSubscriber = TRUE;
++Commands;
} else if (OptLen == 17 &&
((wcsstr(Argv[i], L"/updatesubscriber") == Argv[i]) ||
(wcsstr(Argv[i], L"-updatesubscriber") == Argv[i]))) {
bUpdateSubscriber = TRUE;
++Commands;
} else if (OptLen == 14 &&
((wcsstr(Argv[i], L"/delsubscriber") == Argv[i]) ||
(wcsstr(Argv[i], L"-delsubscriber") == Argv[i]))) {
bDelSubscriber = TRUE;
++Commands;
} else if (OptLen == 5 &&
((wcsstr(Argv[i], L"/dump") == Argv[i]) ||
(wcsstr(Argv[i], L"-dump") == Argv[i]))) {
bDump = TRUE;
++Commands;
} else if (OptLen == 4 &&
((wcsstr(Argv[i], L"/all") == Argv[i]) ||
(wcsstr(Argv[i], L"-all") == Argv[i]))) {
bAffectAll = TRUE;
} else if (OptLen == 8 &&
((wcsstr(Argv[i], L"/settype") == Argv[i]) ||
(wcsstr(Argv[i], L"-settype") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
ReplicaSetType = new WCHAR[wcslen(Argv[i])+1];
wcscpy(ReplicaSetType, Argv[i]);
} else if (OptLen == 11 &&
((wcsstr(Argv[i], L"/filefilter") == Argv[i]) ||
(wcsstr(Argv[i], L"-filefilter") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
FileFilter = new WCHAR[wcslen(Argv[i])+1];
wcscpy(FileFilter, Argv[i]);
} else if (OptLen == 16 &&
((wcsstr(Argv[i], L"/directoryfilter") == Argv[i]) ||
(wcsstr(Argv[i], L"-directoryfilter") == Argv[i]))) {
if( ++i >= argc ){
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
DirectoryFilter = new WCHAR[wcslen(Argv[i])+1];
wcscpy(DirectoryFilter, Argv[i]);
} else if (OptLen == 9 && (i+3 < argc) &&
((wcsstr(Argv[i], L"/schedule") == Argv[i]) ||
(wcsstr(Argv[i], L"-schedule") == Argv[i]))) {
bSchedule = TRUE;
Interval = _wtoi(Argv[i+1]);
Stagger = _wtoi(Argv[i+2]);
Offset = _wtoi(Argv[i+3]);
i+=3;
} else if ((OptLen == 10) && (i+1 < argc) &&
((wcsstr(Argv[i], L"/schedmask") == Argv[i]) ||
(wcsstr(Argv[i], L"-schedmask") == Argv[i]))) {
SchedMask = ReadScheduleFile(Argv[i+1]);
if (SchedMask == NULL) {
FreeArgv(argc,Argv);
return MKDSOE_BAD_ARG;
} else {
if (bVerboseMode) {
printf(" schedmask:\n");
PrintScheduleGrid(SchedMask, 0x0F);
}
}
i+=1;
} else if ((OptLen == 14) && (i+1 < argc) &&
((wcsstr(Argv[i], L"/schedoverride") == Argv[i]) ||
(wcsstr(Argv[i], L"-schedoverride") == Argv[i]))) {
SchedOverride = ReadScheduleFile(Argv[i+1]);
if (SchedOverride == NULL) {
FreeArgv(argc,Argv);
return MKDSOE_BAD_ARG;
} else {
if (bVerboseMode) {
printf(" schedoverride:\n");
PrintScheduleGrid(SchedOverride, 0x0F);
}
}
i+=1;
} else {
Usage(Argv);
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
}
//
// Begin of verify command line parameters.
//
if (Commands != 1) {
if ((Commands == 2) && bDelSubscriber &&bDelMember) {
//
// The only time two commands are allowed is when /delsubscriber
// is used with /delmember
//
} else {
DPRINT0("INVALID ARG: Specify one and only one command except /delmember /delsubscriber.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
}
if (NTFRSSettingsDn == NULL) {
DPRINT0("INVALID ARG: Missing parameter /ntfrssettingsdn.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
if ((ReplicaSetName == NULL) && !(bDump && bAffectAll)) {
DPRINT0("INVALID ARG: Missing parameter /setname.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
if (bCreateSet && ReplicaSetType == NULL) {
DPRINT0("INVALID ARG: Missing parameter /settype.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
if (bCreateMember) {
if (MemberName == NULL) {
DPRINT0("INVALID ARG: Missing parameter /membername.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
}
if (bUpdateMember) {
if ((MemberName == NULL) &&
(ComputerDn == NULL) &&
(NT4ComputerName == NULL)) {
DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
}
if (bCreateSubscriber) {
if ((MemberName == NULL) &&
(ComputerDn == NULL) &&
(NT4ComputerName == NULL)) {
DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
if (RootPath == NULL) {
DPRINT0("INVALID ARG: Missing parameter /rootpath.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
if (StagePath == NULL) {
DPRINT0("INVALID ARG: Missing parameter /stagepath.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
}
if (bUpdateSubscriber) {
if ((MemberName == NULL) &&
(ComputerDn == NULL) &&
(NT4ComputerName == NULL)) {
DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
}
if (bDelMember) {
if (!bAffectAll &&
(MemberName == NULL) &&
(ComputerDn == NULL) &&
(NT4ComputerName == NULL)) {
DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername or /all.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
}
if (bDelSubscriber) {
if (!bDelMember &&
(MemberName == NULL) &&
(ComputerDn == NULL) &&
(NT4ComputerName == NULL)) {
DPRINT0("INVALID ARG: Missing parameter /membername or /computerdn or /computername.\n");
Status = MKDSOE_BAD_ARG;
goto ARG_CLEANUP;
}
}
//
// End of verify command line parameters.
//
Status = BindToDC(DcName, &pLdap);
//
// Verify that the ntfrs settings DN exists and is actually a NTFRSSettings object.
//
i=0;
ClassFound = FALSE;
Values = GetValues(pLdap, NTFRSSettingsDn,ATTR_CLASS,TRUE);
while (Values && Values[i]) {
if (_wcsicmp(Values[i],ATTR_NTFRS_SETTINGS) == 0) {
ClassFound = TRUE;
break;
}
++i;
}
ldap_value_free(Values);
if (!ClassFound) {
DPRINT0("INVALID ARG: Check parameter /ntfrssettingsdn.\n");
Status = MKDSOE_BAD_ARG;
goto CLEANUP;
}
//
// Verify that the computer DN exists and is actually a computer object.
//
if (ComputerDn != NULL) {
i=0;
ClassFound = FALSE;
Values = GetValues(pLdap, ComputerDn,ATTR_CLASS,TRUE);
while (Values && Values[i]) {
if ((_wcsicmp(Values[i],ATTR_COMPUTER)== 0) ||
(_wcsicmp(Values[i],ATTR_USER) == 0)) {
ClassFound = TRUE;
break;
}
++i;
}
ldap_value_free(Values);
if (!ClassFound) {
DPRINT0("INVALID ARG: Check parameter /computerdn.\n");
Status = MKDSOE_BAD_ARG;
goto CLEANUP;
}
}
if (bCreateSet) {
if (bSchedule) {
BuildSchedule(&pSchedule, Interval, Stagger, Offset);
Status = CreateNewReplicaSet(NTFRSSettingsDn,ReplicaSetName,
ReplicaSetType, FileFilter,
DirectoryFilter, pSchedule);
} else {
Status = CreateNewReplicaSet(NTFRSSettingsDn,ReplicaSetName,
ReplicaSetType, FileFilter,
DirectoryFilter, NULL);
}
}
if (bUpdateSet) {
if (bSchedule) {
BuildSchedule(&pSchedule, Interval, Stagger, Offset);
Status = UpdateReplicaSet(NTFRSSettingsDn,ReplicaSetName,
ReplicaSetType, FileFilter,
DirectoryFilter, pSchedule);
} else {
Status = UpdateReplicaSet(NTFRSSettingsDn,ReplicaSetName,
ReplicaSetType, FileFilter,
DirectoryFilter, NULL);
}
}
if (bCreateMember || bUpdateMember || bCreateSubscriber || bUpdateSubscriber ||
bDelSubscriber || bDelMember) {
if ((ComputerDn == NULL) && (NT4ComputerName != NULL)) {
WStatus = DsBind(DcName, NULL, &hDs);
if (WStatus == ERROR_SUCCESS) {
WStatus = DsCrackNames(hDs,
DS_NAME_NO_FLAGS,
DS_NT4_ACCOUNT_NAME,
DS_FQDN_1779_NAME,
1,
&NT4ComputerName,
&Cracked);
DsUnBind(&hDs);
}
if ((WStatus == ERROR_SUCCESS) &&
Cracked && Cracked->cItems && Cracked->rItems &&
(Cracked->rItems->status == DS_NAME_NO_ERROR)) {
ComputerDn = FrsWcsDup(Cracked->rItems->pName);
} else {
DPRINT1("ERROR: Can not crack computerDn %d\n", WStatus);
Status = MKDSOE_BAD_ARG;
goto CLEANUP;
}
}
if (bCreateMember) {
Status = CreateNewReplicaMember(NTFRSSettingsDn,ReplicaSetName,
MemberName,ComputerDn,ServerRef,
RefDCName);
}
if (bUpdateMember) {
Status = UpdateReplicaMember(NTFRSSettingsDn,ReplicaSetName,
MemberName,ComputerDn,ServerRef,
RefDCName);
}
if (bDelMember) {
Status = DeleteReplicaMember(NTFRSSettingsDn,ReplicaSetName,
MemberName,ComputerDn);
}
if (bCreateSubscriber || bUpdateSubscriber) {
Status = CreateNewSubscriber(NTFRSSettingsDn,
ReplicaSetName,
MemberName,
ComputerDn,
RootPath,
StagePath,
RefDCName);
}
if (bDelSubscriber && !bDelMember) {
Status = DeleteSubscriber(NTFRSSettingsDn,
ReplicaSetName,
MemberName,
ComputerDn);
}
}
if (bDelSet) {
Status = DeleteReplicaSet(NTFRSSettingsDn, ReplicaSetName);
}
if (bDump ) {
DumpReplicaSet(NTFRSSettingsDn, ReplicaSetName);
}
goto CLEANUP;
CLEANUP:
ldap_unbind(pLdap);
ARG_CLEANUP:
FreeArgv(argc,Argv);
FREE(MemberName);
FREE(ReplicaSetName);
FREE(ComputerDn);
FREE(NT4ComputerName);
return Status;
}