|
|
/*++
Copyright (c) 1997-1999 Microsoft Corporation
Module Name:
info.c
Abstract:
Support the RPC interface that provides internal info to the caller.
Author:
Billy J Fuller 27-Mar-1998
Environment
User mode, winnt32
--*/
#include <ntreppch.h>
#pragma hdrstop
#undef DEBSUB
#define DEBSUB "Info:"
#include <frs.h>
#include <ntdsapi.h>
#include <ntdsapip.h> // ms internal flags for DsCrackNames()
#include <ntfrsapi.h>
#include <info.h>
#include <tablefcn.h>
#include <lmaccess.h>
#include <lmapibuf.h>
#ifdef SECURITY_WIN32
#include <security.h>
#else
#define SECURITY_WIN32
#include <security.h>
#undef SECURITY_WIN32
#endif
extern PCHAR LatestChanges[]; extern PCHAR CoLocationNames[];
//
// Useful macros
//
#define IPRINTGNAME(_I_, _G_, _F_, _GUID_, _P_) \
{ \ if (_G_) { \ GuidToStr(_G_->Guid, _GUID_); \ IPRINT3(_I_, _F_, _P_, _G_->Name, _GUID_); \ } \ }
#define INFO_DN_LEN (80)
extern OSVERSIONINFOEX OsInfo; extern SYSTEM_INFO SystemInfo; extern PCHAR ProcessorArchName[10];
//
// DC name for LDAP binding
//
WCHAR InfoDcName[MAX_PATH + 1];
//
// Member Subscriber Links
//
typedef struct _INFO_DN INFO_DN, *PINFO_DN; struct _INFO_DN { PINFO_DN Next; PWCHAR Dn; PWCHAR SetType; };
VOID DbsDisplayRecordIPrint( IN PTABLE_CTX TableCtx, IN PINFO_TABLE InfoTable, IN BOOL Read, IN PULONG RecordFieldx, IN ULONG FieldCount );
//
// From frs\ds.c
//
PVOID * FrsDsFindValues( IN PLDAP ldap, IN PLDAPMessage Entry, IN PWCHAR DesiredAttr, IN BOOL DoBerVals );
PWCHAR FrsDsExtendDn( IN PWCHAR Dn, IN PWCHAR Cn );
PWCHAR FrsDsExtendDnOu( IN PWCHAR Dn, IN PWCHAR Ou );
PWCHAR FrsDsFindValue( IN PLDAP ldap, IN PLDAPMessage Entry, IN PWCHAR DesiredAttr );
GUID * FrsDsFindGuid( IN PLDAP Ldap, IN PLDAPMessage LdapEntry );
PWCHAR FrsDsMakeRdn( IN PWCHAR DN );
PWCHAR FrsDsConvertToSettingsDn( IN PWCHAR Dn );
PSCHEDULE FrsDsFindSchedule( IN PLDAP Ldap, IN PLDAPMessage LdapEntry, OUT PULONG Len );
VOID FrsPrintRpcStats( IN ULONG Severity, IN PNTFRSAPI_INFO Info, OPTIONAL IN DWORD Tabs );
VOID FrsPrintThreadStats( IN ULONG Severity, IN PNTFRSAPI_INFO Info, OPTIONAL IN DWORD Tabs );
VOID InfoPrint( IN PNTFRSAPI_INFO Info, IN PCHAR Format, IN ... ) /*++
Routine Description: Format and print a line of information output into the info buffer.
Arguments: Info - Info buffer Format - printf format
Return Value: None. --*/ { PCHAR Line; ULONG LineLen; LONG LineSize;
//
// varargs stuff
//
va_list argptr; va_start(argptr, Format);
//
// Print the line into the info buffer
//
try { if (!FlagOn(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) { Line = ((PCHAR)Info) + Info->OffsetToFree; LineSize = (Info->SizeInChars - (ULONG)(Line - (PCHAR)Info)) - 1; if (LineSize <= 0 || _vsnprintf(Line, LineSize, Format, argptr) < 0) { SetFlag(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL); } else { LineLen = strlen(Line) + 1; if (Info->CharsToSkip) { if (LineLen > Info->CharsToSkip) { Info->CharsToSkip = 0; } else { Info->CharsToSkip -= LineLen; } } else { Info->OffsetToFree += LineLen; Info->TotalChars += LineLen; } } } } except(EXCEPTION_EXECUTE_HANDLER) { } va_end(argptr); }
#define Tab L" "
VOID InfoTabs( IN DWORD Tabs, IN PWCHAR TabW ) /*++
Routine Description: Create a string of tabs for prettyprint
Arguments: Tabs - number of tabs TabW - preallocated string to receive tabs
Return Value: Win32 Status --*/ { DWORD i;
//
// Adjust indentation
//
Tabs = (Tabs >= MAX_TABS) ? MAX_TABS : Tabs; for (TabW[0] = L'\0', i = 0; i < Tabs; ++i) { wcscat(TabW, Tab); } }
PWCHAR InfoDup( IN PWCHAR StrW, IN DWORD DesiredLen ) /*++
Routine Description: Duplicate up to DesiredLen chars of StrW. DesiredLen includes the terminating \0.
Arguments: StrW - original string (untouched) DesiredLen - Maximum length to duplicate (including terminating \0)
Return Value: Win32 Status --*/ { DWORD Len; PWCHAR NewStrW;
if (!StrW) { return NULL; }
Len = wcslen(StrW) + 1; if (Len <= DesiredLen) { return FrsWcsDup(StrW); } NewStrW = FrsAlloc(DesiredLen * sizeof(WCHAR)); wcsncpy(NewStrW, StrW, DesiredLen); NewStrW[DesiredLen - 1] = L'\0'; if (DesiredLen > 4) { NewStrW[DesiredLen - 2] = L'.'; NewStrW[DesiredLen - 3] = L'.'; NewStrW[DesiredLen - 4] = L'.'; } return NewStrW; }
DWORD InfoPrintDbSets( IN PNTFRSAPI_INFO Info, IN DWORD Tabs ) /*++
Routine Description: Return internal info on replica sets (see private\net\inc\ntfrsapi.h).
Arguments: Info - RPC output buffer Tabs
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintDbSets:"
PVOID Key; PREPLICA Replica; CHAR Guid[GUID_CHAR_LEN + 1]; WCHAR TabW[MAX_TAB_WCHARS + 1]; extern PGEN_TABLE ReplicasByGuid; extern PGEN_TABLE DeletedReplicas;
InfoTabs(Tabs, TabW); IPRINT1(Info, "%wsACTIVE REPLICA SETS\n", TabW); Key = NULL; while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) { if (REPLICA_IS_ACTIVE(Replica)) { FrsPrintTypeReplica(0, Info, Tabs, Replica, NULL, 0); } else { //
// If the replica set is not active, one or more of the GNames
// could have freed guid pointers (feeefeee, bug 319600) so
// don't print the replica set in this case, just the name and state.
//
if (Replica->SetName) { IPRINT3(Info, "%ws %ws in state %s\n", TabW, Replica->SetName->Name, RSS_NAME(Replica->ServiceState)); } } }
IPRINT0(Info, "\nDELETED REPLICA SETS\n"); Key = NULL; if (DeletedReplicas) { while (Replica = GTabNextDatum(DeletedReplicas, &Key)) { if (Replica->SetName) { IPRINT2(Info, "%ws %ws\n", TabW, Replica->SetName->Name); } } }
return ERROR_SUCCESS; }
BOOL InfoSearch( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN PWCHAR Base, IN ULONG Scope, IN PWCHAR Filter, IN PWCHAR Attrs[], IN ULONG AttrsOnly, IN LDAPMessage **Res ) /*++
Routine Description: Perform ldap_search_s
Arguments: Info - RPC output buffer Tabs - number of tabs Ldap - bound ldap handle . . .
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoSearch:"
DWORD LStatus; PWCHAR ShortName; WCHAR TabW[MAX_TAB_WCHARS + 1];
InfoTabs(Tabs, TabW); LStatus = ldap_search_s(Ldap, Base, Scope, Filter, Attrs, AttrsOnly, Res);
if (LStatus != LDAP_SUCCESS) { ShortName = InfoDup(Base, 20); IPRINT5(Info, "%wsWARN - ldap_search_s(%ws, %d, %ws); %ws\n", TabW, Base, Scope, ComputerName, ldap_err2string(LStatus)); return FALSE; } return TRUE; }
PCONFIG_NODE InfoAllocBasicNode( IN PNTFRSAPI_INFO Info, IN PWCHAR TabW, IN PWCHAR NodeType, IN PWCHAR ParentDn, IN PWCHAR Filter, IN BOOL *FirstError, IN PLDAP Ldap, IN PLDAPMessage LdapEntry ) /*++
Routine Description: Allocate a node and fill in the basic info (dn and name)
Arguments: Info - text buffer TabW - Prettyprint NodeType - Prettyprint Ldap - openned, bound ldap LdapEntry - returned from ldap_first/next_entry()
Return Value: NULL if basic info is not available. --*/ { #undef DEBSUB
#define DEBSUB "InfoAllocBasicNode:"
PCONFIG_NODE Node = NULL; PWCHAR ShortName = NULL; CHAR Guid[GUID_CHAR_LEN + 1];
//
// Fetch values from the DS
//
Node = FrsAllocType(CONFIG_NODE_TYPE); Node->Dn = FrsDsFindValue(Ldap, LdapEntry, ATTR_DN); FRS_WCSLWR(Node->Dn);
//
// Name
//
Node->Name = FrsBuildGName(FrsDsFindGuid(Ldap, LdapEntry), FrsDsMakeRdn(Node->Dn)); if (!Node->Dn || !Node->Name->Name || !Node->Name->Guid) { IPRINT5(Info, "\n%ws%ws: ERROR - The object returned by the DS" " lacks a dn (%08x), Rdn (%08x), or Guid(%08x)\n", TabW, NodeType, Node->Dn, Node->Name->Name, Node->Name->Guid); if (*FirstError) { *FirstError = FALSE; IPRINT5(Info, "%ws%ws: ERROR - Using ldp, bind to %ws and search the " "container %ws using the filter " "%ws for more information.\n", TabW, NodeType, &InfoDcName[2], ParentDn, Filter); } return FrsFreeType(Node); } IPRINT3(Info, "\n%ws%ws: %ws\n", TabW, NodeType, Node->Name->Name);
ShortName = InfoDup(Node->Dn, INFO_DN_LEN); IPRINT2(Info, "%ws DN : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); GuidToStr(Node->Name->Guid, Guid); IPRINT2(Info, "%ws Guid : %s\n", TabW, Guid);
return Node; }
VOID InfoPrintDsCxtions( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN PWCHAR Base, IN BOOL IsSysVol ) /*++
Routine Description: Print the cxtions from the DS.
Arguments: ldap - opened and bound ldap connection Base - Name of object or container in DS
Return Value: None. --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintDsCxtions:"
PWCHAR Attrs[7]; PLDAPMessage LdapEntry; PLDAPMessage LdapMsg = NULL; PCONFIG_NODE Node = NULL; PWCHAR ShortName = NULL; BOOL FirstError = TRUE; WCHAR TabW[MAX_TAB_WCHARS + 1]; PWCHAR CxtionOptionsWStr = NULL;
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Search the DS for cxtions
//
Attrs[0] = ATTR_DN; Attrs[1] = ATTR_SCHEDULE; Attrs[2] = ATTR_FROM_SERVER; Attrs[3] = ATTR_OBJECT_GUID; Attrs[4] = ATTR_USN_CHANGED; Attrs[5] = ATTR_ENABLED_CXTION; Attrs[6] = ATTR_OPTIONS; Attrs[7] = NULL; if (!InfoSearch(Info, Tabs, Ldap, Base, LDAP_SCOPE_ONELEVEL, CATEGORY_CXTION, Attrs, 0, &LdapMsg)) { goto cleanup; }
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = ldap_first_entry(Ldap, LdapMsg); LdapEntry != NULL; LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
//
// Basic info (dn, rdn, and guid)
//
Node = InfoAllocBasicNode(Info, TabW, L"CXTION", Base, CATEGORY_CXTION, &FirstError, Ldap, LdapEntry); if (!Node) { continue; }
//
// Node's partner's name
//
Node->PartnerDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_FROM_SERVER); FRS_WCSLWR(Node->PartnerDn); ShortName = InfoDup(Node->PartnerDn, INFO_DN_LEN); IPRINT2(Info, "%ws Partner Dn : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); Node->PartnerName = FrsBuildGName(NULL, FrsDsMakeRdn(Node->PartnerDn)); IPRINT2(Info, "%ws Partner Rdn : %ws\n", TabW, Node->PartnerName->Name);
//
// Enabled
//
Node->EnabledCxtion = FrsDsFindValue(Ldap, LdapEntry, ATTR_ENABLED_CXTION); IPRINT2(Info, "%ws Enabled : %ws\n", TabW, Node->EnabledCxtion);
//
// Options
//
CxtionOptionsWStr = FrsDsFindValue(Ldap, LdapEntry, ATTR_OPTIONS); if (CxtionOptionsWStr != NULL) { Node->CxtionOptions = _wtoi(CxtionOptionsWStr); CxtionOptionsWStr = FrsFree(CxtionOptionsWStr); } else { Node->CxtionOptions = 0; } IPRINT2(Info, "%ws Options : 0x%08x\n", TabW, Node->CxtionOptions);
//
// Schedule, if any
//
Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength); if (Node->Schedule) { if (IsSysVol) { IPRINT1(Info, "%ws IGNORED Schedule\n", TabW); } else { IPRINT1(Info, "%ws Schedule\n", TabW); } FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0); } Node = FrsFreeType(Node); } cleanup: LDAP_FREE_MSG(LdapMsg); FrsFreeType(Node); FrsFree(ShortName); }
VOID InfoCrack( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PWCHAR Dn, IN HANDLE Handle, IN PWCHAR DomainDnsName, IN DWORD DesiredFormat ) /*++
Routine Description: Find the NT4 account name for Dn. Dn should be the Dn of a computer object.
Arguments: Dn - Of computer object Handle - From DsBind DomainDnsName - If !NULL, produce new local handle DesiredFormat - DS_NT4_ACCOUNT_NAME or DS_STRING_SID_NAME
Return Value: NT4 Account Name or NULL --*/ { #undef DEBSUB
#define DEBSUB "InfoCrack:"
DWORD WStatus; DS_NAME_RESULT *Cracked; WCHAR TabW[MAX_TAB_WCHARS + 1]; PWCHAR ShortName = NULL; HANDLE LocalHandle = NULL;
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Computer's Dn not available
//
if (!Dn) { return; }
//
// Need something to go on!
//
if (!HANDLE_IS_VALID(Handle) && !DomainDnsName) { return; }
//
// Bind to Ds
//
if (DomainDnsName) { WStatus = DsBind(NULL, DomainDnsName, &LocalHandle); if (!WIN_SUCCESS(WStatus)) { IPRINT4(Info, "%ws ERROR - DsBind(%ws, %08x); WStatus %s\n", TabW, DomainDnsName, DesiredFormat, ErrLabelW32(WStatus)); return; } Handle = LocalHandle; }
//
// Crack the computer's distinguished name into its NT4 Account Name
//
WStatus = DsCrackNames(Handle, // in hDS,
DS_NAME_NO_FLAGS, // in flags,
DS_FQDN_1779_NAME, // in formatOffered,
DesiredFormat, // in formatDesired,
1, // in cNames,
&Dn, // in *rpNames,
&Cracked); // out *ppResult
if (!WIN_SUCCESS(WStatus)) { ShortName = InfoDup(Dn, INFO_DN_LEN); IPRINT4(Info, "%ws ERROR - DsCrackNames(%ws, %08x); WStatus %s\n", TabW, ShortName, DesiredFormat, ErrLabelW32(WStatus)); ShortName = FrsFree(ShortName); //
// What else can we do?
//
if (HANDLE_IS_VALID(LocalHandle)) { DsUnBind(&LocalHandle); } return; }
//
// Might have it
//
if (Cracked && Cracked->cItems && Cracked->rItems) { //
// Got it!
//
if (Cracked->rItems->status == DS_NAME_NO_ERROR) { IPRINT2(Info, "%ws Cracked Domain : %ws\n", TabW, Cracked->rItems->pDomain); IPRINT3(Info, "%ws Cracked Name : %08x %ws\n", TabW, DesiredFormat, Cracked->rItems->pName); //
// Only got the domain; rebind and try again
//
} else if (Cracked->rItems->status == DS_NAME_ERROR_DOMAIN_ONLY) { InfoCrack(Info, Tabs, Dn, NULL, Cracked->rItems->pDomain, DesiredFormat); } else { ShortName = InfoDup(Dn, INFO_DN_LEN); IPRINT4(Info, "%ws ERROR - DsCrackNames(%ws, %08x); internal status %d\n", TabW, ShortName, DesiredFormat, Cracked->rItems->status); ShortName = FrsFree(ShortName); } DsFreeNameResult(Cracked); } else { ShortName = InfoDup(Dn, INFO_DN_LEN); IPRINT3(Info, "%ws ERROR - DsCrackNames(%ws, %08x); no status\n", TabW, ShortName, DesiredFormat); ShortName = FrsFree(ShortName); } if (HANDLE_IS_VALID(LocalHandle)) { DsUnBind(&LocalHandle); } }
VOID InfoCrackDns( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN PWCHAR Base ) /*++
Routine Description: Find the DNS name for Base. Base should be the Dn of a computer object.
Arguments: Info Tabs Ldap Base
Return Value: Prints a message into Info. --*/ { #undef DEBSUB
#define DEBSUB "InfoCrackDns:"
PWCHAR Attrs[2]; WCHAR TabW[MAX_TAB_WCHARS + 1]; PLDAPMessage LdapEntry; PLDAPMessage LdapMsg = NULL; PWCHAR DnsName = NULL;
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Computer's Dn not available
//
if (!Base) { return; }
//
// Search the DS for the DNS attribute of Base
//
Attrs[0] = ATTR_DNS_HOST_NAME; Attrs[1] = NULL; if (!InfoSearch(Info, Tabs, Ldap, Base, LDAP_SCOPE_BASE, CATEGORY_ANY, Attrs, 0, &LdapMsg)) { goto cleanup; } LdapEntry = ldap_first_entry(Ldap, LdapMsg); if (!LdapEntry) { IPRINT2(Info, "%ws ERROR - No LdapEntry for Dns name on %ws\n", TabW, Base); goto cleanup; }
DnsName = FrsDsFindValue(Ldap, LdapEntry, ATTR_DNS_HOST_NAME); if (!DnsName) { IPRINT2(Info, "%ws ERROR - No DNS name on %ws\n", TabW, Base); goto cleanup; }
//
// Got it!
//
IPRINT2(Info, "%ws Computer's DNS : %ws\n", TabW, DnsName);
cleanup: LDAP_FREE_MSG(LdapMsg); FrsFree(DnsName); }
VOID InfoPrintMembers( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN BOOL IsSysVol, IN PWCHAR Base, IN HANDLE DsHandle ) /*++
Routine Description: Print the members
Arguments: ldap - opened and bound ldap connection Base - Name of object or container in DS
Return Value: None. --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintMembers:"
PWCHAR Attrs[7]; PLDAPMessage LdapEntry; PLDAPMessage LdapMsg = NULL; PCONFIG_NODE Node = NULL; PWCHAR ShortName = NULL; BOOL FirstError = TRUE; WCHAR TabW[MAX_TAB_WCHARS + 1];
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Search the DS for members
//
Attrs[0] = ATTR_OBJECT_GUID; Attrs[1] = ATTR_DN; Attrs[2] = ATTR_SCHEDULE; Attrs[3] = ATTR_USN_CHANGED; Attrs[4] = ATTR_SERVER_REF; Attrs[5] = ATTR_COMPUTER_REF; Attrs[6] = NULL; if (!InfoSearch(Info, Tabs, Ldap, Base, LDAP_SCOPE_ONELEVEL, CATEGORY_MEMBER, Attrs, 0, &LdapMsg)) { goto cleanup; }
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = ldap_first_entry(Ldap, LdapMsg); LdapEntry != NULL; LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
//
// Basic info (dn, rdn, and guid)
//
Node = InfoAllocBasicNode(Info, TabW, L"MEMBER", Base, CATEGORY_MEMBER, &FirstError, Ldap, LdapEntry); if (!Node) { continue; }
//
// NTDS Settings (DSA) Reference
//
Node->SettingsDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_SERVER_REF); ShortName = InfoDup(Node->SettingsDn, INFO_DN_LEN); IPRINT2(Info, "%ws Server Ref : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName);
//
// Computer Reference
//
Node->ComputerDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_COMPUTER_REF); FRS_WCSLWR(Node->ComputerDn); ShortName = InfoDup(Node->ComputerDn, INFO_DN_LEN); IPRINT2(Info, "%ws Computer Ref : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName);
InfoCrack(Info, Tabs, Node->ComputerDn, DsHandle, NULL, DS_NT4_ACCOUNT_NAME); InfoCrack(Info, Tabs, Node->ComputerDn, DsHandle, NULL, DS_STRING_SID_NAME); InfoCrackDns(Info, Tabs, Ldap, Node->ComputerDn);
//
// Schedule, if any
//
Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength); if (Node->Schedule) { IPRINT1(Info, "%ws Schedule\n", TabW); FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0); } //
// Get the inbound cxtions
//
InfoPrintDsCxtions(Info, Tabs + 1, Ldap, Node->Dn, FALSE); if (IsSysVol) { if (Node->SettingsDn) { InfoPrintDsCxtions(Info, Tabs + 1, Ldap, Node->SettingsDn, TRUE); } else { IPRINT2(Info, "%ws WARN - %ws lacks a settings reference\n", TabW, Node->Name->Name); } } Node = FrsFreeType(Node); } cleanup: LDAP_FREE_MSG(LdapMsg); FrsFreeType(Node); FrsFree(ShortName); }
VOID InfoPrintDsSets( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN PWCHAR SetDnAddr, IN HANDLE DsHandle, IN OUT PINFO_DN *InfoSets ) /*++
Routine Description: Print replica sets from the ds
Arguments: ldap - opened and bound ldap connection Base - Name of object or container in DS
Return Value: None --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintDsSets:"
PWCHAR Attrs[9]; DWORD i; PINFO_DN InfoSet; PLDAPMessage LdapEntry; PLDAPMessage LdapMsg = NULL; PCONFIG_NODE Node = NULL; PWCHAR ShortName = NULL; BOOL FirstError = TRUE; WCHAR TabW[MAX_TAB_WCHARS + 1];
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Have we processed this settings before?
//
for (InfoSet = *InfoSets; InfoSet; InfoSet = InfoSet->Next) { if (WSTR_EQ(InfoSet->Dn, SetDnAddr)) { IPRINT2(Info, "%ws %ws processed previously\n", TabW, SetDnAddr); break; } } //
// Yep; get the sets
//
if (InfoSet) { //
// Recurse to the next level in the DS hierarchy
//
InfoPrintMembers(Info, Tabs + 1, Ldap, FRS_RSTYPE_IS_SYSVOLW(InfoSet->SetType), InfoSet->Dn, DsHandle); goto cleanup; }
//
// Search the DS beginning at Base for sets
//
Attrs[0] = ATTR_OBJECT_GUID; Attrs[1] = ATTR_DN; Attrs[2] = ATTR_SCHEDULE; Attrs[3] = ATTR_USN_CHANGED; Attrs[4] = ATTR_SET_TYPE; Attrs[5] = ATTR_PRIMARY_MEMBER; Attrs[6] = ATTR_FILE_FILTER; Attrs[7] = ATTR_DIRECTORY_FILTER; Attrs[8] = NULL; if (!InfoSearch(Info, Tabs, Ldap, SetDnAddr, LDAP_SCOPE_BASE, CATEGORY_REPLICA_SET, Attrs, 0, &LdapMsg)) { goto cleanup; }
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = ldap_first_entry(Ldap, LdapMsg); LdapEntry != NULL; LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
//
// Basic info (dn, rdn, and guid)
//
Node = InfoAllocBasicNode(Info, TabW, L"SET", SetDnAddr, CATEGORY_REPLICA_SET, &FirstError, Ldap, LdapEntry); if (!Node) { continue; }
//
// Replica set type
//
Node->SetType = FrsDsFindValue(Ldap, LdapEntry, ATTR_SET_TYPE); IPRINT2(Info, "%ws Type : %ws\n", TabW, Node->SetType);
//
// Primary member
//
Node->MemberDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_PRIMARY_MEMBER); ShortName = InfoDup(Node->MemberDn, INFO_DN_LEN); IPRINT2(Info, "%ws Primary Member: %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName);
//
// File filter
//
Node->FileFilterList = FrsDsFindValue(Ldap, LdapEntry, ATTR_FILE_FILTER); IPRINT2(Info, "%ws File Filter : %ws\n", TabW, Node->FileFilterList);
//
// Directory filter
//
Node->DirFilterList = FrsDsFindValue(Ldap, LdapEntry, ATTR_DIRECTORY_FILTER); IPRINT2(Info, "%ws Dir Filter : %ws\n", TabW, Node->DirFilterList);
//
// Schedule, if any
//
Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength); if (Node->Schedule) { IPRINT1(Info, "%ws Schedule\n", TabW); FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0); }
InfoSet = FrsAlloc(sizeof(INFO_DN)); InfoSet->Dn = FrsWcsDup(Node->Dn); InfoSet->SetType = FrsWcsDup(Node->SetType); InfoSet->Next = *InfoSets; *InfoSets = InfoSet;
//
// Recurse to the next level in the DS hierarchy
//
InfoPrintMembers(Info, Tabs + 1, Ldap, FRS_RSTYPE_IS_SYSVOLW(Node->SetType), Node->Dn, DsHandle); Node = FrsFreeType(Node); } cleanup: LDAP_FREE_MSG(LdapMsg); FrsFreeType(Node); FrsFree(ShortName); }
VOID InfoPrintSettings( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN PWCHAR MemberDn, IN HANDLE DsHandle, IN OUT PINFO_DN *InfoSettings, IN OUT PINFO_DN *InfoSets ) /*++
Routine Description: Scan the DS tree for NTFRS-Settings
Arguments: ldap - opened and bound ldap connection Base - Name of object or container in DS
Return Value: WIN32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintSettings:"
PWCHAR Attrs[5]; PLDAPMessage LdapEntry; PWCHAR MemberDnAddr; PWCHAR SetDnAddr; PWCHAR SettingsDnAddr; PINFO_DN InfoSetting; PLDAPMessage LdapMsg = NULL; PCONFIG_NODE Node = NULL; PWCHAR ShortName = NULL; BOOL FirstError = TRUE; WCHAR TabW[MAX_TAB_WCHARS + 1];
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Find the member component
//
MemberDnAddr = wcsstr(MemberDn, L"cn="); if (!MemberDnAddr) { IPRINT2(Info, "%ws ERROR - No MemberDnAddr in %ws\n", TabW, MemberDn); goto cleanup; } //
// Find the set component
//
SetDnAddr = wcsstr(MemberDnAddr + 3, L"cn="); if (!SetDnAddr) { IPRINT2(Info, "%ws ERROR - No SetDnAddr in %ws\n", TabW, MemberDn); goto cleanup; } //
// Find the settings component
//
SettingsDnAddr = wcsstr(SetDnAddr + 3, L"cn="); if (!SettingsDnAddr) { IPRINT2(Info, "%ws ERROR - No SettingsDnAddr in %ws\n", TabW, MemberDn); goto cleanup; }
//
// Have we processed this settings before?
//
for (InfoSetting = *InfoSettings; InfoSetting; InfoSetting = InfoSetting->Next) { if (WSTR_EQ(InfoSetting->Dn, SettingsDnAddr)) { IPRINT2(Info, "%ws %ws processed previously\n", TabW, SettingsDnAddr); break; } } //
// Yep; get the sets
//
if (InfoSetting) { InfoPrintDsSets(Info, Tabs + 1, Ldap, SetDnAddr, DsHandle, InfoSets); goto cleanup; }
//
// Search the DS beginning at Base for settings
//
Attrs[0] = ATTR_OBJECT_GUID; Attrs[1] = ATTR_DN; Attrs[2] = ATTR_SCHEDULE; Attrs[3] = ATTR_USN_CHANGED; Attrs[4] = NULL; if (!InfoSearch(Info, Tabs, Ldap, SettingsDnAddr, LDAP_SCOPE_BASE, CATEGORY_NTFRS_SETTINGS, Attrs, 0, &LdapMsg)) { goto cleanup; }
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = ldap_first_entry(Ldap, LdapMsg); LdapEntry != NULL; LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
//
// Basic info (dn, rdn, and guid)
//
Node = InfoAllocBasicNode(Info, TabW, L"SETTINGS", SettingsDnAddr, CATEGORY_NTFRS_SETTINGS, &FirstError, Ldap, LdapEntry); if (!Node) { continue; }
//
// Schedule, if any
//
Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength); if (Node->Schedule) { IPRINT1(Info, "%ws Schedule\n", TabW); FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0); }
InfoSetting = FrsAlloc(sizeof(INFO_DN)); InfoSetting->Dn = FrsWcsDup(Node->Dn); InfoSetting->Next = *InfoSettings; *InfoSettings = InfoSetting;
//
// Recurse to the next level in the DS hierarchy
//
InfoPrintDsSets(Info, Tabs + 1, Ldap, SetDnAddr, DsHandle, InfoSets); Node = FrsFreeType(Node); } cleanup: LDAP_FREE_MSG(LdapMsg); FrsFreeType(Node); FrsFree(ShortName); }
VOID InfoPrintSubscribers( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN PWCHAR SubscriptionDn, IN PINFO_DN *InfoSubs ) /*++
Routine Description: Print subscribers
Arguments: Ldap - opened and bound ldap connection SubscriptionDn - distininguished name of subscriptions object
Return Value: WIN32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintSubscribers:"
PWCHAR Attrs[8]; PLDAPMessage LdapEntry; PINFO_DN InfoSub; PLDAPMessage LdapMsg = NULL; PCONFIG_NODE Node = NULL; PWCHAR ShortName = NULL; BOOL FirstError = TRUE; WCHAR TabW[MAX_TAB_WCHARS + 1];
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Search the DS beginning at Base for the entries of class "Filter"
//
Attrs[0] = ATTR_OBJECT_GUID; Attrs[1] = ATTR_DN; Attrs[2] = ATTR_SCHEDULE; Attrs[3] = ATTR_USN_CHANGED; Attrs[4] = ATTR_REPLICA_ROOT; Attrs[5] = ATTR_REPLICA_STAGE; Attrs[6] = ATTR_MEMBER_REF; Attrs[7] = NULL; if (!InfoSearch(Info, Tabs, Ldap, SubscriptionDn, LDAP_SCOPE_ONELEVEL, CATEGORY_SUBSCRIBER, Attrs, 0, &LdapMsg)) { goto cleanup; }
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = ldap_first_entry(Ldap, LdapMsg); LdapEntry != NULL; LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
//
// Basic info (dn, rdn, and guid)
//
Node = InfoAllocBasicNode(Info, TabW, L"SUBSCRIBER", SubscriptionDn, CATEGORY_SUBSCRIBER, &FirstError, Ldap, LdapEntry); if (!Node) { continue; }
//
// Member reference
//
Node->MemberDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_MEMBER_REF); ShortName = InfoDup(Node->MemberDn, INFO_DN_LEN); IPRINT2(Info, "%ws Member Ref: %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName);
if (Node->MemberDn) { InfoSub = FrsAlloc(sizeof(INFO_DN )); InfoSub->Dn = FrsWcsDup(Node->MemberDn); InfoSub->Next = *InfoSubs; *InfoSubs = InfoSub; }
//
// Root pathname
//
Node->Root = FrsDsFindValue(Ldap, LdapEntry, ATTR_REPLICA_ROOT); FRS_WCSLWR(Node->Root); IPRINT2(Info, "%ws Root : %ws\n", TabW, Node->Root);
//
// Staging pathname
//
Node->Stage = FrsDsFindValue(Ldap, LdapEntry, ATTR_REPLICA_STAGE); FRS_WCSLWR(Node->Stage); IPRINT2(Info, "%ws Stage : %ws\n", TabW, Node->Stage);
//
// Schedule, if any
//
Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength); if (Node->Schedule) { IPRINT1(Info, "%ws Schedule\n", TabW); FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0); }
Node = FrsFreeType(Node); } cleanup: LDAP_FREE_MSG(LdapMsg); FrsFreeType(Node); FrsFree(ShortName); }
VOID InfoPrintSubscriptions( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN PWCHAR ComputerDn, IN PINFO_DN *InfoSubs ) /*++
Routine Description: Recursively scan the DS tree beginning at computer
Arguments: Info Tabs Ldap ComputerDn
Return Value: WIN32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintSubscriptions:"
PWCHAR Attrs[6]; PLDAPMessage LdapEntry; PLDAPMessage LdapMsg = NULL; PCONFIG_NODE Node = NULL; PWCHAR ShortName = NULL; BOOL FirstError = TRUE; WCHAR TabW[MAX_TAB_WCHARS + 1];
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Search the DS beginning at Base for the entries of class "Filter"
//
Attrs[0] = ATTR_OBJECT_GUID; Attrs[1] = ATTR_DN; Attrs[2] = ATTR_SCHEDULE; Attrs[3] = ATTR_USN_CHANGED; Attrs[4] = ATTR_WORKING; Attrs[5] = NULL; if (!InfoSearch(Info, Tabs + 1, Ldap, ComputerDn, LDAP_SCOPE_SUBTREE, CATEGORY_SUBSCRIPTIONS, Attrs, 0, &LdapMsg)) { goto cleanup; }
//
// Scan the entries returned from ldap_search
//
for (LdapEntry = ldap_first_entry(Ldap, LdapMsg); LdapEntry != NULL; LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
//
// Basic info (dn, rdn, and guid)
//
Node = InfoAllocBasicNode(Info, TabW, L"SUBSCRIPTION", ComputerDn, CATEGORY_SUBSCRIPTIONS, &FirstError, Ldap, LdapEntry); if (!Node) { continue; }
//
// Working Directory
//
Node->Working = FrsDsFindValue(Ldap, LdapEntry, ATTR_WORKING); IPRINT2(Info, "%ws Working : %ws\n", TabW, Node->Working); IPRINT2(Info, "%ws Actual Working: %ws\n", TabW, WorkingPath);
//
// Schedule, if any
//
Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength); if (Node->Schedule) { IPRINT1(Info, "%ws Schedule\n", TabW); FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0); }
//
// Recurse to the next level in the DS hierarchy
//
InfoPrintSubscribers(Info, Tabs + 1, Ldap, Node->Dn, InfoSubs);
Node = FrsFreeType(Node); } cleanup: LDAP_FREE_MSG(LdapMsg); FrsFreeType(Node); FrsFree(ShortName); }
BOOL InfoPrintComputer( IN PNTFRSAPI_INFO Info, IN DWORD Tabs, IN PLDAP Ldap, IN PWCHAR FindDn, IN PWCHAR ObjectCategory, IN ULONG Scope, OUT PINFO_DN *InfoSubs ) /*++
Routine Description: Return internal info on DS computer objects.
Arguments: Info - RPC output buffer Tabs - number of tabs Ldap - bound ldap handle DefaultNcDn - DN of the DCs default naming context FindDn - Base Dn for search ObjectCategory - Object class (computer or user) A user object serves the same purpose as the computer object *sometimes* following a NT4 to NT5 upgrade. Scope - Scope of search (currently BASE or SUBTREE)
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintComputer:"
DWORD i; DWORD LStatus; PLDAPMessage LdapEntry; PWCHAR UserAccountControl; DWORD NumVals; PINFO_DN InfoSub; BOOL FoundAComputer = FALSE; PWCHAR ShortName = NULL; PCONFIG_NODE Node = NULL; PLDAPMessage LdapMsg = NULL; PWCHAR *Values = NULL; DWORD WStatus = ERROR_SUCCESS; BOOL FirstError = TRUE; WCHAR TabW[MAX_TAB_WCHARS + 1]; WCHAR Filter[MAX_PATH + 1]; WCHAR ComputerFqdn[MAX_PATH + 1]; DWORD ComputerFqdnLen; PWCHAR Attrs[10];
//
// Initialize return value
//
*InfoSubs = NULL;
//
// Adjust indentation
//
InfoTabs(Tabs, TabW);
//
// Filter that locates our computer object
//
swprintf(Filter, L"(&%s(sAMAccountName=%s$))", ObjectCategory, ComputerName);
//
// Search the DS beginning at Base for the entries of class "Filter"
//
Attrs[0] = ATTR_OBJECT_GUID; Attrs[1] = ATTR_DN; Attrs[2] = ATTR_SCHEDULE; Attrs[3] = ATTR_COMPUTER_REF_BL; Attrs[4] = ATTR_SERVER_REF; Attrs[5] = ATTR_SERVER_REF_BL; Attrs[6] = ATTR_USER_ACCOUNT_CONTROL; Attrs[7] = ATTR_DNS_HOST_NAME; Attrs[8] = NULL; InfoSearch(Info, Tabs + 1, Ldap, FindDn, Scope, Filter, Attrs, 0, &LdapMsg);
if (!LdapMsg) { goto CLEANUP; } //
// Scan the entries returned from ldap_search
//
for (LdapEntry = ldap_first_entry(Ldap, LdapMsg); LdapEntry != NULL && WIN_SUCCESS(WStatus); LdapEntry = ldap_next_entry(Ldap, LdapEntry)) { FoundAComputer = TRUE;
//
// Basic info (dn, rdn, and guid)
//
Node = InfoAllocBasicNode(Info, TabW, L"COMPUTER", FindDn, Filter, &FirstError, Ldap, LdapEntry); if (!Node) { continue; } UserAccountControl = FrsDsFindValue(Ldap, LdapEntry, ATTR_USER_ACCOUNT_CONTROL); if (UserAccountControl) { IPRINT2(Info, "%ws UAC : 0x%08x\n", TabW, wcstoul(UserAccountControl, NULL, 10)); UserAccountControl = FrsFree(UserAccountControl); }
//
// Server reference
//
Node->SettingsDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_SERVER_REF_BL); ShortName = InfoDup(Node->SettingsDn, INFO_DN_LEN); IPRINT2(Info, "%ws Server BL : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); if (!Node->SettingsDn) { Node->SettingsDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_SERVER_REF); ShortName = InfoDup(Node->SettingsDn, INFO_DN_LEN); IPRINT2(Info, "%ws Server Ref: %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); } //
// Make sure it references the settings; not the server
//
Node->SettingsDn = FrsDsConvertToSettingsDn(Node->SettingsDn); ShortName = InfoDup(Node->SettingsDn, INFO_DN_LEN); IPRINT2(Info, "%ws Settings : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName);
//
// DNS Host Name
//
Node->DnsName = FrsDsFindValue(Ldap, LdapEntry, ATTR_DNS_HOST_NAME); IPRINT2(Info, "%ws DNS Name : %ws\n", TabW, Node->DnsName);
//
// Schedule, if any
//
Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength); if (Node->Schedule) { IPRINT1(Info, "%ws Schedule\n", TabW); FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0); }
InfoPrintSubscriptions(Info, Tabs + 1, Ldap, Node->Dn, InfoSubs);
//
// Subscriber Member Bls
//
if (!*InfoSubs) { IPRINT2(Info, "%ws %ws IS NOT A MEMBER OF ANY SET!\n", TabW, ComputerName); } else { IPRINT1(Info, "%ws Subscriber Member Back Links:\n", TabW); for (InfoSub = *InfoSubs; InfoSub; InfoSub = InfoSub->Next) { FRS_WCSLWR(InfoSub->Dn); ShortName = InfoDup(InfoSub->Dn, INFO_DN_LEN); IPRINT2(Info, "%ws %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); } }
//
// Next computer
//
Node = FrsFreeType(Node); }
CLEANUP: LDAP_FREE_MSG(LdapMsg); FrsFreeType(Node); FrsFree(ShortName); return FoundAComputer; }
DWORD InfoPrintDs( IN PNTFRSAPI_INFO Info, IN DWORD Tabs ) /*++
Routine Description: Return internal info on DS (see private\net\inc\ntfrsapi.h).
Arguments: Info - RPC output buffer Tabs - number of tabs
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintDs:"
DWORD WStatus; DWORD LStatus; DWORD i; PWCHAR DcAddr; PWCHAR DcName; PWCHAR DcDnsName; DWORD NumVals; PWCHAR Config; PLDAPMessage LdapEntry; BOOL PrintedComputers; PINFO_DN InfoSub; PINFO_DN InfoSetting; PINFO_DN InfoSet; PINFO_DN InfoSubs = NULL; PINFO_DN InfoSettings = NULL; PINFO_DN InfoSets = NULL; PWCHAR ShortName = NULL; PWCHAR SitesDn = NULL; PWCHAR ServicesDn = NULL; PWCHAR DefaultNcDn = NULL; PWCHAR ComputersDn = NULL; PWCHAR DomainControllersDn = NULL; PLDAPMessage LdapMsg = NULL; PWCHAR *Values = NULL; PLDAP Ldap = NULL; HANDLE DsHandle = INVALID_HANDLE_VALUE; WCHAR ComputerFqdn[MAX_PATH + 1]; DWORD ComputerFqdnLen; WCHAR TabW[MAX_TAB_WCHARS + 1]; CHAR Guid[GUID_CHAR_LEN + 1]; PWCHAR Attrs[3]; PDOMAIN_CONTROLLER_INFO DcInfo = NULL; struct l_timeval Timeout;
DWORD InfoFlags; CHAR FlagBuffer[220]; ULONG ulOptions;
extern PWCHAR DsDomainControllerName; extern FLAG_NAME_TABLE DsGetDcInfoFlagNameTable[]; //
// Client side ldap_connect timeout in seconds. Reg value "Ldap Bind Timeout In Seconds". Default is 30 seconds.
//
extern DWORD LdapBindTimeoutInSeconds;
//
// Adjust indentation
//
InfoTabs(Tabs, TabW); IPRINT1(Info, "%wsNTFRS CONFIGURATION IN THE DS\n", TabW);
Ldap = NULL; if (IsADc) { DcAddr = NULL; DcName = ComputerName; DcDnsName = ComputerDnsName; IPRINT1(Info, "%wsSUBSTITUTE DCINFO FOR DC\n", TabW); IPRINT2(Info, "%ws FRS DomainControllerName: %ws\n", TabW, DsDomainControllerName); IPRINT2(Info, "%ws Computer Name : %ws\n", TabW, DcName); IPRINT2(Info, "%ws Computer DNS Name : %ws\n", TabW, DcDnsName); } else { //
// Domain Controller
//
WStatus = DsGetDcName(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED | DS_WRITABLE_REQUIRED | DS_BACKGROUND_ONLY, &DcInfo); if (!WIN_SUCCESS(WStatus)) { DcInfo = NULL; IPRINT2(Info, "%wsWARN - DsGetDcName WStatus %s; Flushing cache...\n", TabW, ErrLabelW32(WStatus)); WStatus = DsGetDcName(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_REQUIRED | DS_WRITABLE_REQUIRED | DS_FORCE_REDISCOVERY, &DcInfo); } //
// Report the error and retry for any DC
//
if (!WIN_SUCCESS(WStatus)) { DcInfo = NULL; IPRINT3(Info, "%wsERROR - DsGetDcName(%ws); WStatus %s\n", TabW, ComputerName, ErrLabelW32(WStatus)); goto cleanup; }
//
// Dump dcinfo
//
IPRINT1(Info, "%wsDCINFO\n", TabW); IPRINT2(Info, "%ws LAST DomainControllerName: %ws\n", TabW, DsDomainControllerName); IPRINT2(Info, "%ws DomainControllerName : %ws\n", TabW, DcInfo->DomainControllerName); IPRINT2(Info, "%ws DomainControllerAddress : %ws\n", TabW, DcInfo->DomainControllerAddress); IPRINT2(Info, "%ws DomainControllerType : %08x\n",TabW, DcInfo->DomainControllerAddressType); IPRINT2(Info, "%ws DomainName : %ws\n", TabW, DcInfo->DomainName); IPRINT2(Info, "%ws DnsForestName : %ws\n", TabW, DcInfo->DnsForestName); IPRINT2(Info, "%ws DcSiteName : %ws\n", TabW, DcInfo->DcSiteName); IPRINT2(Info, "%ws ClientSiteName : %ws\n", TabW, DcInfo->ClientSiteName);
InfoFlags = DcInfo->Flags; FrsFlagsToStr(InfoFlags, DsGetDcInfoFlagNameTable, sizeof(FlagBuffer), FlagBuffer); IPRINT3(Info, "%ws Flags : %08x [%s]\n",TabW, InfoFlags, FlagBuffer);
if (!DsDomainControllerName || !DcInfo->DomainControllerName || WSTR_NE(DsDomainControllerName, DcInfo->DomainControllerName)) { IPRINT3(Info, "%wsWARN - Using DC %ws; not %ws\n", TabW, DcInfo->DomainControllerName, DsDomainControllerName); }
//
// Binding address
//
DcAddr = DcInfo->DomainControllerAddress; DcDnsName = DcInfo->DomainControllerName; } wcsncpy(InfoDcName, DcDnsName, ARRAY_SZ(InfoDcName)-1); //
// BIND to the DS
//
IPRINT1(Info, "\n%wsBINDING TO THE DS:\n", TabW);
//
// 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.
//
//
// Remove the leading \\ if they exist.
//
FRS_TRIM_LEADING_2SLASH(DcDnsName); FRS_TRIM_LEADING_2SLASH(DcAddr);
ulOptions = PtrToUlong(LDAP_OPT_ON); Timeout.tv_sec = LdapBindTimeoutInSeconds; Timeout.tv_usec = 0;
//
// Try using DcDnsName first.
//
if ((Ldap == NULL) && (DcDnsName != NULL)) {
Ldap = ldap_init(DcDnsName, LDAP_PORT); if (Ldap != NULL) { ldap_set_option(Ldap, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions); LStatus = ldap_connect(Ldap, &Timeout); if (LStatus != LDAP_SUCCESS) { IPRINT4(Info, "%ws WARN - ldap_connect(%ws); (ldap error %08x = %ws)\n", TabW, DcDnsName, LStatus, ldap_err2string(LStatus)); ldap_unbind_s(Ldap); Ldap = NULL; } else { IPRINT2(Info, "%ws ldap_connect : %ws\n", TabW, DcDnsName); } } }
//
// Try using DcAddr next.
//
if ((Ldap == NULL) && (DcAddr != NULL)) {
Ldap = ldap_init(DcAddr, LDAP_PORT); if (Ldap != NULL) { ldap_set_option(Ldap, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions); LStatus = ldap_connect(Ldap, &Timeout); if (LStatus != LDAP_SUCCESS) { IPRINT4(Info, "%ws WARN - ldap_connect(%ws); (ldap error %08x = %ws)\n", TabW, DcAddr, LStatus, ldap_err2string(LStatus)); ldap_unbind_s(Ldap); Ldap = NULL; } else { IPRINT2(Info, "%ws ldap_connect : %ws\n", TabW, DcAddr); } } }
//
// Try using DcName finally.
//
if ((Ldap == NULL) && (DcName != NULL)) {
Ldap = ldap_init(DcName, LDAP_PORT); if (Ldap != NULL) { ldap_set_option(Ldap, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions); LStatus = ldap_connect(Ldap, &Timeout); if (LStatus != LDAP_SUCCESS) { IPRINT4(Info, "%ws WARN - ldap_connect(%ws); (ldap error %08x = %ws)\n", TabW, DcName, LStatus, ldap_err2string(LStatus)); ldap_unbind_s(Ldap); Ldap = NULL; } else { IPRINT2(Info, "%ws ldap_connect : %ws\n", TabW, DcName); } } }
//
// Whatever it is, we can't find it.
//
if (!Ldap) { IPRINT6(Info, "%ws ERROR - ldap_connect(DNS %ws, BIOS %ws, IP %ws); (ldap error %08x = %ws)\n", TabW, DcDnsName, DcName, DcAddr, LStatus, ldap_err2string(LStatus)); goto cleanup; }
//
// Bind to the ldap server
//
LStatus = ldap_bind_s(Ldap, NULL, NULL, LDAP_AUTH_NEGOTIATE);
//
// No luck; report error and carry on
//
if (LStatus != LDAP_SUCCESS) { IPRINT4(Info, "%ws ERROR - ldap_bind_s(%ws); (ldap error %08x = %ws)\n", TabW, ComputerName, LStatus, ldap_err2string(LStatus)); goto cleanup; }
//
// Bind to the Ds (for various Ds calls such as DsCrackName())
//
//
// DC's Dns Name
//
WStatus = ERROR_RETRY; if (!WIN_SUCCESS(WStatus) && DcDnsName) { WStatus = DsBind(DcDnsName, NULL, &DsHandle); if (!WIN_SUCCESS(WStatus)) { DsHandle = NULL; IPRINT3(Info, "%ws WARN - DsBind(DcDnsName %ws); WStatus %s\n", TabW, DcDnsName, ErrLabelW32(WStatus)); } else { IPRINT2(Info, "%ws DsBind : %ws\n", TabW, DcDnsName); } }
//
// DC's Computer Name
//
if (!WIN_SUCCESS(WStatus) && DcName) { WStatus = DsBind(DcName, NULL, &DsHandle); if (!WIN_SUCCESS(WStatus)) { DsHandle = NULL; IPRINT3(Info, "%ws WARN - DsBind(DcName %ws); WStatus %s\n", TabW, DcName, ErrLabelW32(WStatus)); } else { IPRINT2(Info, "%ws DsBind : %ws\n", TabW, DcName); } }
//
// DC's IP Address
//
if (!WIN_SUCCESS(WStatus) && DcAddr) { WStatus = DsBind(DcAddr, NULL, &DsHandle); if (!WIN_SUCCESS(WStatus)) { DsHandle = NULL; IPRINT3(Info, "%ws WARN - DsBind(DcAddr %ws); WStatus %s\n", TabW, DcAddr, ErrLabelW32(WStatus)); } else { IPRINT2(Info, "%ws DsBind : %ws\n", TabW, DcAddr); } }
//
// Whatever it is, we can't find it
//
if (!WIN_SUCCESS(WStatus)) { IPRINT5(Info, "%ws ERROR - DsBind(DNS %ws, BIOS %ws, IP %ws); WStatus %s\n", TabW, DcDnsName, DcName, DcAddr, ErrLabelW32(WStatus)); goto cleanup; }
//
// NAMING CONTEXTS
//
IPRINT1(Info, "\n%wsNAMING CONTEXTS:\n", TabW);
//
// Find the naming contexts and the default naming context
//
Attrs[0] = ATTR_NAMING_CONTEXTS; Attrs[1] = ATTR_DEFAULT_NAMING_CONTEXT; Attrs[2] = NULL; if (!InfoSearch(Info, Tabs + 1, Ldap, CN_ROOT, LDAP_SCOPE_BASE, CATEGORY_ANY, Attrs, 0, &LdapMsg)) { goto cleanup; }
LdapEntry = ldap_first_entry(Ldap, LdapMsg); if (!LdapEntry) { IPRINT2(Info, "%ws ERROR - ldap_first_entry(contexts, %ws) no entry\n", TabW, ComputerName); goto cleanup; } Values = (PWCHAR *)FrsDsFindValues(Ldap, LdapEntry, ATTR_NAMING_CONTEXTS, FALSE); if (!Values) { IPRINT2(Info, "%ws ERROR - FrsDsFindValues(contexts, %ws) no entry\n", TabW, ComputerName); goto cleanup; }
//
// Now, find the naming context that begins with "CN=configuration"
//
NumVals = ldap_count_values(Values); while (NumVals--) { FRS_WCSLWR(Values[NumVals]); Config = wcsstr(Values[NumVals], CONFIG_NAMING_CONTEXT); if (Config && Config == Values[NumVals]) { //
// Build the pathname for "configuration\sites & services"
//
SitesDn = FrsDsExtendDn(Config, CN_SITES); ServicesDn = FrsDsExtendDn(Config, CN_SERVICES); break; } } LDAP_FREE_VALUES(Values);
//
// Finally, find the default naming context
//
Values = (PWCHAR *)FrsDsFindValues(Ldap, LdapEntry, ATTR_DEFAULT_NAMING_CONTEXT, FALSE); if (!Values) { IPRINT2(Info, "%ws ERROR - FrsDsFindValues(default naming context, %ws) no entry\n", TabW, ComputerName); goto cleanup; }
DefaultNcDn = FrsWcsDup(Values[0]); ComputersDn = FrsDsExtendDn(DefaultNcDn, CN_COMPUTERS); DomainControllersDn = FrsDsExtendDnOu(DefaultNcDn, CN_DOMAIN_CONTROLLERS); LDAP_FREE_VALUES(Values);
ShortName = InfoDup(SitesDn, INFO_DN_LEN); IPRINT2(Info, "%ws SitesDn : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); ShortName = InfoDup(ServicesDn, INFO_DN_LEN); IPRINT2(Info, "%ws ServicesDn : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); ShortName = InfoDup(DefaultNcDn, INFO_DN_LEN); IPRINT2(Info, "%ws DefaultNcDn: %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); ShortName = InfoDup(ComputersDn, INFO_DN_LEN); IPRINT2(Info, "%ws ComputersDn: %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); ShortName = InfoDup(DomainControllersDn, INFO_DN_LEN); IPRINT2(Info, "%ws DomainCtlDn: %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName);
//
// Retrieve the computer's fully qualified Dn
//
ComputerFqdnLen = MAX_PATH; if (!GetComputerObjectName(NameFullyQualifiedDN, ComputerFqdn, &ComputerFqdnLen)) { IPRINT4(Info, "%ws ERROR - GetComputerObjectName(%ws); Len %d, WStatus %s\n", TabW, ComputerName, ComputerFqdnLen, ErrLabelW32(GetLastError())); ComputerFqdn[0] = L'\0'; } else { ShortName = InfoDup(ComputerFqdn, INFO_DN_LEN); IPRINT2(Info, "%ws Fqdn : %ws\n", TabW, ShortName); ShortName = FrsFree(ShortName); }
//
// Find and print the computer info
//
PrintedComputers = FALSE; if (!PrintedComputers && ComputerFqdn[0]) { IPRINT1(Info, "%ws Searching : Fqdn\n", TabW); PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, ComputerFqdn, CATEGORY_COMPUTER, LDAP_SCOPE_BASE, &InfoSubs); } if (!PrintedComputers && ComputersDn) { IPRINT1(Info, "%ws Searching : Computers\n", TabW); PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, ComputersDn, CATEGORY_COMPUTER, LDAP_SCOPE_SUBTREE, &InfoSubs); } if (!PrintedComputers && DomainControllersDn) { IPRINT1(Info, "%ws Searching : Domain Controllers\n", TabW); PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, DomainControllersDn, CATEGORY_COMPUTER, LDAP_SCOPE_SUBTREE, &InfoSubs); } if (!PrintedComputers && DefaultNcDn) { IPRINT1(Info, "%ws Searching : Default Naming Context\n", TabW); PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, DefaultNcDn, CATEGORY_COMPUTER, LDAP_SCOPE_SUBTREE, &InfoSubs); } if (!PrintedComputers && DefaultNcDn) { IPRINT1(Info, "%ws Searching : Default Naming Context for USER\n", TabW); PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, DefaultNcDn, CATEGORY_USER, LDAP_SCOPE_SUBTREE, &InfoSubs); }
for (InfoSub = InfoSubs; InfoSub; InfoSub = InfoSub->Next) { InfoPrintSettings(Info, Tabs, Ldap, InfoSub->Dn, DsHandle, &InfoSettings, &InfoSets); }
cleanup: //
// Cleanup
//
LDAP_FREE_VALUES(Values); LDAP_FREE_MSG(LdapMsg); if (DcInfo) { NetApiBufferFree(DcInfo); DcInfo = NULL; } if (Ldap) { ldap_unbind_s(Ldap); } if (HANDLE_IS_VALID(DsHandle)) { DsUnBind(&DsHandle); } FrsFree(SitesDn); FrsFree(ServicesDn); FrsFree(DefaultNcDn); FrsFree(ComputersDn); FrsFree(DomainControllersDn); FrsFree(ShortName);
while (InfoSub = InfoSubs) { InfoSubs = InfoSub->Next; FrsFree(InfoSub->Dn); FrsFree(InfoSub->SetType); FrsFree(InfoSub); } while (InfoSetting = InfoSettings) { InfoSettings = InfoSetting->Next; FrsFree(InfoSetting->Dn); FrsFree(InfoSetting->SetType); FrsFree(InfoSetting); } while (InfoSet = InfoSets) { InfoSets = InfoSet->Next; FrsFree(InfoSet->Dn); FrsFree(InfoSet->SetType); FrsFree(InfoSet); }
//
// Real error messages are in the info buffer
//
return ERROR_SUCCESS; }
PVOID InfoFreeInfoTable( IN PINFO_TABLE InfoTable, IN PNTFRSAPI_INFO Info ) /*++
Routine Description: Free the info IDTable
Arguments: InfoTable Info
Return Value: NULL --*/ { #undef DEBSUB
#define DEBSUB "InfoFreeInfoTable:"
JET_ERR jerr;
if (!InfoTable) { return NULL; } if (InfoTable->TableCtx) { DbsFreeTableContext(InfoTable->TableCtx, InfoTable->ThreadCtx->JSesid); } if (InfoTable->ThreadCtx) { jerr = DbsCloseJetSession(InfoTable->ThreadCtx); if (!JET_SUCCESS(jerr)) { IPRINT1(Info, "DbsCloseJetSession jet error = %s\n", ErrLabelJet(jerr)); }
InfoTable->ThreadCtx = FrsFreeType(InfoTable->ThreadCtx); }
return FrsFree(InfoTable);
}
JET_ERR InfoConfigTableWorker( IN PTHREAD_CTX ThreadCtx, IN PTABLE_CTX TableCtx, IN PCONFIG_TABLE_RECORD ConfigRecord, IN PINFO_TABLE InfoTable ) /*++
Routine Description:
This is a worker function passed to FrsEnumerateTable(). Each time it is called it prints an entry into the info buffer.
Arguments:
ThreadCtx - Needed to access Jet. TableCtx - A ptr to an ConfigTable context struct. ConfigRecord - A ptr to a config table record. InfoTable
Thread Return Value:
A Jet error status. Success means call us with the next record. Failure means don't call again and pass our status back to the caller of FrsEnumerateTable().
--*/ { #undef DEBSUB
#define DEBSUB "InfoConfigTableWorker:"
if (FlagOn(InfoTable->Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) { return JET_errNoCurrentRecord; }
IPRINT0(InfoTable->Info, "\n\n");
DbsDisplayRecordIPrint(TableCtx, InfoTable, TRUE, NULL, 0);
return JET_errSuccess; }
JET_ERR InfoIDTableWorker( IN PTHREAD_CTX ThreadCtx, IN PTABLE_CTX TableCtx, IN PIDTABLE_RECORD IDTableRec, IN PINFO_TABLE InfoTable ) /*++
Routine Description:
This is a worker function passed to FrsEnumerateTable(). Each time it is called it prints an entry into the info buffer.
Arguments:
ThreadCtx - Needed to access Jet. TableCtx - A ptr to an IDTable context struct. IDTableRec - A ptr to a IDTable record. InfoTable
Thread Return Value:
A Jet error status. Success means call us with the next record. Failure means don't call again and pass our status back to the caller of FrsEnumerateTable().
--*/ { #undef DEBSUB
#define DEBSUB "InfoIDTableWorker:"
CHAR FlagBuffer[120]; WCHAR TabW[MAX_TAB_WCHARS + 1]; CHAR TimeStr[TIME_STRING_LENGTH]; CHAR Guid[GUID_CHAR_LEN + 1];
if (FlagOn(InfoTable->Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) { return JET_errNoCurrentRecord; }
//
// Table Descriptor
//
IPRINT1(InfoTable->Info, "\nTable Type: ID Table for %ws\n", InfoTable->Replica->ReplicaName->Name);
DbsDisplayRecordIPrint(TableCtx, InfoTable, TRUE, NULL, 0);
return JET_errSuccess;
}
JET_ERR InfoInOutLogTableWorker( IN PTHREAD_CTX ThreadCtx, IN PTABLE_CTX TableCtx, IN PCHANGE_ORDER_COMMAND Coc, IN PINFO_TABLE InfoTable, IN PWCHAR TableDescriptor ) /*++
Routine Description:
This is a worker function passed to FrsEnumerateTable(). Each time it is called it prints an entry into the info buffer.
Arguments:
ThreadCtx - Needed to access Jet. TableCtx - A ptr to an IDTable context struct. Coc - A ptr to a inbound log record (change order) InfoTable TableDescriptor
Thread Return Value:
A Jet error status. Success means call us with the next record. Failure means don't call again and pass our status back to the caller of FrsEnumerateTable().
--*/ { #undef DEBSUB
#define DEBSUB "InfoInOutLogTableWorker:"
PREPLICA Replica;
PCXTION Cxtion = NULL; PWSTR CxtName = L"<null>"; PWSTR PartnerName = L"<null>"; PWSTR PartSrvName = L"<null>"; PCHAR CxtionState = "<null>"; BOOL PrintCxtion;
if (FlagOn(InfoTable->Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) { return JET_errNoCurrentRecord; }
//
// Table Descriptor
//
IPRINT2(InfoTable->Info, "\nTable Type: %ws for %ws\n", TableDescriptor, InfoTable->Replica->ReplicaName->Name);
//
// Dump the change order record.
//
DbsDisplayRecordIPrint(TableCtx, InfoTable, TRUE, NULL, 0);
Replica = InfoTable->Replica; //
// Find the cxtion for this CO
//
LOCK_CXTION_TABLE(Replica);
Cxtion = GTabLookupNoLock(Replica->Cxtions, &Coc->CxtionGuid, NULL);
PrintCxtion = (Cxtion != NULL) && (Cxtion->Inbound);
if (PrintCxtion) { CxtionState = CxtionStateNames[Cxtion->State];
if (Cxtion->Name != NULL) {
if (Cxtion->Name->Name != NULL) { CxtName = Cxtion->Name->Name; } }
if ((Cxtion->Partner != NULL) && (Cxtion->Partner->Name != NULL)) { PartnerName = Cxtion->Partner->Name; }
if (Cxtion->PartSrvName != NULL) { PartSrvName = Cxtion->PartSrvName; } } UNLOCK_CXTION_TABLE(Replica);
if (PrintCxtion) { IPRINT3(InfoTable->Info, "Cxtion Name : %ws <- %ws\\%ws\n", CxtName, PartnerName, PartSrvName);
IPRINT1(InfoTable->Info, "Cxtion State : %s\n", CxtionState); }
return JET_errSuccess;
}
JET_ERR InfoInLogTableWorker( IN PTHREAD_CTX ThreadCtx, IN PTABLE_CTX TableCtx, IN PCHANGE_ORDER_COMMAND Coc, IN PINFO_TABLE InfoTable ) /*++
Routine Description:
This is a worker function passed to FrsEnumerateTable(). Each time it is called it prints an entry into the info buffer.
Arguments:
ThreadCtx - Needed to access Jet. TableCtx - A ptr to an IDTable context struct. Coc - A ptr to a inbound log record (change order) InfoTable
Thread Return Value:
A Jet error status. Success means call us with the next record. Failure means don't call again and pass our status back to the caller of FrsEnumerateTable().
--*/ { return InfoInOutLogTableWorker(ThreadCtx, TableCtx, Coc, InfoTable, L"Inbound Log Table"); }
JET_ERR InfoOutLogTableWorker( IN PTHREAD_CTX ThreadCtx, IN PTABLE_CTX TableCtx, IN PCHANGE_ORDER_COMMAND Coc, IN PINFO_TABLE InfoTable ) /*++
Routine Description:
This is a worker function passed to FrsEnumerateTable(). Each time it is called it prints an entry into the info buffer.
Arguments:
ThreadCtx - Needed to access Jet. TableCtx - A ptr to an IDTable context struct. Coc - A ptr to a inbound log record (change order) InfoTable
Thread Return Value:
A Jet error status. Success means call us with the next record. Failure means don't call again and pass our status back to the caller of FrsEnumerateTable().
--*/ { return InfoInOutLogTableWorker(ThreadCtx, TableCtx, Coc, InfoTable, L"Outbound Log Table"); }
DWORD InfoPrintSingleTable( IN PNTFRSAPI_INFO Info, IN PWCHAR TableName, IN TABLE_TYPE TableType, IN PREPLICA Replica, IN ULONG InfoIndexx, IN PENUMERATE_TABLE_ROUTINE InfoTableWorker ) /*++
Routine Description:
Display data for the specified table using the InfoPrint interface.
Arguments: Info - ptr to the API Info ctx. TableName - The name of the table TableType - the Type code for the table. Replica, -- ptr to the replica struct for the replica set. InfoIndexx -- The ID of the index to use when enumerating the table. InfoTableWorker -- The function to call to display each record.
Return Value: jet error Status
--*/ { #undef DEBSUB
#define DEBSUB "InfoPrintSingleTable:"
JET_ERR jerr = JET_errSuccess; PINFO_TABLE InfoTable = NULL;
InfoTable = FrsAlloc(sizeof(*InfoTable)); InfoTable->ThreadCtx = FrsAllocType(THREAD_CONTEXT_TYPE); InfoTable->TableCtx = DbsCreateTableContext(TableType); InfoTable->Info = Info; InfoTable->Tabs = 0; /* Tabs + 1*/ // Pitch this tabs stuff.
IPRINT1(Info, "\n***** %ws\n", TableName); //
// Setup a Jet Session (returning the session ID in ThreadCtx).
//
jerr = DbsCreateJetSession(InfoTable->ThreadCtx); if (!JET_SUCCESS(jerr)) { IPRINT2(Info,"ERROR - %ws: DbsCreateJetSession jet error %s.\n", TableName, ErrLabelJet(jerr)); goto RETURN; } //
// Init the table context and open the ID table.
//
jerr = DbsOpenTable(InfoTable->ThreadCtx, InfoTable->TableCtx, ReplicaAddrToId(Replica), TableType, NULL); if (!JET_SUCCESS(jerr)) { IPRINT2(Info,"ERROR - %ws: DbsOpenTable jet error %s.\n", TableName, ErrLabelJet(jerr)); goto RETURN; }
//
// Replica
//
InfoTable->Replica = Replica;
//
// Scan thru the Table
//
jerr = FrsEnumerateTable(InfoTable->ThreadCtx, InfoTable->TableCtx, InfoIndexx, InfoTableWorker, InfoTable); //
// We're done. Return success if we made it to the end
//
if (jerr != JET_errNoCurrentRecord && jerr != JET_wrnTableEmpty) { IPRINT2(Info,"ERROR - %ws: FrsEnumerateTable jet error %s.\n", TableName, ErrLabelJet(jerr)); }
RETURN: //
// Done
//
InfoTable = InfoFreeInfoTable(InfoTable, Info);
return jerr; }
DWORD InfoPrintTables( IN PNTFRSAPI_INFO Info, IN PWCHAR TableDescriptor, IN TABLE_TYPE TableType, IN ULONG InfoIndexx, IN PENUMERATE_TABLE_ROUTINE InfoTableWorker ) /*++
Routine Description: Return internal info on a DB Table (see private\net\inc\ntfrsapi.h).
Arguments: Info - RPC output buffer TableDescriptor - Text string for output TableType - Table type code (from schema.h) InfoIndexx - Table index to use for enumeration (from schema.h)
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintTables:"
PVOID Key; PREPLICA Replica = NULL; extern PGEN_TABLE ReplicasByGuid;
//
// Check for single instance tables.
//
if ((TableType == ConfigTablex) || (TableType == ServiceTablex)) {
InfoPrintSingleTable(Info, TableDescriptor, TableType, Replica, InfoIndexx, InfoTableWorker); return ERROR_SUCCESS; }
//
// For the given table type, dump info for all replica sets.
//
IPRINT1(Info, "NTFRS %ws\n", TableDescriptor);
Key = NULL; while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
InfoPrintSingleTable(Info, Replica->ReplicaName->Name, TableType, Replica, InfoIndexx, InfoTableWorker); }
return ERROR_SUCCESS; }
DWORD InfoPrintMemory( IN PNTFRSAPI_INFO Info, IN DWORD Tabs ) /*++
Routine Description: Return internal info on memory usage (see private\net\inc\ntfrsapi.h).
Arguments: Info - RPC output buffer Tabs - number of tabs
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintMemory:"
FrsPrintAllocStats(0, Info, Tabs); FrsPrintRpcStats(0, Info, Tabs); return ERROR_SUCCESS; }
DWORD InfoPrintThreads( IN PNTFRSAPI_INFO Info, IN DWORD Tabs ) /*++
Routine Description: Return internal info on thread usage (see private\net\inc\ntfrsapi.h).
Arguments: Info - RPC output buffer Tabs - number of tabs
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintThreads:"
FrsPrintThreadStats(0, Info, Tabs); return ERROR_SUCCESS; }
VOID FrsPrintStageStats( IN ULONG Severity, IN PNTFRSAPI_INFO Info, OPTIONAL IN DWORD Tabs ); DWORD InfoPrintStage( IN PNTFRSAPI_INFO Info, IN DWORD Tabs ) /*++
Routine Description: Return internal info on thread usage (see private\net\inc\ntfrsapi.h).
Arguments: Info - RPC output buffer Tabs - number of tabs
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoPrintStage:"
FrsPrintStageStats(0, Info, Tabs); return ERROR_SUCCESS; }
DWORD InfoVerify( IN ULONG BlobSize, IN OUT PBYTE Blob ) /*++
Routine Description: Verify the consistency of the blob.
Arguments: BlobSize - total bytes of Blob Blob - details desired info and provides buffer for info
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "InfoVerify:"
DWORD WStatus; PBYTE EoB; PBYTE EoI; PBYTE BoL; PBYTE BoF; PNTFRSAPI_INFO Info = (PNTFRSAPI_INFO)Blob;
//
// Assume success
//
WStatus = ERROR_SUCCESS;
//
// Not a valid blob
//
if (BlobSize < NTFRSAPI_INFO_HEADER_SIZE) { WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER; goto CLEANUP; }
//
// BlobSize must include the entire Blob
//
if (BlobSize != Info->SizeInChars) { WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER; goto CLEANUP; }
//
// Return our info version
//
Info->NtFrsMajor = NTFRS_MAJOR; Info->NtFrsMinor = NTFRS_MINOR; SetFlag(Info->Flags, NTFRSAPI_INFO_FLAGS_VERSION);
//
// Bad major
//
if (Info->Major != Info->NtFrsMajor) { WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER; goto CLEANUP; } //
// Bad minor
//
if (Info->Minor != Info->NtFrsMinor) { WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER; goto CLEANUP; }
//
// Not large enough to verify internal consistency
//
if (Info->SizeInChars < sizeof(NTFRSAPI_INFO)) { WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER; goto CLEANUP; }
//
// Buffer full; done
//
if (FlagOn(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) { goto CLEANUP; }
//
// Verify internal offsets
//
// make this into a subroutine (table driven?)
//
EoB = Blob + BlobSize; EoI = ((PBYTE)Info) + (Info->SizeInChars); BoL = (PBYTE)(((PCHAR)Info) + Info->OffsetToLines); BoF = (PBYTE)(((PCHAR)Info) + Info->OffsetToFree); if (EoI > EoB || BoL > EoB || BoF > EoB || EoI < Blob || BoL < Blob || BoF < Blob) { WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER; goto CLEANUP; }
//
// No free space in buffer; done
//
if (BoF == EoB) { SetFlag(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL); goto CLEANUP; } CLEANUP: return WStatus; }
DWORD Info( IN ULONG BlobSize, IN OUT PBYTE Blob ) /*++
Routine Description: Return internal info (see private\net\inc\ntfrsapi.h).
Arguments: BlobSize - total bytes of Blob Blob - details desired info and provides buffer for info
Return Value: Win32 Status --*/ { #undef DEBSUB
#define DEBSUB "Info:"
DWORD WStatus; PBYTE EoB; PBYTE EoI; PBYTE BoL; PBYTE BoF; ULONG i; PNTFRSAPI_INFO Info = (PNTFRSAPI_INFO)Blob; ULONG ProductType; ULONG Arch;
try { //
// Verify the blob
//
WStatus = InfoVerify(BlobSize, Blob); if (!WIN_SUCCESS(WStatus)) { goto cleanup; }
//
// Full buffer; done
//
if (FlagOn(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) { goto cleanup; }
if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_VERSION) { IPRINT0(Info, "NtFrs Version Information\n"); IPRINT1(Info, " NtFrs Major : %d\n", NtFrsMajor); IPRINT1(Info, " NtFrs Minor : %d\n", NtFrsMinor); // IPRINT1(Info, " NtFrs Module : %s\n", NtFrsModule);
IPRINT2(Info, " NtFrs Compiled on : %s %s\n", NtFrsDate, NtFrsTime); #if NTFRS_TEST
IPRINT0(Info, " NTFRS_TEST Enabled\n"); #else NTFRS_TEST
IPRINT0(Info, " NTFRS_TEST Disabled\n"); #endif NTFRS_TEST
i = 0; while (LatestChanges[i] != NULL) { IPRINT1(Info, " %s\n", LatestChanges[i]); i++; }
IPRINT4(Info, "OS Version %d.%d (%d) - %w\n", OsInfo.dwMajorVersion, OsInfo.dwMinorVersion, OsInfo.dwBuildNumber, OsInfo.szCSDVersion);
ProductType = (ULONG) OsInfo.wProductType; IPRINT4(Info, "SP (%hd.%hd) SM: 0x%04hx PT: 0x%02x\n", OsInfo.wServicePackMajor, OsInfo.wServicePackMinor, OsInfo.wSuiteMask, ProductType);
Arch = SystemInfo.wProcessorArchitecture; if (Arch >= ARRAY_SZ(ProcessorArchName)) { Arch = ARRAY_SZ(ProcessorArchName)-1; }
IPRINT5(Info, "Processor: %s Level: 0x%04hx Revision: 0x%04hx Processor num/mask: %d/%08x\n", ProcessorArchName[Arch], SystemInfo.wProcessorLevel, SystemInfo.wProcessorRevision, SystemInfo.dwNumberOfProcessors, SystemInfo.dwActiveProcessorMask);
goto cleanup;
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_SETS) { WStatus = InfoPrintDbSets(Info, 0);
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_DS) { WStatus = InfoPrintDs(Info, 0);
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_MEMORY) { WStatus = InfoPrintMemory(Info, 0);
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_IDTABLE) { WStatus = InfoPrintTables(Info, L"ID TABLES", IDTablex, GuidIndexx, InfoIDTableWorker);
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_INLOG) { WStatus = InfoPrintTables(Info, L"INLOG TABLES", INLOGTablex, ILSequenceNumberIndexx, InfoInLogTableWorker);
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_OUTLOG) { WStatus = InfoPrintTables(Info, L"OUTLOG TABLES", OUTLOGTablex, OLSequenceNumberIndexx, InfoOutLogTableWorker);
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_CONFIGTABLE) { WStatus = InfoPrintTables(Info, L"CONFIG TABLE", ConfigTablex, ReplicaSetNameIndexx, InfoConfigTableWorker);
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_THREADS) { WStatus = InfoPrintThreads(Info, 0);
} else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_STAGE) { WStatus = InfoPrintStage(Info, 0);
} else { IPRINT1(Info, "NtFrs Doesn't understand TypeOfInfo %d\n", Info->TypeOfInfo); } cleanup:; } except (EXCEPTION_EXECUTE_HANDLER) { GET_EXCEPTION_CODE(WStatus); } //
// Clean up any handles, events, memory, ...
//
try { } except (EXCEPTION_EXECUTE_HANDLER) { GET_EXCEPTION_CODE(WStatus); } return WStatus; }
|