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.

2918 lines
78 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. info.c
  5. Abstract:
  6. Support the RPC interface that provides internal info to the caller.
  7. Author:
  8. Billy J Fuller 27-Mar-1998
  9. Environment
  10. User mode, winnt32
  11. --*/
  12. #include <ntreppch.h>
  13. #pragma hdrstop
  14. #undef DEBSUB
  15. #define DEBSUB "Info:"
  16. #include <frs.h>
  17. #include <ntdsapi.h>
  18. #include <ntdsapip.h> // ms internal flags for DsCrackNames()
  19. #include <ntfrsapi.h>
  20. #include <info.h>
  21. #include <tablefcn.h>
  22. #include <lmaccess.h>
  23. #include <lmapibuf.h>
  24. #ifdef SECURITY_WIN32
  25. #include <security.h>
  26. #else
  27. #define SECURITY_WIN32
  28. #include <security.h>
  29. #undef SECURITY_WIN32
  30. #endif
  31. extern PCHAR LatestChanges[];
  32. extern PCHAR CoLocationNames[];
  33. //
  34. // Useful macros
  35. //
  36. #define IPRINTGNAME(_I_, _G_, _F_, _GUID_, _P_) \
  37. { \
  38. if (_G_) { \
  39. GuidToStr(_G_->Guid, _GUID_); \
  40. IPRINT3(_I_, _F_, _P_, _G_->Name, _GUID_); \
  41. } \
  42. }
  43. #define INFO_DN_LEN (80)
  44. extern OSVERSIONINFOEX OsInfo;
  45. extern SYSTEM_INFO SystemInfo;
  46. extern PCHAR ProcessorArchName[10];
  47. //
  48. // DC name for LDAP binding
  49. //
  50. WCHAR InfoDcName[MAX_PATH + 1];
  51. //
  52. // Member Subscriber Links
  53. //
  54. typedef struct _INFO_DN INFO_DN, *PINFO_DN;
  55. struct _INFO_DN {
  56. PINFO_DN Next;
  57. PWCHAR Dn;
  58. PWCHAR SetType;
  59. };
  60. VOID
  61. DbsDisplayRecordIPrint(
  62. IN PTABLE_CTX TableCtx,
  63. IN PINFO_TABLE InfoTable,
  64. IN BOOL Read,
  65. IN PULONG RecordFieldx,
  66. IN ULONG FieldCount
  67. );
  68. //
  69. // From frs\ds.c
  70. //
  71. PVOID *
  72. FrsDsFindValues(
  73. IN PLDAP ldap,
  74. IN PLDAPMessage Entry,
  75. IN PWCHAR DesiredAttr,
  76. IN BOOL DoBerVals
  77. );
  78. PWCHAR
  79. FrsDsExtendDn(
  80. IN PWCHAR Dn,
  81. IN PWCHAR Cn
  82. );
  83. PWCHAR
  84. FrsDsExtendDnOu(
  85. IN PWCHAR Dn,
  86. IN PWCHAR Ou
  87. );
  88. PWCHAR
  89. FrsDsFindValue(
  90. IN PLDAP ldap,
  91. IN PLDAPMessage Entry,
  92. IN PWCHAR DesiredAttr
  93. );
  94. GUID *
  95. FrsDsFindGuid(
  96. IN PLDAP Ldap,
  97. IN PLDAPMessage LdapEntry
  98. );
  99. PWCHAR
  100. FrsDsMakeRdn(
  101. IN PWCHAR DN
  102. );
  103. PWCHAR
  104. FrsDsConvertToSettingsDn(
  105. IN PWCHAR Dn
  106. );
  107. PSCHEDULE
  108. FrsDsFindSchedule(
  109. IN PLDAP Ldap,
  110. IN PLDAPMessage LdapEntry,
  111. OUT PULONG Len
  112. );
  113. VOID
  114. FrsPrintRpcStats(
  115. IN ULONG Severity,
  116. IN PNTFRSAPI_INFO Info, OPTIONAL
  117. IN DWORD Tabs
  118. );
  119. VOID
  120. FrsPrintThreadStats(
  121. IN ULONG Severity,
  122. IN PNTFRSAPI_INFO Info, OPTIONAL
  123. IN DWORD Tabs
  124. );
  125. VOID
  126. InfoPrint(
  127. IN PNTFRSAPI_INFO Info,
  128. IN PCHAR Format,
  129. IN ... )
  130. /*++
  131. Routine Description:
  132. Format and print a line of information output into the info buffer.
  133. Arguments:
  134. Info - Info buffer
  135. Format - printf format
  136. Return Value:
  137. None.
  138. --*/
  139. {
  140. PCHAR Line;
  141. ULONG LineLen;
  142. LONG LineSize;
  143. //
  144. // varargs stuff
  145. //
  146. va_list argptr;
  147. va_start(argptr, Format);
  148. //
  149. // Print the line into the info buffer
  150. //
  151. try {
  152. if (!FlagOn(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) {
  153. Line = ((PCHAR)Info) + Info->OffsetToFree;
  154. LineSize = (Info->SizeInChars - (ULONG)(Line - (PCHAR)Info)) - 1;
  155. if (LineSize <= 0 ||
  156. _vsnprintf(Line, LineSize, Format, argptr) < 0) {
  157. SetFlag(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL);
  158. } else {
  159. LineLen = strlen(Line) + 1;
  160. if (Info->CharsToSkip) {
  161. if (LineLen > Info->CharsToSkip) {
  162. Info->CharsToSkip = 0;
  163. } else {
  164. Info->CharsToSkip -= LineLen;
  165. }
  166. } else {
  167. Info->OffsetToFree += LineLen;
  168. Info->TotalChars += LineLen;
  169. }
  170. }
  171. }
  172. } except(EXCEPTION_EXECUTE_HANDLER) {
  173. }
  174. va_end(argptr);
  175. }
  176. #define Tab L" "
  177. VOID
  178. InfoTabs(
  179. IN DWORD Tabs,
  180. IN PWCHAR TabW
  181. )
  182. /*++
  183. Routine Description:
  184. Create a string of tabs for prettyprint
  185. Arguments:
  186. Tabs - number of tabs
  187. TabW - preallocated string to receive tabs
  188. Return Value:
  189. Win32 Status
  190. --*/
  191. {
  192. DWORD i;
  193. //
  194. // Adjust indentation
  195. //
  196. Tabs = (Tabs >= MAX_TABS) ? MAX_TABS : Tabs;
  197. for (TabW[0] = L'\0', i = 0; i < Tabs; ++i) {
  198. wcscat(TabW, Tab);
  199. }
  200. }
  201. PWCHAR
  202. InfoDup(
  203. IN PWCHAR StrW,
  204. IN DWORD DesiredLen
  205. )
  206. /*++
  207. Routine Description:
  208. Duplicate up to DesiredLen chars of StrW. DesiredLen includes
  209. the terminating \0.
  210. Arguments:
  211. StrW - original string (untouched)
  212. DesiredLen - Maximum length to duplicate (including terminating \0)
  213. Return Value:
  214. Win32 Status
  215. --*/
  216. {
  217. DWORD Len;
  218. PWCHAR NewStrW;
  219. if (!StrW) {
  220. return NULL;
  221. }
  222. Len = wcslen(StrW) + 1;
  223. if (Len <= DesiredLen) {
  224. return FrsWcsDup(StrW);
  225. }
  226. NewStrW = FrsAlloc(DesiredLen * sizeof(WCHAR));
  227. wcsncpy(NewStrW, StrW, DesiredLen);
  228. NewStrW[DesiredLen - 1] = L'\0';
  229. if (DesiredLen > 4) {
  230. NewStrW[DesiredLen - 2] = L'.';
  231. NewStrW[DesiredLen - 3] = L'.';
  232. NewStrW[DesiredLen - 4] = L'.';
  233. }
  234. return NewStrW;
  235. }
  236. DWORD
  237. InfoPrintDbSets(
  238. IN PNTFRSAPI_INFO Info,
  239. IN DWORD Tabs
  240. )
  241. /*++
  242. Routine Description:
  243. Return internal info on replica sets (see private\net\inc\ntfrsapi.h).
  244. Arguments:
  245. Info - RPC output buffer
  246. Tabs
  247. Return Value:
  248. Win32 Status
  249. --*/
  250. {
  251. #undef DEBSUB
  252. #define DEBSUB "InfoPrintDbSets:"
  253. PVOID Key;
  254. PREPLICA Replica;
  255. CHAR Guid[GUID_CHAR_LEN + 1];
  256. WCHAR TabW[MAX_TAB_WCHARS + 1];
  257. extern PGEN_TABLE ReplicasByGuid;
  258. extern PGEN_TABLE DeletedReplicas;
  259. InfoTabs(Tabs, TabW);
  260. IPRINT1(Info, "%wsACTIVE REPLICA SETS\n", TabW);
  261. Key = NULL;
  262. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  263. if (REPLICA_IS_ACTIVE(Replica)) {
  264. FrsPrintTypeReplica(0, Info, Tabs, Replica, NULL, 0);
  265. } else {
  266. //
  267. // If the replica set is not active, one or more of the GNames
  268. // could have freed guid pointers (feeefeee, bug 319600) so
  269. // don't print the replica set in this case, just the name and state.
  270. //
  271. if (Replica->SetName) {
  272. IPRINT3(Info, "%ws %ws in state %s\n",
  273. TabW, Replica->SetName->Name, RSS_NAME(Replica->ServiceState));
  274. }
  275. }
  276. }
  277. IPRINT0(Info, "\nDELETED REPLICA SETS\n");
  278. Key = NULL;
  279. if (DeletedReplicas) {
  280. while (Replica = GTabNextDatum(DeletedReplicas, &Key)) {
  281. if (Replica->SetName) {
  282. IPRINT2(Info, "%ws %ws\n", TabW, Replica->SetName->Name);
  283. }
  284. }
  285. }
  286. return ERROR_SUCCESS;
  287. }
  288. BOOL
  289. InfoSearch(
  290. IN PNTFRSAPI_INFO Info,
  291. IN DWORD Tabs,
  292. IN PLDAP Ldap,
  293. IN PWCHAR Base,
  294. IN ULONG Scope,
  295. IN PWCHAR Filter,
  296. IN PWCHAR Attrs[],
  297. IN ULONG AttrsOnly,
  298. IN LDAPMessage **Res
  299. )
  300. /*++
  301. Routine Description:
  302. Perform ldap_search_s
  303. Arguments:
  304. Info - RPC output buffer
  305. Tabs - number of tabs
  306. Ldap - bound ldap handle
  307. .
  308. .
  309. .
  310. Return Value:
  311. Win32 Status
  312. --*/
  313. {
  314. #undef DEBSUB
  315. #define DEBSUB "InfoSearch:"
  316. DWORD LStatus;
  317. PWCHAR ShortName;
  318. WCHAR TabW[MAX_TAB_WCHARS + 1];
  319. InfoTabs(Tabs, TabW);
  320. LStatus = ldap_search_s(Ldap, Base, Scope, Filter, Attrs, AttrsOnly, Res);
  321. if (LStatus != LDAP_SUCCESS) {
  322. ShortName = InfoDup(Base, 20);
  323. IPRINT5(Info, "%wsWARN - ldap_search_s(%ws, %d, %ws); %ws\n",
  324. TabW, Base, Scope, ComputerName, ldap_err2string(LStatus));
  325. return FALSE;
  326. }
  327. return TRUE;
  328. }
  329. PCONFIG_NODE
  330. InfoAllocBasicNode(
  331. IN PNTFRSAPI_INFO Info,
  332. IN PWCHAR TabW,
  333. IN PWCHAR NodeType,
  334. IN PWCHAR ParentDn,
  335. IN PWCHAR Filter,
  336. IN BOOL *FirstError,
  337. IN PLDAP Ldap,
  338. IN PLDAPMessage LdapEntry
  339. )
  340. /*++
  341. Routine Description:
  342. Allocate a node and fill in the basic info (dn and name)
  343. Arguments:
  344. Info - text buffer
  345. TabW - Prettyprint
  346. NodeType - Prettyprint
  347. Ldap - openned, bound ldap
  348. LdapEntry - returned from ldap_first/next_entry()
  349. Return Value:
  350. NULL if basic info is not available.
  351. --*/
  352. {
  353. #undef DEBSUB
  354. #define DEBSUB "InfoAllocBasicNode:"
  355. PCONFIG_NODE Node = NULL;
  356. PWCHAR ShortName = NULL;
  357. CHAR Guid[GUID_CHAR_LEN + 1];
  358. //
  359. // Fetch values from the DS
  360. //
  361. Node = FrsAllocType(CONFIG_NODE_TYPE);
  362. Node->Dn = FrsDsFindValue(Ldap, LdapEntry, ATTR_DN);
  363. FRS_WCSLWR(Node->Dn);
  364. //
  365. // Name
  366. //
  367. Node->Name = FrsBuildGName(FrsDsFindGuid(Ldap, LdapEntry),
  368. FrsDsMakeRdn(Node->Dn));
  369. if (!Node->Dn || !Node->Name->Name || !Node->Name->Guid) {
  370. IPRINT5(Info, "\n%ws%ws: ERROR - The object returned by the DS"
  371. " lacks a dn (%08x), Rdn (%08x), or Guid(%08x)\n",
  372. TabW, NodeType, Node->Dn, Node->Name->Name, Node->Name->Guid);
  373. if (*FirstError) {
  374. *FirstError = FALSE;
  375. IPRINT5(Info, "%ws%ws: ERROR - Using ldp, bind to %ws and search the "
  376. "container %ws using the filter "
  377. "%ws for more information.\n",
  378. TabW, NodeType, &InfoDcName[2], ParentDn, Filter);
  379. }
  380. return FrsFreeType(Node);
  381. }
  382. IPRINT3(Info, "\n%ws%ws: %ws\n", TabW, NodeType, Node->Name->Name);
  383. ShortName = InfoDup(Node->Dn, INFO_DN_LEN);
  384. IPRINT2(Info, "%ws DN : %ws\n", TabW, ShortName);
  385. ShortName = FrsFree(ShortName);
  386. GuidToStr(Node->Name->Guid, Guid);
  387. IPRINT2(Info, "%ws Guid : %s\n", TabW, Guid);
  388. return Node;
  389. }
  390. VOID
  391. InfoPrintDsCxtions(
  392. IN PNTFRSAPI_INFO Info,
  393. IN DWORD Tabs,
  394. IN PLDAP Ldap,
  395. IN PWCHAR Base,
  396. IN BOOL IsSysVol
  397. )
  398. /*++
  399. Routine Description:
  400. Print the cxtions from the DS.
  401. Arguments:
  402. ldap - opened and bound ldap connection
  403. Base - Name of object or container in DS
  404. Return Value:
  405. None.
  406. --*/
  407. {
  408. #undef DEBSUB
  409. #define DEBSUB "InfoPrintDsCxtions:"
  410. PWCHAR Attrs[7];
  411. PLDAPMessage LdapEntry;
  412. PLDAPMessage LdapMsg = NULL;
  413. PCONFIG_NODE Node = NULL;
  414. PWCHAR ShortName = NULL;
  415. BOOL FirstError = TRUE;
  416. WCHAR TabW[MAX_TAB_WCHARS + 1];
  417. PWCHAR CxtionOptionsWStr = NULL;
  418. //
  419. // Adjust indentation
  420. //
  421. InfoTabs(Tabs, TabW);
  422. //
  423. // Search the DS for cxtions
  424. //
  425. Attrs[0] = ATTR_DN;
  426. Attrs[1] = ATTR_SCHEDULE;
  427. Attrs[2] = ATTR_FROM_SERVER;
  428. Attrs[3] = ATTR_OBJECT_GUID;
  429. Attrs[4] = ATTR_USN_CHANGED;
  430. Attrs[5] = ATTR_ENABLED_CXTION;
  431. Attrs[6] = ATTR_OPTIONS;
  432. Attrs[7] = NULL;
  433. if (!InfoSearch(Info, Tabs, Ldap, Base, LDAP_SCOPE_ONELEVEL,
  434. CATEGORY_CXTION, Attrs, 0, &LdapMsg)) {
  435. goto cleanup;
  436. }
  437. //
  438. // Scan the entries returned from ldap_search
  439. //
  440. for (LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  441. LdapEntry != NULL;
  442. LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
  443. //
  444. // Basic info (dn, rdn, and guid)
  445. //
  446. Node = InfoAllocBasicNode(Info, TabW, L"CXTION", Base,
  447. CATEGORY_CXTION, &FirstError, Ldap, LdapEntry);
  448. if (!Node) {
  449. continue;
  450. }
  451. //
  452. // Node's partner's name
  453. //
  454. Node->PartnerDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_FROM_SERVER);
  455. FRS_WCSLWR(Node->PartnerDn);
  456. ShortName = InfoDup(Node->PartnerDn, INFO_DN_LEN);
  457. IPRINT2(Info, "%ws Partner Dn : %ws\n", TabW, ShortName);
  458. ShortName = FrsFree(ShortName);
  459. Node->PartnerName = FrsBuildGName(NULL, FrsDsMakeRdn(Node->PartnerDn));
  460. IPRINT2(Info, "%ws Partner Rdn : %ws\n", TabW, Node->PartnerName->Name);
  461. //
  462. // Enabled
  463. //
  464. Node->EnabledCxtion = FrsDsFindValue(Ldap, LdapEntry, ATTR_ENABLED_CXTION);
  465. IPRINT2(Info, "%ws Enabled : %ws\n", TabW, Node->EnabledCxtion);
  466. //
  467. // Options
  468. //
  469. CxtionOptionsWStr = FrsDsFindValue(Ldap, LdapEntry, ATTR_OPTIONS);
  470. if (CxtionOptionsWStr != NULL) {
  471. Node->CxtionOptions = _wtoi(CxtionOptionsWStr);
  472. CxtionOptionsWStr = FrsFree(CxtionOptionsWStr);
  473. } else {
  474. Node->CxtionOptions = 0;
  475. }
  476. IPRINT2(Info, "%ws Options : 0x%08x\n", TabW, Node->CxtionOptions);
  477. //
  478. // Schedule, if any
  479. //
  480. Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength);
  481. if (Node->Schedule) {
  482. if (IsSysVol) {
  483. IPRINT1(Info, "%ws IGNORED Schedule\n", TabW);
  484. } else {
  485. IPRINT1(Info, "%ws Schedule\n", TabW);
  486. }
  487. FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0);
  488. }
  489. Node = FrsFreeType(Node);
  490. }
  491. cleanup:
  492. LDAP_FREE_MSG(LdapMsg);
  493. FrsFreeType(Node);
  494. FrsFree(ShortName);
  495. }
  496. VOID
  497. InfoCrack(
  498. IN PNTFRSAPI_INFO Info,
  499. IN DWORD Tabs,
  500. IN PWCHAR Dn,
  501. IN HANDLE Handle,
  502. IN PWCHAR DomainDnsName,
  503. IN DWORD DesiredFormat
  504. )
  505. /*++
  506. Routine Description:
  507. Find the NT4 account name for Dn. Dn should be the Dn
  508. of a computer object.
  509. Arguments:
  510. Dn - Of computer object
  511. Handle - From DsBind
  512. DomainDnsName - If !NULL, produce new local handle
  513. DesiredFormat - DS_NT4_ACCOUNT_NAME or DS_STRING_SID_NAME
  514. Return Value:
  515. NT4 Account Name or NULL
  516. --*/
  517. {
  518. #undef DEBSUB
  519. #define DEBSUB "InfoCrack:"
  520. DWORD WStatus;
  521. DS_NAME_RESULT *Cracked;
  522. WCHAR TabW[MAX_TAB_WCHARS + 1];
  523. PWCHAR ShortName = NULL;
  524. HANDLE LocalHandle = NULL;
  525. //
  526. // Adjust indentation
  527. //
  528. InfoTabs(Tabs, TabW);
  529. //
  530. // Computer's Dn not available
  531. //
  532. if (!Dn) {
  533. return;
  534. }
  535. //
  536. // Need something to go on!
  537. //
  538. if (!HANDLE_IS_VALID(Handle) && !DomainDnsName) {
  539. return;
  540. }
  541. //
  542. // Bind to Ds
  543. //
  544. if (DomainDnsName) {
  545. WStatus = DsBind(NULL, DomainDnsName, &LocalHandle);
  546. if (!WIN_SUCCESS(WStatus)) {
  547. IPRINT4(Info, "%ws ERROR - DsBind(%ws, %08x); WStatus %s\n",
  548. TabW, DomainDnsName, DesiredFormat, ErrLabelW32(WStatus));
  549. return;
  550. }
  551. Handle = LocalHandle;
  552. }
  553. //
  554. // Crack the computer's distinguished name into its NT4 Account Name
  555. //
  556. WStatus = DsCrackNames(Handle, // in hDS,
  557. DS_NAME_NO_FLAGS, // in flags,
  558. DS_FQDN_1779_NAME, // in formatOffered,
  559. DesiredFormat, // in formatDesired,
  560. 1, // in cNames,
  561. &Dn, // in *rpNames,
  562. &Cracked); // out *ppResult
  563. if (!WIN_SUCCESS(WStatus)) {
  564. ShortName = InfoDup(Dn, INFO_DN_LEN);
  565. IPRINT4(Info, "%ws ERROR - DsCrackNames(%ws, %08x); WStatus %s\n",
  566. TabW, ShortName, DesiredFormat, ErrLabelW32(WStatus));
  567. ShortName = FrsFree(ShortName);
  568. //
  569. // What else can we do?
  570. //
  571. if (HANDLE_IS_VALID(LocalHandle)) {
  572. DsUnBind(&LocalHandle);
  573. }
  574. return;
  575. }
  576. //
  577. // Might have it
  578. //
  579. if (Cracked && Cracked->cItems && Cracked->rItems) {
  580. //
  581. // Got it!
  582. //
  583. if (Cracked->rItems->status == DS_NAME_NO_ERROR) {
  584. IPRINT2(Info, "%ws Cracked Domain : %ws\n",
  585. TabW, Cracked->rItems->pDomain);
  586. IPRINT3(Info, "%ws Cracked Name : %08x %ws\n",
  587. TabW, DesiredFormat, Cracked->rItems->pName);
  588. //
  589. // Only got the domain; rebind and try again
  590. //
  591. } else if (Cracked->rItems->status == DS_NAME_ERROR_DOMAIN_ONLY) {
  592. InfoCrack(Info, Tabs, Dn, NULL, Cracked->rItems->pDomain, DesiredFormat);
  593. } else {
  594. ShortName = InfoDup(Dn, INFO_DN_LEN);
  595. IPRINT4(Info, "%ws ERROR - DsCrackNames(%ws, %08x); internal status %d\n",
  596. TabW, ShortName, DesiredFormat, Cracked->rItems->status);
  597. ShortName = FrsFree(ShortName);
  598. }
  599. DsFreeNameResult(Cracked);
  600. } else {
  601. ShortName = InfoDup(Dn, INFO_DN_LEN);
  602. IPRINT3(Info, "%ws ERROR - DsCrackNames(%ws, %08x); no status\n",
  603. TabW, ShortName, DesiredFormat);
  604. ShortName = FrsFree(ShortName);
  605. }
  606. if (HANDLE_IS_VALID(LocalHandle)) {
  607. DsUnBind(&LocalHandle);
  608. }
  609. }
  610. VOID
  611. InfoCrackDns(
  612. IN PNTFRSAPI_INFO Info,
  613. IN DWORD Tabs,
  614. IN PLDAP Ldap,
  615. IN PWCHAR Base
  616. )
  617. /*++
  618. Routine Description:
  619. Find the DNS name for Base. Base should be the Dn
  620. of a computer object.
  621. Arguments:
  622. Info
  623. Tabs
  624. Ldap
  625. Base
  626. Return Value:
  627. Prints a message into Info.
  628. --*/
  629. {
  630. #undef DEBSUB
  631. #define DEBSUB "InfoCrackDns:"
  632. PWCHAR Attrs[2];
  633. WCHAR TabW[MAX_TAB_WCHARS + 1];
  634. PLDAPMessage LdapEntry;
  635. PLDAPMessage LdapMsg = NULL;
  636. PWCHAR DnsName = NULL;
  637. //
  638. // Adjust indentation
  639. //
  640. InfoTabs(Tabs, TabW);
  641. //
  642. // Computer's Dn not available
  643. //
  644. if (!Base) {
  645. return;
  646. }
  647. //
  648. // Search the DS for the DNS attribute of Base
  649. //
  650. Attrs[0] = ATTR_DNS_HOST_NAME;
  651. Attrs[1] = NULL;
  652. if (!InfoSearch(Info, Tabs, Ldap, Base, LDAP_SCOPE_BASE,
  653. CATEGORY_ANY, Attrs, 0, &LdapMsg)) {
  654. goto cleanup;
  655. }
  656. LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  657. if (!LdapEntry) {
  658. IPRINT2(Info, "%ws ERROR - No LdapEntry for Dns name on %ws\n", TabW, Base);
  659. goto cleanup;
  660. }
  661. DnsName = FrsDsFindValue(Ldap, LdapEntry, ATTR_DNS_HOST_NAME);
  662. if (!DnsName) {
  663. IPRINT2(Info, "%ws ERROR - No DNS name on %ws\n", TabW, Base);
  664. goto cleanup;
  665. }
  666. //
  667. // Got it!
  668. //
  669. IPRINT2(Info, "%ws Computer's DNS : %ws\n", TabW, DnsName);
  670. cleanup:
  671. LDAP_FREE_MSG(LdapMsg);
  672. FrsFree(DnsName);
  673. }
  674. VOID
  675. InfoPrintMembers(
  676. IN PNTFRSAPI_INFO Info,
  677. IN DWORD Tabs,
  678. IN PLDAP Ldap,
  679. IN BOOL IsSysVol,
  680. IN PWCHAR Base,
  681. IN HANDLE DsHandle
  682. )
  683. /*++
  684. Routine Description:
  685. Print the members
  686. Arguments:
  687. ldap - opened and bound ldap connection
  688. Base - Name of object or container in DS
  689. Return Value:
  690. None.
  691. --*/
  692. {
  693. #undef DEBSUB
  694. #define DEBSUB "InfoPrintMembers:"
  695. PWCHAR Attrs[7];
  696. PLDAPMessage LdapEntry;
  697. PLDAPMessage LdapMsg = NULL;
  698. PCONFIG_NODE Node = NULL;
  699. PWCHAR ShortName = NULL;
  700. BOOL FirstError = TRUE;
  701. WCHAR TabW[MAX_TAB_WCHARS + 1];
  702. //
  703. // Adjust indentation
  704. //
  705. InfoTabs(Tabs, TabW);
  706. //
  707. // Search the DS for members
  708. //
  709. Attrs[0] = ATTR_OBJECT_GUID;
  710. Attrs[1] = ATTR_DN;
  711. Attrs[2] = ATTR_SCHEDULE;
  712. Attrs[3] = ATTR_USN_CHANGED;
  713. Attrs[4] = ATTR_SERVER_REF;
  714. Attrs[5] = ATTR_COMPUTER_REF;
  715. Attrs[6] = NULL;
  716. if (!InfoSearch(Info, Tabs, Ldap, Base, LDAP_SCOPE_ONELEVEL,
  717. CATEGORY_MEMBER, Attrs, 0, &LdapMsg)) {
  718. goto cleanup;
  719. }
  720. //
  721. // Scan the entries returned from ldap_search
  722. //
  723. for (LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  724. LdapEntry != NULL;
  725. LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
  726. //
  727. // Basic info (dn, rdn, and guid)
  728. //
  729. Node = InfoAllocBasicNode(Info, TabW, L"MEMBER", Base,
  730. CATEGORY_MEMBER, &FirstError, Ldap, LdapEntry);
  731. if (!Node) {
  732. continue;
  733. }
  734. //
  735. // NTDS Settings (DSA) Reference
  736. //
  737. Node->SettingsDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_SERVER_REF);
  738. ShortName = InfoDup(Node->SettingsDn, INFO_DN_LEN);
  739. IPRINT2(Info, "%ws Server Ref : %ws\n", TabW, ShortName);
  740. ShortName = FrsFree(ShortName);
  741. //
  742. // Computer Reference
  743. //
  744. Node->ComputerDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_COMPUTER_REF);
  745. FRS_WCSLWR(Node->ComputerDn);
  746. ShortName = InfoDup(Node->ComputerDn, INFO_DN_LEN);
  747. IPRINT2(Info, "%ws Computer Ref : %ws\n", TabW, ShortName);
  748. ShortName = FrsFree(ShortName);
  749. InfoCrack(Info, Tabs, Node->ComputerDn, DsHandle, NULL, DS_NT4_ACCOUNT_NAME);
  750. InfoCrack(Info, Tabs, Node->ComputerDn, DsHandle, NULL, DS_STRING_SID_NAME);
  751. InfoCrackDns(Info, Tabs, Ldap, Node->ComputerDn);
  752. //
  753. // Schedule, if any
  754. //
  755. Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength);
  756. if (Node->Schedule) {
  757. IPRINT1(Info, "%ws Schedule\n", TabW);
  758. FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0);
  759. }
  760. //
  761. // Get the inbound cxtions
  762. //
  763. InfoPrintDsCxtions(Info, Tabs + 1, Ldap, Node->Dn, FALSE);
  764. if (IsSysVol) {
  765. if (Node->SettingsDn) {
  766. InfoPrintDsCxtions(Info, Tabs + 1, Ldap, Node->SettingsDn, TRUE);
  767. } else {
  768. IPRINT2(Info, "%ws WARN - %ws lacks a settings reference\n",
  769. TabW, Node->Name->Name);
  770. }
  771. }
  772. Node = FrsFreeType(Node);
  773. }
  774. cleanup:
  775. LDAP_FREE_MSG(LdapMsg);
  776. FrsFreeType(Node);
  777. FrsFree(ShortName);
  778. }
  779. VOID
  780. InfoPrintDsSets(
  781. IN PNTFRSAPI_INFO Info,
  782. IN DWORD Tabs,
  783. IN PLDAP Ldap,
  784. IN PWCHAR SetDnAddr,
  785. IN HANDLE DsHandle,
  786. IN OUT PINFO_DN *InfoSets
  787. )
  788. /*++
  789. Routine Description:
  790. Print replica sets from the ds
  791. Arguments:
  792. ldap - opened and bound ldap connection
  793. Base - Name of object or container in DS
  794. Return Value:
  795. None
  796. --*/
  797. {
  798. #undef DEBSUB
  799. #define DEBSUB "InfoPrintDsSets:"
  800. PWCHAR Attrs[9];
  801. DWORD i;
  802. PINFO_DN InfoSet;
  803. PLDAPMessage LdapEntry;
  804. PLDAPMessage LdapMsg = NULL;
  805. PCONFIG_NODE Node = NULL;
  806. PWCHAR ShortName = NULL;
  807. BOOL FirstError = TRUE;
  808. WCHAR TabW[MAX_TAB_WCHARS + 1];
  809. //
  810. // Adjust indentation
  811. //
  812. InfoTabs(Tabs, TabW);
  813. //
  814. // Have we processed this settings before?
  815. //
  816. for (InfoSet = *InfoSets; InfoSet; InfoSet = InfoSet->Next) {
  817. if (WSTR_EQ(InfoSet->Dn, SetDnAddr)) {
  818. IPRINT2(Info, "%ws %ws processed previously\n", TabW, SetDnAddr);
  819. break;
  820. }
  821. }
  822. //
  823. // Yep; get the sets
  824. //
  825. if (InfoSet) {
  826. //
  827. // Recurse to the next level in the DS hierarchy
  828. //
  829. InfoPrintMembers(Info,
  830. Tabs + 1,
  831. Ldap,
  832. FRS_RSTYPE_IS_SYSVOLW(InfoSet->SetType),
  833. InfoSet->Dn,
  834. DsHandle);
  835. goto cleanup;
  836. }
  837. //
  838. // Search the DS beginning at Base for sets
  839. //
  840. Attrs[0] = ATTR_OBJECT_GUID;
  841. Attrs[1] = ATTR_DN;
  842. Attrs[2] = ATTR_SCHEDULE;
  843. Attrs[3] = ATTR_USN_CHANGED;
  844. Attrs[4] = ATTR_SET_TYPE;
  845. Attrs[5] = ATTR_PRIMARY_MEMBER;
  846. Attrs[6] = ATTR_FILE_FILTER;
  847. Attrs[7] = ATTR_DIRECTORY_FILTER;
  848. Attrs[8] = NULL;
  849. if (!InfoSearch(Info, Tabs, Ldap, SetDnAddr, LDAP_SCOPE_BASE,
  850. CATEGORY_REPLICA_SET, Attrs, 0, &LdapMsg)) {
  851. goto cleanup;
  852. }
  853. //
  854. // Scan the entries returned from ldap_search
  855. //
  856. for (LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  857. LdapEntry != NULL;
  858. LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
  859. //
  860. // Basic info (dn, rdn, and guid)
  861. //
  862. Node = InfoAllocBasicNode(Info, TabW, L"SET", SetDnAddr,
  863. CATEGORY_REPLICA_SET, &FirstError, Ldap, LdapEntry);
  864. if (!Node) {
  865. continue;
  866. }
  867. //
  868. // Replica set type
  869. //
  870. Node->SetType = FrsDsFindValue(Ldap, LdapEntry, ATTR_SET_TYPE);
  871. IPRINT2(Info, "%ws Type : %ws\n", TabW, Node->SetType);
  872. //
  873. // Primary member
  874. //
  875. Node->MemberDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_PRIMARY_MEMBER);
  876. ShortName = InfoDup(Node->MemberDn, INFO_DN_LEN);
  877. IPRINT2(Info, "%ws Primary Member: %ws\n", TabW, ShortName);
  878. ShortName = FrsFree(ShortName);
  879. //
  880. // File filter
  881. //
  882. Node->FileFilterList = FrsDsFindValue(Ldap, LdapEntry, ATTR_FILE_FILTER);
  883. IPRINT2(Info, "%ws File Filter : %ws\n", TabW, Node->FileFilterList);
  884. //
  885. // Directory filter
  886. //
  887. Node->DirFilterList = FrsDsFindValue(Ldap, LdapEntry, ATTR_DIRECTORY_FILTER);
  888. IPRINT2(Info, "%ws Dir Filter : %ws\n", TabW, Node->DirFilterList);
  889. //
  890. // Schedule, if any
  891. //
  892. Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength);
  893. if (Node->Schedule) {
  894. IPRINT1(Info, "%ws Schedule\n", TabW);
  895. FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0);
  896. }
  897. InfoSet = FrsAlloc(sizeof(INFO_DN));
  898. InfoSet->Dn = FrsWcsDup(Node->Dn);
  899. InfoSet->SetType = FrsWcsDup(Node->SetType);
  900. InfoSet->Next = *InfoSets;
  901. *InfoSets = InfoSet;
  902. //
  903. // Recurse to the next level in the DS hierarchy
  904. //
  905. InfoPrintMembers(Info,
  906. Tabs + 1,
  907. Ldap,
  908. FRS_RSTYPE_IS_SYSVOLW(Node->SetType),
  909. Node->Dn,
  910. DsHandle);
  911. Node = FrsFreeType(Node);
  912. }
  913. cleanup:
  914. LDAP_FREE_MSG(LdapMsg);
  915. FrsFreeType(Node);
  916. FrsFree(ShortName);
  917. }
  918. VOID
  919. InfoPrintSettings(
  920. IN PNTFRSAPI_INFO Info,
  921. IN DWORD Tabs,
  922. IN PLDAP Ldap,
  923. IN PWCHAR MemberDn,
  924. IN HANDLE DsHandle,
  925. IN OUT PINFO_DN *InfoSettings,
  926. IN OUT PINFO_DN *InfoSets
  927. )
  928. /*++
  929. Routine Description:
  930. Scan the DS tree for NTFRS-Settings
  931. Arguments:
  932. ldap - opened and bound ldap connection
  933. Base - Name of object or container in DS
  934. Return Value:
  935. WIN32 Status
  936. --*/
  937. {
  938. #undef DEBSUB
  939. #define DEBSUB "InfoPrintSettings:"
  940. PWCHAR Attrs[5];
  941. PLDAPMessage LdapEntry;
  942. PWCHAR MemberDnAddr;
  943. PWCHAR SetDnAddr;
  944. PWCHAR SettingsDnAddr;
  945. PINFO_DN InfoSetting;
  946. PLDAPMessage LdapMsg = NULL;
  947. PCONFIG_NODE Node = NULL;
  948. PWCHAR ShortName = NULL;
  949. BOOL FirstError = TRUE;
  950. WCHAR TabW[MAX_TAB_WCHARS + 1];
  951. //
  952. // Adjust indentation
  953. //
  954. InfoTabs(Tabs, TabW);
  955. //
  956. // Find the member component
  957. //
  958. MemberDnAddr = wcsstr(MemberDn, L"cn=");
  959. if (!MemberDnAddr) {
  960. IPRINT2(Info, "%ws ERROR - No MemberDnAddr in %ws\n", TabW, MemberDn);
  961. goto cleanup;
  962. }
  963. //
  964. // Find the set component
  965. //
  966. SetDnAddr = wcsstr(MemberDnAddr + 3, L"cn=");
  967. if (!SetDnAddr) {
  968. IPRINT2(Info, "%ws ERROR - No SetDnAddr in %ws\n", TabW, MemberDn);
  969. goto cleanup;
  970. }
  971. //
  972. // Find the settings component
  973. //
  974. SettingsDnAddr = wcsstr(SetDnAddr + 3, L"cn=");
  975. if (!SettingsDnAddr) {
  976. IPRINT2(Info, "%ws ERROR - No SettingsDnAddr in %ws\n", TabW, MemberDn);
  977. goto cleanup;
  978. }
  979. //
  980. // Have we processed this settings before?
  981. //
  982. for (InfoSetting = *InfoSettings; InfoSetting; InfoSetting = InfoSetting->Next) {
  983. if (WSTR_EQ(InfoSetting->Dn, SettingsDnAddr)) {
  984. IPRINT2(Info, "%ws %ws processed previously\n", TabW, SettingsDnAddr);
  985. break;
  986. }
  987. }
  988. //
  989. // Yep; get the sets
  990. //
  991. if (InfoSetting) {
  992. InfoPrintDsSets(Info, Tabs + 1, Ldap, SetDnAddr, DsHandle, InfoSets);
  993. goto cleanup;
  994. }
  995. //
  996. // Search the DS beginning at Base for settings
  997. //
  998. Attrs[0] = ATTR_OBJECT_GUID;
  999. Attrs[1] = ATTR_DN;
  1000. Attrs[2] = ATTR_SCHEDULE;
  1001. Attrs[3] = ATTR_USN_CHANGED;
  1002. Attrs[4] = NULL;
  1003. if (!InfoSearch(Info, Tabs, Ldap, SettingsDnAddr, LDAP_SCOPE_BASE,
  1004. CATEGORY_NTFRS_SETTINGS, Attrs, 0, &LdapMsg)) {
  1005. goto cleanup;
  1006. }
  1007. //
  1008. // Scan the entries returned from ldap_search
  1009. //
  1010. for (LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  1011. LdapEntry != NULL;
  1012. LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
  1013. //
  1014. // Basic info (dn, rdn, and guid)
  1015. //
  1016. Node = InfoAllocBasicNode(Info, TabW, L"SETTINGS", SettingsDnAddr,
  1017. CATEGORY_NTFRS_SETTINGS, &FirstError, Ldap, LdapEntry);
  1018. if (!Node) {
  1019. continue;
  1020. }
  1021. //
  1022. // Schedule, if any
  1023. //
  1024. Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength);
  1025. if (Node->Schedule) {
  1026. IPRINT1(Info, "%ws Schedule\n", TabW);
  1027. FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0);
  1028. }
  1029. InfoSetting = FrsAlloc(sizeof(INFO_DN));
  1030. InfoSetting->Dn = FrsWcsDup(Node->Dn);
  1031. InfoSetting->Next = *InfoSettings;
  1032. *InfoSettings = InfoSetting;
  1033. //
  1034. // Recurse to the next level in the DS hierarchy
  1035. //
  1036. InfoPrintDsSets(Info, Tabs + 1, Ldap, SetDnAddr, DsHandle, InfoSets);
  1037. Node = FrsFreeType(Node);
  1038. }
  1039. cleanup:
  1040. LDAP_FREE_MSG(LdapMsg);
  1041. FrsFreeType(Node);
  1042. FrsFree(ShortName);
  1043. }
  1044. VOID
  1045. InfoPrintSubscribers(
  1046. IN PNTFRSAPI_INFO Info,
  1047. IN DWORD Tabs,
  1048. IN PLDAP Ldap,
  1049. IN PWCHAR SubscriptionDn,
  1050. IN PINFO_DN *InfoSubs
  1051. )
  1052. /*++
  1053. Routine Description:
  1054. Print subscribers
  1055. Arguments:
  1056. Ldap - opened and bound ldap connection
  1057. SubscriptionDn - distininguished name of subscriptions object
  1058. Return Value:
  1059. WIN32 Status
  1060. --*/
  1061. {
  1062. #undef DEBSUB
  1063. #define DEBSUB "InfoPrintSubscribers:"
  1064. PWCHAR Attrs[8];
  1065. PLDAPMessage LdapEntry;
  1066. PINFO_DN InfoSub;
  1067. PLDAPMessage LdapMsg = NULL;
  1068. PCONFIG_NODE Node = NULL;
  1069. PWCHAR ShortName = NULL;
  1070. BOOL FirstError = TRUE;
  1071. WCHAR TabW[MAX_TAB_WCHARS + 1];
  1072. //
  1073. // Adjust indentation
  1074. //
  1075. InfoTabs(Tabs, TabW);
  1076. //
  1077. // Search the DS beginning at Base for the entries of class "Filter"
  1078. //
  1079. Attrs[0] = ATTR_OBJECT_GUID;
  1080. Attrs[1] = ATTR_DN;
  1081. Attrs[2] = ATTR_SCHEDULE;
  1082. Attrs[3] = ATTR_USN_CHANGED;
  1083. Attrs[4] = ATTR_REPLICA_ROOT;
  1084. Attrs[5] = ATTR_REPLICA_STAGE;
  1085. Attrs[6] = ATTR_MEMBER_REF;
  1086. Attrs[7] = NULL;
  1087. if (!InfoSearch(Info, Tabs, Ldap, SubscriptionDn, LDAP_SCOPE_ONELEVEL,
  1088. CATEGORY_SUBSCRIBER, Attrs, 0, &LdapMsg)) {
  1089. goto cleanup;
  1090. }
  1091. //
  1092. // Scan the entries returned from ldap_search
  1093. //
  1094. for (LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  1095. LdapEntry != NULL;
  1096. LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
  1097. //
  1098. // Basic info (dn, rdn, and guid)
  1099. //
  1100. Node = InfoAllocBasicNode(Info, TabW, L"SUBSCRIBER", SubscriptionDn,
  1101. CATEGORY_SUBSCRIBER, &FirstError, Ldap, LdapEntry);
  1102. if (!Node) {
  1103. continue;
  1104. }
  1105. //
  1106. // Member reference
  1107. //
  1108. Node->MemberDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_MEMBER_REF);
  1109. ShortName = InfoDup(Node->MemberDn, INFO_DN_LEN);
  1110. IPRINT2(Info, "%ws Member Ref: %ws\n", TabW, ShortName);
  1111. ShortName = FrsFree(ShortName);
  1112. if (Node->MemberDn) {
  1113. InfoSub = FrsAlloc(sizeof(INFO_DN ));
  1114. InfoSub->Dn = FrsWcsDup(Node->MemberDn);
  1115. InfoSub->Next = *InfoSubs;
  1116. *InfoSubs = InfoSub;
  1117. }
  1118. //
  1119. // Root pathname
  1120. //
  1121. Node->Root = FrsDsFindValue(Ldap, LdapEntry, ATTR_REPLICA_ROOT);
  1122. FRS_WCSLWR(Node->Root);
  1123. IPRINT2(Info, "%ws Root : %ws\n", TabW, Node->Root);
  1124. //
  1125. // Staging pathname
  1126. //
  1127. Node->Stage = FrsDsFindValue(Ldap, LdapEntry, ATTR_REPLICA_STAGE);
  1128. FRS_WCSLWR(Node->Stage);
  1129. IPRINT2(Info, "%ws Stage : %ws\n", TabW, Node->Stage);
  1130. //
  1131. // Schedule, if any
  1132. //
  1133. Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength);
  1134. if (Node->Schedule) {
  1135. IPRINT1(Info, "%ws Schedule\n", TabW);
  1136. FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0);
  1137. }
  1138. Node = FrsFreeType(Node);
  1139. }
  1140. cleanup:
  1141. LDAP_FREE_MSG(LdapMsg);
  1142. FrsFreeType(Node);
  1143. FrsFree(ShortName);
  1144. }
  1145. VOID
  1146. InfoPrintSubscriptions(
  1147. IN PNTFRSAPI_INFO Info,
  1148. IN DWORD Tabs,
  1149. IN PLDAP Ldap,
  1150. IN PWCHAR ComputerDn,
  1151. IN PINFO_DN *InfoSubs
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. Recursively scan the DS tree beginning at computer
  1156. Arguments:
  1157. Info
  1158. Tabs
  1159. Ldap
  1160. ComputerDn
  1161. Return Value:
  1162. WIN32 Status
  1163. --*/
  1164. {
  1165. #undef DEBSUB
  1166. #define DEBSUB "InfoPrintSubscriptions:"
  1167. PWCHAR Attrs[6];
  1168. PLDAPMessage LdapEntry;
  1169. PLDAPMessage LdapMsg = NULL;
  1170. PCONFIG_NODE Node = NULL;
  1171. PWCHAR ShortName = NULL;
  1172. BOOL FirstError = TRUE;
  1173. WCHAR TabW[MAX_TAB_WCHARS + 1];
  1174. //
  1175. // Adjust indentation
  1176. //
  1177. InfoTabs(Tabs, TabW);
  1178. //
  1179. // Search the DS beginning at Base for the entries of class "Filter"
  1180. //
  1181. Attrs[0] = ATTR_OBJECT_GUID;
  1182. Attrs[1] = ATTR_DN;
  1183. Attrs[2] = ATTR_SCHEDULE;
  1184. Attrs[3] = ATTR_USN_CHANGED;
  1185. Attrs[4] = ATTR_WORKING;
  1186. Attrs[5] = NULL;
  1187. if (!InfoSearch(Info, Tabs + 1, Ldap, ComputerDn, LDAP_SCOPE_SUBTREE,
  1188. CATEGORY_SUBSCRIPTIONS, Attrs, 0, &LdapMsg)) {
  1189. goto cleanup;
  1190. }
  1191. //
  1192. // Scan the entries returned from ldap_search
  1193. //
  1194. for (LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  1195. LdapEntry != NULL;
  1196. LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
  1197. //
  1198. // Basic info (dn, rdn, and guid)
  1199. //
  1200. Node = InfoAllocBasicNode(Info, TabW, L"SUBSCRIPTION", ComputerDn,
  1201. CATEGORY_SUBSCRIPTIONS, &FirstError, Ldap, LdapEntry);
  1202. if (!Node) {
  1203. continue;
  1204. }
  1205. //
  1206. // Working Directory
  1207. //
  1208. Node->Working = FrsDsFindValue(Ldap, LdapEntry, ATTR_WORKING);
  1209. IPRINT2(Info, "%ws Working : %ws\n", TabW, Node->Working);
  1210. IPRINT2(Info, "%ws Actual Working: %ws\n", TabW, WorkingPath);
  1211. //
  1212. // Schedule, if any
  1213. //
  1214. Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength);
  1215. if (Node->Schedule) {
  1216. IPRINT1(Info, "%ws Schedule\n", TabW);
  1217. FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0);
  1218. }
  1219. //
  1220. // Recurse to the next level in the DS hierarchy
  1221. //
  1222. InfoPrintSubscribers(Info, Tabs + 1, Ldap, Node->Dn, InfoSubs);
  1223. Node = FrsFreeType(Node);
  1224. }
  1225. cleanup:
  1226. LDAP_FREE_MSG(LdapMsg);
  1227. FrsFreeType(Node);
  1228. FrsFree(ShortName);
  1229. }
  1230. BOOL
  1231. InfoPrintComputer(
  1232. IN PNTFRSAPI_INFO Info,
  1233. IN DWORD Tabs,
  1234. IN PLDAP Ldap,
  1235. IN PWCHAR FindDn,
  1236. IN PWCHAR ObjectCategory,
  1237. IN ULONG Scope,
  1238. OUT PINFO_DN *InfoSubs
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. Return internal info on DS computer objects.
  1243. Arguments:
  1244. Info - RPC output buffer
  1245. Tabs - number of tabs
  1246. Ldap - bound ldap handle
  1247. DefaultNcDn - DN of the DCs default naming context
  1248. FindDn - Base Dn for search
  1249. ObjectCategory - Object class (computer or user)
  1250. A user object serves the same purpose as the computer
  1251. object *sometimes* following a NT4 to NT5 upgrade.
  1252. Scope - Scope of search (currently BASE or SUBTREE)
  1253. Return Value:
  1254. Win32 Status
  1255. --*/
  1256. {
  1257. #undef DEBSUB
  1258. #define DEBSUB "InfoPrintComputer:"
  1259. DWORD i;
  1260. DWORD LStatus;
  1261. PLDAPMessage LdapEntry;
  1262. PWCHAR UserAccountControl;
  1263. DWORD NumVals;
  1264. PINFO_DN InfoSub;
  1265. BOOL FoundAComputer = FALSE;
  1266. PWCHAR ShortName = NULL;
  1267. PCONFIG_NODE Node = NULL;
  1268. PLDAPMessage LdapMsg = NULL;
  1269. PWCHAR *Values = NULL;
  1270. DWORD WStatus = ERROR_SUCCESS;
  1271. BOOL FirstError = TRUE;
  1272. WCHAR TabW[MAX_TAB_WCHARS + 1];
  1273. WCHAR Filter[MAX_PATH + 1];
  1274. WCHAR ComputerFqdn[MAX_PATH + 1];
  1275. DWORD ComputerFqdnLen;
  1276. PWCHAR Attrs[10];
  1277. //
  1278. // Initialize return value
  1279. //
  1280. *InfoSubs = NULL;
  1281. //
  1282. // Adjust indentation
  1283. //
  1284. InfoTabs(Tabs, TabW);
  1285. //
  1286. // Filter that locates our computer object
  1287. //
  1288. swprintf(Filter, L"(&%s(sAMAccountName=%s$))", ObjectCategory, ComputerName);
  1289. //
  1290. // Search the DS beginning at Base for the entries of class "Filter"
  1291. //
  1292. Attrs[0] = ATTR_OBJECT_GUID;
  1293. Attrs[1] = ATTR_DN;
  1294. Attrs[2] = ATTR_SCHEDULE;
  1295. Attrs[3] = ATTR_COMPUTER_REF_BL;
  1296. Attrs[4] = ATTR_SERVER_REF;
  1297. Attrs[5] = ATTR_SERVER_REF_BL;
  1298. Attrs[6] = ATTR_USER_ACCOUNT_CONTROL;
  1299. Attrs[7] = ATTR_DNS_HOST_NAME;
  1300. Attrs[8] = NULL;
  1301. InfoSearch(Info,
  1302. Tabs + 1,
  1303. Ldap,
  1304. FindDn,
  1305. Scope,
  1306. Filter,
  1307. Attrs,
  1308. 0,
  1309. &LdapMsg);
  1310. if (!LdapMsg) {
  1311. goto CLEANUP;
  1312. }
  1313. //
  1314. // Scan the entries returned from ldap_search
  1315. //
  1316. for (LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  1317. LdapEntry != NULL && WIN_SUCCESS(WStatus);
  1318. LdapEntry = ldap_next_entry(Ldap, LdapEntry)) {
  1319. FoundAComputer = TRUE;
  1320. //
  1321. // Basic info (dn, rdn, and guid)
  1322. //
  1323. Node = InfoAllocBasicNode(Info,
  1324. TabW,
  1325. L"COMPUTER",
  1326. FindDn,
  1327. Filter,
  1328. &FirstError,
  1329. Ldap,
  1330. LdapEntry);
  1331. if (!Node) {
  1332. continue;
  1333. }
  1334. UserAccountControl = FrsDsFindValue(Ldap, LdapEntry, ATTR_USER_ACCOUNT_CONTROL);
  1335. if (UserAccountControl) {
  1336. IPRINT2(Info, "%ws UAC : 0x%08x\n",
  1337. TabW, wcstoul(UserAccountControl, NULL, 10));
  1338. UserAccountControl = FrsFree(UserAccountControl);
  1339. }
  1340. //
  1341. // Server reference
  1342. //
  1343. Node->SettingsDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_SERVER_REF_BL);
  1344. ShortName = InfoDup(Node->SettingsDn, INFO_DN_LEN);
  1345. IPRINT2(Info, "%ws Server BL : %ws\n", TabW, ShortName);
  1346. ShortName = FrsFree(ShortName);
  1347. if (!Node->SettingsDn) {
  1348. Node->SettingsDn = FrsDsFindValue(Ldap, LdapEntry, ATTR_SERVER_REF);
  1349. ShortName = InfoDup(Node->SettingsDn, INFO_DN_LEN);
  1350. IPRINT2(Info, "%ws Server Ref: %ws\n", TabW, ShortName);
  1351. ShortName = FrsFree(ShortName);
  1352. }
  1353. //
  1354. // Make sure it references the settings; not the server
  1355. //
  1356. Node->SettingsDn = FrsDsConvertToSettingsDn(Node->SettingsDn);
  1357. ShortName = InfoDup(Node->SettingsDn, INFO_DN_LEN);
  1358. IPRINT2(Info, "%ws Settings : %ws\n", TabW, ShortName);
  1359. ShortName = FrsFree(ShortName);
  1360. //
  1361. // DNS Host Name
  1362. //
  1363. Node->DnsName = FrsDsFindValue(Ldap, LdapEntry, ATTR_DNS_HOST_NAME);
  1364. IPRINT2(Info, "%ws DNS Name : %ws\n", TabW, Node->DnsName);
  1365. //
  1366. // Schedule, if any
  1367. //
  1368. Node->Schedule = FrsDsFindSchedule(Ldap, LdapEntry, &Node->ScheduleLength);
  1369. if (Node->Schedule) {
  1370. IPRINT1(Info, "%ws Schedule\n", TabW);
  1371. FrsPrintTypeSchedule(0, Info, Tabs + 1, Node->Schedule, NULL, 0);
  1372. }
  1373. InfoPrintSubscriptions(Info, Tabs + 1, Ldap, Node->Dn, InfoSubs);
  1374. //
  1375. // Subscriber Member Bls
  1376. //
  1377. if (!*InfoSubs) {
  1378. IPRINT2(Info, "%ws %ws IS NOT A MEMBER OF ANY SET!\n",
  1379. TabW, ComputerName);
  1380. } else {
  1381. IPRINT1(Info, "%ws Subscriber Member Back Links:\n", TabW);
  1382. for (InfoSub = *InfoSubs; InfoSub; InfoSub = InfoSub->Next) {
  1383. FRS_WCSLWR(InfoSub->Dn);
  1384. ShortName = InfoDup(InfoSub->Dn, INFO_DN_LEN);
  1385. IPRINT2(Info, "%ws %ws\n", TabW, ShortName);
  1386. ShortName = FrsFree(ShortName);
  1387. }
  1388. }
  1389. //
  1390. // Next computer
  1391. //
  1392. Node = FrsFreeType(Node);
  1393. }
  1394. CLEANUP:
  1395. LDAP_FREE_MSG(LdapMsg);
  1396. FrsFreeType(Node);
  1397. FrsFree(ShortName);
  1398. return FoundAComputer;
  1399. }
  1400. DWORD
  1401. InfoPrintDs(
  1402. IN PNTFRSAPI_INFO Info,
  1403. IN DWORD Tabs
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. Return internal info on DS (see private\net\inc\ntfrsapi.h).
  1408. Arguments:
  1409. Info - RPC output buffer
  1410. Tabs - number of tabs
  1411. Return Value:
  1412. Win32 Status
  1413. --*/
  1414. {
  1415. #undef DEBSUB
  1416. #define DEBSUB "InfoPrintDs:"
  1417. DWORD WStatus;
  1418. DWORD LStatus;
  1419. DWORD i;
  1420. PWCHAR DcAddr;
  1421. PWCHAR DcName;
  1422. PWCHAR DcDnsName;
  1423. DWORD NumVals;
  1424. PWCHAR Config;
  1425. PLDAPMessage LdapEntry;
  1426. BOOL PrintedComputers;
  1427. PINFO_DN InfoSub;
  1428. PINFO_DN InfoSetting;
  1429. PINFO_DN InfoSet;
  1430. PINFO_DN InfoSubs = NULL;
  1431. PINFO_DN InfoSettings = NULL;
  1432. PINFO_DN InfoSets = NULL;
  1433. PWCHAR ShortName = NULL;
  1434. PWCHAR SitesDn = NULL;
  1435. PWCHAR ServicesDn = NULL;
  1436. PWCHAR DefaultNcDn = NULL;
  1437. PWCHAR ComputersDn = NULL;
  1438. PWCHAR DomainControllersDn = NULL;
  1439. PLDAPMessage LdapMsg = NULL;
  1440. PWCHAR *Values = NULL;
  1441. PLDAP Ldap = NULL;
  1442. HANDLE DsHandle = INVALID_HANDLE_VALUE;
  1443. WCHAR ComputerFqdn[MAX_PATH + 1];
  1444. DWORD ComputerFqdnLen;
  1445. WCHAR TabW[MAX_TAB_WCHARS + 1];
  1446. CHAR Guid[GUID_CHAR_LEN + 1];
  1447. PWCHAR Attrs[3];
  1448. PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
  1449. struct l_timeval Timeout;
  1450. DWORD InfoFlags;
  1451. CHAR FlagBuffer[220];
  1452. ULONG ulOptions;
  1453. extern PWCHAR DsDomainControllerName;
  1454. extern FLAG_NAME_TABLE DsGetDcInfoFlagNameTable[];
  1455. //
  1456. // Client side ldap_connect timeout in seconds. Reg value "Ldap Bind Timeout In Seconds". Default is 30 seconds.
  1457. //
  1458. extern DWORD LdapBindTimeoutInSeconds;
  1459. //
  1460. // Adjust indentation
  1461. //
  1462. InfoTabs(Tabs, TabW);
  1463. IPRINT1(Info, "%wsNTFRS CONFIGURATION IN THE DS\n", TabW);
  1464. Ldap = NULL;
  1465. if (IsADc) {
  1466. DcAddr = NULL;
  1467. DcName = ComputerName;
  1468. DcDnsName = ComputerDnsName;
  1469. IPRINT1(Info, "%wsSUBSTITUTE DCINFO FOR DC\n", TabW);
  1470. IPRINT2(Info, "%ws FRS DomainControllerName: %ws\n", TabW, DsDomainControllerName);
  1471. IPRINT2(Info, "%ws Computer Name : %ws\n", TabW, DcName);
  1472. IPRINT2(Info, "%ws Computer DNS Name : %ws\n", TabW, DcDnsName);
  1473. } else {
  1474. //
  1475. // Domain Controller
  1476. //
  1477. WStatus = DsGetDcName(NULL,
  1478. NULL,
  1479. NULL,
  1480. NULL,
  1481. DS_DIRECTORY_SERVICE_REQUIRED |
  1482. DS_WRITABLE_REQUIRED |
  1483. DS_BACKGROUND_ONLY,
  1484. &DcInfo);
  1485. if (!WIN_SUCCESS(WStatus)) {
  1486. DcInfo = NULL;
  1487. IPRINT2(Info, "%wsWARN - DsGetDcName WStatus %s; Flushing cache...\n",
  1488. TabW, ErrLabelW32(WStatus));
  1489. WStatus = DsGetDcName(NULL,
  1490. NULL,
  1491. NULL,
  1492. NULL,
  1493. DS_DIRECTORY_SERVICE_REQUIRED |
  1494. DS_WRITABLE_REQUIRED |
  1495. DS_FORCE_REDISCOVERY,
  1496. &DcInfo);
  1497. }
  1498. //
  1499. // Report the error and retry for any DC
  1500. //
  1501. if (!WIN_SUCCESS(WStatus)) {
  1502. DcInfo = NULL;
  1503. IPRINT3(Info, "%wsERROR - DsGetDcName(%ws); WStatus %s\n",
  1504. TabW, ComputerName, ErrLabelW32(WStatus));
  1505. goto cleanup;
  1506. }
  1507. //
  1508. // Dump dcinfo
  1509. //
  1510. IPRINT1(Info, "%wsDCINFO\n", TabW);
  1511. IPRINT2(Info, "%ws LAST DomainControllerName: %ws\n", TabW, DsDomainControllerName);
  1512. IPRINT2(Info, "%ws DomainControllerName : %ws\n", TabW, DcInfo->DomainControllerName);
  1513. IPRINT2(Info, "%ws DomainControllerAddress : %ws\n", TabW, DcInfo->DomainControllerAddress);
  1514. IPRINT2(Info, "%ws DomainControllerType : %08x\n",TabW, DcInfo->DomainControllerAddressType);
  1515. IPRINT2(Info, "%ws DomainName : %ws\n", TabW, DcInfo->DomainName);
  1516. IPRINT2(Info, "%ws DnsForestName : %ws\n", TabW, DcInfo->DnsForestName);
  1517. IPRINT2(Info, "%ws DcSiteName : %ws\n", TabW, DcInfo->DcSiteName);
  1518. IPRINT2(Info, "%ws ClientSiteName : %ws\n", TabW, DcInfo->ClientSiteName);
  1519. InfoFlags = DcInfo->Flags;
  1520. FrsFlagsToStr(InfoFlags, DsGetDcInfoFlagNameTable, sizeof(FlagBuffer), FlagBuffer);
  1521. IPRINT3(Info, "%ws Flags : %08x [%s]\n",TabW, InfoFlags, FlagBuffer);
  1522. if (!DsDomainControllerName ||
  1523. !DcInfo->DomainControllerName ||
  1524. WSTR_NE(DsDomainControllerName, DcInfo->DomainControllerName)) {
  1525. IPRINT3(Info, "%wsWARN - Using DC %ws; not %ws\n",
  1526. TabW, DcInfo->DomainControllerName, DsDomainControllerName);
  1527. }
  1528. //
  1529. // Binding address
  1530. //
  1531. DcAddr = DcInfo->DomainControllerAddress;
  1532. DcDnsName = DcInfo->DomainControllerName;
  1533. }
  1534. wcsncpy(InfoDcName, DcDnsName, ARRAY_SZ(InfoDcName)-1);
  1535. //
  1536. // BIND to the DS
  1537. //
  1538. IPRINT1(Info, "\n%wsBINDING TO THE DS:\n", TabW);
  1539. //
  1540. // if ldap_open is called with a server name the api will call DsGetDcName
  1541. // passing the server name as the domainname parm...bad, because
  1542. // DsGetDcName will make a load of DNS queries based on the server name,
  1543. // it is designed to construct these queries from a domain name...so all
  1544. // these queries will be bogus, meaning they will waste network bandwidth,
  1545. // time to fail, and worst case cause expensive on demand links to come up
  1546. // as referrals/forwarders are contacted to attempt to resolve the bogus
  1547. // names. By setting LDAP_OPT_AREC_EXCLUSIVE to on using ldap_set_option
  1548. // after the ldap_init but before any other operation using the ldap
  1549. // handle from ldap_init, the delayed connection setup will not call
  1550. // DsGetDcName, just gethostbyname, or if an IP is passed, the ldap client
  1551. // will detect that and use the address directly.
  1552. //
  1553. //
  1554. // Remove the leading \\ if they exist.
  1555. //
  1556. FRS_TRIM_LEADING_2SLASH(DcDnsName);
  1557. FRS_TRIM_LEADING_2SLASH(DcAddr);
  1558. ulOptions = PtrToUlong(LDAP_OPT_ON);
  1559. Timeout.tv_sec = LdapBindTimeoutInSeconds;
  1560. Timeout.tv_usec = 0;
  1561. //
  1562. // Try using DcDnsName first.
  1563. //
  1564. if ((Ldap == NULL) && (DcDnsName != NULL)) {
  1565. Ldap = ldap_init(DcDnsName, LDAP_PORT);
  1566. if (Ldap != NULL) {
  1567. ldap_set_option(Ldap, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions);
  1568. LStatus = ldap_connect(Ldap, &Timeout);
  1569. if (LStatus != LDAP_SUCCESS) {
  1570. IPRINT4(Info, "%ws WARN - ldap_connect(%ws); (ldap error %08x = %ws)\n",
  1571. TabW, DcDnsName, LStatus, ldap_err2string(LStatus));
  1572. ldap_unbind_s(Ldap);
  1573. Ldap = NULL;
  1574. } else {
  1575. IPRINT2(Info, "%ws ldap_connect : %ws\n", TabW, DcDnsName);
  1576. }
  1577. }
  1578. }
  1579. //
  1580. // Try using DcAddr next.
  1581. //
  1582. if ((Ldap == NULL) && (DcAddr != NULL)) {
  1583. Ldap = ldap_init(DcAddr, LDAP_PORT);
  1584. if (Ldap != NULL) {
  1585. ldap_set_option(Ldap, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions);
  1586. LStatus = ldap_connect(Ldap, &Timeout);
  1587. if (LStatus != LDAP_SUCCESS) {
  1588. IPRINT4(Info, "%ws WARN - ldap_connect(%ws); (ldap error %08x = %ws)\n",
  1589. TabW, DcAddr, LStatus, ldap_err2string(LStatus));
  1590. ldap_unbind_s(Ldap);
  1591. Ldap = NULL;
  1592. } else {
  1593. IPRINT2(Info, "%ws ldap_connect : %ws\n", TabW, DcAddr);
  1594. }
  1595. }
  1596. }
  1597. //
  1598. // Try using DcName finally.
  1599. //
  1600. if ((Ldap == NULL) && (DcName != NULL)) {
  1601. Ldap = ldap_init(DcName, LDAP_PORT);
  1602. if (Ldap != NULL) {
  1603. ldap_set_option(Ldap, LDAP_OPT_AREC_EXCLUSIVE, &ulOptions);
  1604. LStatus = ldap_connect(Ldap, &Timeout);
  1605. if (LStatus != LDAP_SUCCESS) {
  1606. IPRINT4(Info, "%ws WARN - ldap_connect(%ws); (ldap error %08x = %ws)\n",
  1607. TabW, DcName, LStatus, ldap_err2string(LStatus));
  1608. ldap_unbind_s(Ldap);
  1609. Ldap = NULL;
  1610. } else {
  1611. IPRINT2(Info, "%ws ldap_connect : %ws\n", TabW, DcName);
  1612. }
  1613. }
  1614. }
  1615. //
  1616. // Whatever it is, we can't find it.
  1617. //
  1618. if (!Ldap) {
  1619. IPRINT6(Info, "%ws ERROR - ldap_connect(DNS %ws, BIOS %ws, IP %ws); (ldap error %08x = %ws)\n",
  1620. TabW, DcDnsName, DcName, DcAddr, LStatus, ldap_err2string(LStatus));
  1621. goto cleanup;
  1622. }
  1623. //
  1624. // Bind to the ldap server
  1625. //
  1626. LStatus = ldap_bind_s(Ldap, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  1627. //
  1628. // No luck; report error and carry on
  1629. //
  1630. if (LStatus != LDAP_SUCCESS) {
  1631. IPRINT4(Info, "%ws ERROR - ldap_bind_s(%ws); (ldap error %08x = %ws)\n",
  1632. TabW, ComputerName, LStatus, ldap_err2string(LStatus));
  1633. goto cleanup;
  1634. }
  1635. //
  1636. // Bind to the Ds (for various Ds calls such as DsCrackName())
  1637. //
  1638. //
  1639. // DC's Dns Name
  1640. //
  1641. WStatus = ERROR_RETRY;
  1642. if (!WIN_SUCCESS(WStatus) && DcDnsName) {
  1643. WStatus = DsBind(DcDnsName, NULL, &DsHandle);
  1644. if (!WIN_SUCCESS(WStatus)) {
  1645. DsHandle = NULL;
  1646. IPRINT3(Info, "%ws WARN - DsBind(DcDnsName %ws); WStatus %s\n",
  1647. TabW, DcDnsName, ErrLabelW32(WStatus));
  1648. } else {
  1649. IPRINT2(Info, "%ws DsBind : %ws\n", TabW, DcDnsName);
  1650. }
  1651. }
  1652. //
  1653. // DC's Computer Name
  1654. //
  1655. if (!WIN_SUCCESS(WStatus) && DcName) {
  1656. WStatus = DsBind(DcName, NULL, &DsHandle);
  1657. if (!WIN_SUCCESS(WStatus)) {
  1658. DsHandle = NULL;
  1659. IPRINT3(Info, "%ws WARN - DsBind(DcName %ws); WStatus %s\n",
  1660. TabW, DcName, ErrLabelW32(WStatus));
  1661. } else {
  1662. IPRINT2(Info, "%ws DsBind : %ws\n", TabW, DcName);
  1663. }
  1664. }
  1665. //
  1666. // DC's IP Address
  1667. //
  1668. if (!WIN_SUCCESS(WStatus) && DcAddr) {
  1669. WStatus = DsBind(DcAddr, NULL, &DsHandle);
  1670. if (!WIN_SUCCESS(WStatus)) {
  1671. DsHandle = NULL;
  1672. IPRINT3(Info, "%ws WARN - DsBind(DcAddr %ws); WStatus %s\n",
  1673. TabW, DcAddr, ErrLabelW32(WStatus));
  1674. } else {
  1675. IPRINT2(Info, "%ws DsBind : %ws\n", TabW, DcAddr);
  1676. }
  1677. }
  1678. //
  1679. // Whatever it is, we can't find it
  1680. //
  1681. if (!WIN_SUCCESS(WStatus)) {
  1682. IPRINT5(Info, "%ws ERROR - DsBind(DNS %ws, BIOS %ws, IP %ws); WStatus %s\n",
  1683. TabW, DcDnsName, DcName, DcAddr, ErrLabelW32(WStatus));
  1684. goto cleanup;
  1685. }
  1686. //
  1687. // NAMING CONTEXTS
  1688. //
  1689. IPRINT1(Info, "\n%wsNAMING CONTEXTS:\n", TabW);
  1690. //
  1691. // Find the naming contexts and the default naming context
  1692. //
  1693. Attrs[0] = ATTR_NAMING_CONTEXTS;
  1694. Attrs[1] = ATTR_DEFAULT_NAMING_CONTEXT;
  1695. Attrs[2] = NULL;
  1696. if (!InfoSearch(Info, Tabs + 1, Ldap, CN_ROOT, LDAP_SCOPE_BASE, CATEGORY_ANY,
  1697. Attrs, 0, &LdapMsg)) {
  1698. goto cleanup;
  1699. }
  1700. LdapEntry = ldap_first_entry(Ldap, LdapMsg);
  1701. if (!LdapEntry) {
  1702. IPRINT2(Info, "%ws ERROR - ldap_first_entry(contexts, %ws) no entry\n",
  1703. TabW, ComputerName);
  1704. goto cleanup;
  1705. }
  1706. Values = (PWCHAR *)FrsDsFindValues(Ldap, LdapEntry, ATTR_NAMING_CONTEXTS, FALSE);
  1707. if (!Values) {
  1708. IPRINT2(Info, "%ws ERROR - FrsDsFindValues(contexts, %ws) no entry\n",
  1709. TabW, ComputerName);
  1710. goto cleanup;
  1711. }
  1712. //
  1713. // Now, find the naming context that begins with "CN=configuration"
  1714. //
  1715. NumVals = ldap_count_values(Values);
  1716. while (NumVals--) {
  1717. FRS_WCSLWR(Values[NumVals]);
  1718. Config = wcsstr(Values[NumVals], CONFIG_NAMING_CONTEXT);
  1719. if (Config && Config == Values[NumVals]) {
  1720. //
  1721. // Build the pathname for "configuration\sites & services"
  1722. //
  1723. SitesDn = FrsDsExtendDn(Config, CN_SITES);
  1724. ServicesDn = FrsDsExtendDn(Config, CN_SERVICES);
  1725. break;
  1726. }
  1727. }
  1728. LDAP_FREE_VALUES(Values);
  1729. //
  1730. // Finally, find the default naming context
  1731. //
  1732. Values = (PWCHAR *)FrsDsFindValues(Ldap,
  1733. LdapEntry,
  1734. ATTR_DEFAULT_NAMING_CONTEXT,
  1735. FALSE);
  1736. if (!Values) {
  1737. IPRINT2(Info, "%ws ERROR - FrsDsFindValues(default naming context, %ws) no entry\n",
  1738. TabW, ComputerName);
  1739. goto cleanup;
  1740. }
  1741. DefaultNcDn = FrsWcsDup(Values[0]);
  1742. ComputersDn = FrsDsExtendDn(DefaultNcDn, CN_COMPUTERS);
  1743. DomainControllersDn = FrsDsExtendDnOu(DefaultNcDn, CN_DOMAIN_CONTROLLERS);
  1744. LDAP_FREE_VALUES(Values);
  1745. ShortName = InfoDup(SitesDn, INFO_DN_LEN);
  1746. IPRINT2(Info, "%ws SitesDn : %ws\n", TabW, ShortName);
  1747. ShortName = FrsFree(ShortName);
  1748. ShortName = InfoDup(ServicesDn, INFO_DN_LEN);
  1749. IPRINT2(Info, "%ws ServicesDn : %ws\n", TabW, ShortName);
  1750. ShortName = FrsFree(ShortName);
  1751. ShortName = InfoDup(DefaultNcDn, INFO_DN_LEN);
  1752. IPRINT2(Info, "%ws DefaultNcDn: %ws\n", TabW, ShortName);
  1753. ShortName = FrsFree(ShortName);
  1754. ShortName = InfoDup(ComputersDn, INFO_DN_LEN);
  1755. IPRINT2(Info, "%ws ComputersDn: %ws\n", TabW, ShortName);
  1756. ShortName = FrsFree(ShortName);
  1757. ShortName = InfoDup(DomainControllersDn, INFO_DN_LEN);
  1758. IPRINT2(Info, "%ws DomainCtlDn: %ws\n", TabW, ShortName);
  1759. ShortName = FrsFree(ShortName);
  1760. //
  1761. // Retrieve the computer's fully qualified Dn
  1762. //
  1763. ComputerFqdnLen = MAX_PATH;
  1764. if (!GetComputerObjectName(NameFullyQualifiedDN, ComputerFqdn, &ComputerFqdnLen)) {
  1765. IPRINT4(Info, "%ws ERROR - GetComputerObjectName(%ws); Len %d, WStatus %s\n",
  1766. TabW, ComputerName, ComputerFqdnLen, ErrLabelW32(GetLastError()));
  1767. ComputerFqdn[0] = L'\0';
  1768. } else {
  1769. ShortName = InfoDup(ComputerFqdn, INFO_DN_LEN);
  1770. IPRINT2(Info, "%ws Fqdn : %ws\n", TabW, ShortName);
  1771. ShortName = FrsFree(ShortName);
  1772. }
  1773. //
  1774. // Find and print the computer info
  1775. //
  1776. PrintedComputers = FALSE;
  1777. if (!PrintedComputers && ComputerFqdn[0]) {
  1778. IPRINT1(Info, "%ws Searching : Fqdn\n", TabW);
  1779. PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, ComputerFqdn,
  1780. CATEGORY_COMPUTER, LDAP_SCOPE_BASE, &InfoSubs);
  1781. }
  1782. if (!PrintedComputers && ComputersDn) {
  1783. IPRINT1(Info, "%ws Searching : Computers\n", TabW);
  1784. PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, ComputersDn,
  1785. CATEGORY_COMPUTER, LDAP_SCOPE_SUBTREE, &InfoSubs);
  1786. }
  1787. if (!PrintedComputers && DomainControllersDn) {
  1788. IPRINT1(Info, "%ws Searching : Domain Controllers\n", TabW);
  1789. PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, DomainControllersDn,
  1790. CATEGORY_COMPUTER, LDAP_SCOPE_SUBTREE, &InfoSubs);
  1791. }
  1792. if (!PrintedComputers && DefaultNcDn) {
  1793. IPRINT1(Info, "%ws Searching : Default Naming Context\n", TabW);
  1794. PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, DefaultNcDn,
  1795. CATEGORY_COMPUTER, LDAP_SCOPE_SUBTREE, &InfoSubs);
  1796. }
  1797. if (!PrintedComputers && DefaultNcDn) {
  1798. IPRINT1(Info, "%ws Searching : Default Naming Context for USER\n", TabW);
  1799. PrintedComputers = InfoPrintComputer(Info, Tabs, Ldap, DefaultNcDn,
  1800. CATEGORY_USER, LDAP_SCOPE_SUBTREE, &InfoSubs);
  1801. }
  1802. for (InfoSub = InfoSubs; InfoSub; InfoSub = InfoSub->Next) {
  1803. InfoPrintSettings(Info, Tabs, Ldap, InfoSub->Dn, DsHandle, &InfoSettings,
  1804. &InfoSets);
  1805. }
  1806. cleanup:
  1807. //
  1808. // Cleanup
  1809. //
  1810. LDAP_FREE_VALUES(Values);
  1811. LDAP_FREE_MSG(LdapMsg);
  1812. if (DcInfo) {
  1813. NetApiBufferFree(DcInfo);
  1814. DcInfo = NULL;
  1815. }
  1816. if (Ldap) {
  1817. ldap_unbind_s(Ldap);
  1818. }
  1819. if (HANDLE_IS_VALID(DsHandle)) {
  1820. DsUnBind(&DsHandle);
  1821. }
  1822. FrsFree(SitesDn);
  1823. FrsFree(ServicesDn);
  1824. FrsFree(DefaultNcDn);
  1825. FrsFree(ComputersDn);
  1826. FrsFree(DomainControllersDn);
  1827. FrsFree(ShortName);
  1828. while (InfoSub = InfoSubs) {
  1829. InfoSubs = InfoSub->Next;
  1830. FrsFree(InfoSub->Dn);
  1831. FrsFree(InfoSub->SetType);
  1832. FrsFree(InfoSub);
  1833. }
  1834. while (InfoSetting = InfoSettings) {
  1835. InfoSettings = InfoSetting->Next;
  1836. FrsFree(InfoSetting->Dn);
  1837. FrsFree(InfoSetting->SetType);
  1838. FrsFree(InfoSetting);
  1839. }
  1840. while (InfoSet = InfoSets) {
  1841. InfoSets = InfoSet->Next;
  1842. FrsFree(InfoSet->Dn);
  1843. FrsFree(InfoSet->SetType);
  1844. FrsFree(InfoSet);
  1845. }
  1846. //
  1847. // Real error messages are in the info buffer
  1848. //
  1849. return ERROR_SUCCESS;
  1850. }
  1851. PVOID
  1852. InfoFreeInfoTable(
  1853. IN PINFO_TABLE InfoTable,
  1854. IN PNTFRSAPI_INFO Info
  1855. )
  1856. /*++
  1857. Routine Description:
  1858. Free the info IDTable
  1859. Arguments:
  1860. InfoTable
  1861. Info
  1862. Return Value:
  1863. NULL
  1864. --*/
  1865. {
  1866. #undef DEBSUB
  1867. #define DEBSUB "InfoFreeInfoTable:"
  1868. JET_ERR jerr;
  1869. if (!InfoTable) {
  1870. return NULL;
  1871. }
  1872. if (InfoTable->TableCtx) {
  1873. DbsFreeTableContext(InfoTable->TableCtx, InfoTable->ThreadCtx->JSesid);
  1874. }
  1875. if (InfoTable->ThreadCtx) {
  1876. jerr = DbsCloseJetSession(InfoTable->ThreadCtx);
  1877. if (!JET_SUCCESS(jerr)) {
  1878. IPRINT1(Info, "DbsCloseJetSession jet error = %s\n", ErrLabelJet(jerr));
  1879. }
  1880. InfoTable->ThreadCtx = FrsFreeType(InfoTable->ThreadCtx);
  1881. }
  1882. return FrsFree(InfoTable);
  1883. }
  1884. JET_ERR
  1885. InfoConfigTableWorker(
  1886. IN PTHREAD_CTX ThreadCtx,
  1887. IN PTABLE_CTX TableCtx,
  1888. IN PCONFIG_TABLE_RECORD ConfigRecord,
  1889. IN PINFO_TABLE InfoTable
  1890. )
  1891. /*++
  1892. Routine Description:
  1893. This is a worker function passed to FrsEnumerateTable(). Each time
  1894. it is called it prints an entry into the info buffer.
  1895. Arguments:
  1896. ThreadCtx - Needed to access Jet.
  1897. TableCtx - A ptr to an ConfigTable context struct.
  1898. ConfigRecord - A ptr to a config table record.
  1899. InfoTable
  1900. Thread Return Value:
  1901. A Jet error status. Success means call us with the next record.
  1902. Failure means don't call again and pass our status back to the
  1903. caller of FrsEnumerateTable().
  1904. --*/
  1905. {
  1906. #undef DEBSUB
  1907. #define DEBSUB "InfoConfigTableWorker:"
  1908. if (FlagOn(InfoTable->Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) {
  1909. return JET_errNoCurrentRecord;
  1910. }
  1911. IPRINT0(InfoTable->Info, "\n\n");
  1912. DbsDisplayRecordIPrint(TableCtx, InfoTable, TRUE, NULL, 0);
  1913. return JET_errSuccess;
  1914. }
  1915. JET_ERR
  1916. InfoIDTableWorker(
  1917. IN PTHREAD_CTX ThreadCtx,
  1918. IN PTABLE_CTX TableCtx,
  1919. IN PIDTABLE_RECORD IDTableRec,
  1920. IN PINFO_TABLE InfoTable
  1921. )
  1922. /*++
  1923. Routine Description:
  1924. This is a worker function passed to FrsEnumerateTable(). Each time
  1925. it is called it prints an entry into the info buffer.
  1926. Arguments:
  1927. ThreadCtx - Needed to access Jet.
  1928. TableCtx - A ptr to an IDTable context struct.
  1929. IDTableRec - A ptr to a IDTable record.
  1930. InfoTable
  1931. Thread Return Value:
  1932. A Jet error status. Success means call us with the next record.
  1933. Failure means don't call again and pass our status back to the
  1934. caller of FrsEnumerateTable().
  1935. --*/
  1936. {
  1937. #undef DEBSUB
  1938. #define DEBSUB "InfoIDTableWorker:"
  1939. CHAR FlagBuffer[120];
  1940. WCHAR TabW[MAX_TAB_WCHARS + 1];
  1941. CHAR TimeStr[TIME_STRING_LENGTH];
  1942. CHAR Guid[GUID_CHAR_LEN + 1];
  1943. if (FlagOn(InfoTable->Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) {
  1944. return JET_errNoCurrentRecord;
  1945. }
  1946. //
  1947. // Table Descriptor
  1948. //
  1949. IPRINT1(InfoTable->Info, "\nTable Type: ID Table for %ws\n",
  1950. InfoTable->Replica->ReplicaName->Name);
  1951. DbsDisplayRecordIPrint(TableCtx, InfoTable, TRUE, NULL, 0);
  1952. return JET_errSuccess;
  1953. }
  1954. JET_ERR
  1955. InfoInOutLogTableWorker(
  1956. IN PTHREAD_CTX ThreadCtx,
  1957. IN PTABLE_CTX TableCtx,
  1958. IN PCHANGE_ORDER_COMMAND Coc,
  1959. IN PINFO_TABLE InfoTable,
  1960. IN PWCHAR TableDescriptor
  1961. )
  1962. /*++
  1963. Routine Description:
  1964. This is a worker function passed to FrsEnumerateTable(). Each time
  1965. it is called it prints an entry into the info buffer.
  1966. Arguments:
  1967. ThreadCtx - Needed to access Jet.
  1968. TableCtx - A ptr to an IDTable context struct.
  1969. Coc - A ptr to a inbound log record (change order)
  1970. InfoTable
  1971. TableDescriptor
  1972. Thread Return Value:
  1973. A Jet error status. Success means call us with the next record.
  1974. Failure means don't call again and pass our status back to the
  1975. caller of FrsEnumerateTable().
  1976. --*/
  1977. {
  1978. #undef DEBSUB
  1979. #define DEBSUB "InfoInOutLogTableWorker:"
  1980. PREPLICA Replica;
  1981. PCXTION Cxtion = NULL;
  1982. PWSTR CxtName = L"<null>";
  1983. PWSTR PartnerName = L"<null>";
  1984. PWSTR PartSrvName = L"<null>";
  1985. PCHAR CxtionState = "<null>";
  1986. BOOL PrintCxtion;
  1987. if (FlagOn(InfoTable->Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) {
  1988. return JET_errNoCurrentRecord;
  1989. }
  1990. //
  1991. // Table Descriptor
  1992. //
  1993. IPRINT2(InfoTable->Info, "\nTable Type: %ws for %ws\n",
  1994. TableDescriptor, InfoTable->Replica->ReplicaName->Name);
  1995. //
  1996. // Dump the change order record.
  1997. //
  1998. DbsDisplayRecordIPrint(TableCtx, InfoTable, TRUE, NULL, 0);
  1999. Replica = InfoTable->Replica;
  2000. //
  2001. // Find the cxtion for this CO
  2002. //
  2003. LOCK_CXTION_TABLE(Replica);
  2004. Cxtion = GTabLookupNoLock(Replica->Cxtions, &Coc->CxtionGuid, NULL);
  2005. PrintCxtion = (Cxtion != NULL) && (Cxtion->Inbound);
  2006. if (PrintCxtion) {
  2007. CxtionState = CxtionStateNames[Cxtion->State];
  2008. if (Cxtion->Name != NULL) {
  2009. if (Cxtion->Name->Name != NULL) {
  2010. CxtName = Cxtion->Name->Name;
  2011. }
  2012. }
  2013. if ((Cxtion->Partner != NULL) && (Cxtion->Partner->Name != NULL)) {
  2014. PartnerName = Cxtion->Partner->Name;
  2015. }
  2016. if (Cxtion->PartSrvName != NULL) {
  2017. PartSrvName = Cxtion->PartSrvName;
  2018. }
  2019. }
  2020. UNLOCK_CXTION_TABLE(Replica);
  2021. if (PrintCxtion) {
  2022. IPRINT3(InfoTable->Info, "Cxtion Name : %ws <- %ws\\%ws\n",
  2023. CxtName, PartnerName, PartSrvName);
  2024. IPRINT1(InfoTable->Info, "Cxtion State : %s\n", CxtionState);
  2025. }
  2026. return JET_errSuccess;
  2027. }
  2028. JET_ERR
  2029. InfoInLogTableWorker(
  2030. IN PTHREAD_CTX ThreadCtx,
  2031. IN PTABLE_CTX TableCtx,
  2032. IN PCHANGE_ORDER_COMMAND Coc,
  2033. IN PINFO_TABLE InfoTable
  2034. )
  2035. /*++
  2036. Routine Description:
  2037. This is a worker function passed to FrsEnumerateTable(). Each time
  2038. it is called it prints an entry into the info buffer.
  2039. Arguments:
  2040. ThreadCtx - Needed to access Jet.
  2041. TableCtx - A ptr to an IDTable context struct.
  2042. Coc - A ptr to a inbound log record (change order)
  2043. InfoTable
  2044. Thread Return Value:
  2045. A Jet error status. Success means call us with the next record.
  2046. Failure means don't call again and pass our status back to the
  2047. caller of FrsEnumerateTable().
  2048. --*/
  2049. {
  2050. return InfoInOutLogTableWorker(ThreadCtx, TableCtx, Coc, InfoTable,
  2051. L"Inbound Log Table");
  2052. }
  2053. JET_ERR
  2054. InfoOutLogTableWorker(
  2055. IN PTHREAD_CTX ThreadCtx,
  2056. IN PTABLE_CTX TableCtx,
  2057. IN PCHANGE_ORDER_COMMAND Coc,
  2058. IN PINFO_TABLE InfoTable
  2059. )
  2060. /*++
  2061. Routine Description:
  2062. This is a worker function passed to FrsEnumerateTable(). Each time
  2063. it is called it prints an entry into the info buffer.
  2064. Arguments:
  2065. ThreadCtx - Needed to access Jet.
  2066. TableCtx - A ptr to an IDTable context struct.
  2067. Coc - A ptr to a inbound log record (change order)
  2068. InfoTable
  2069. Thread Return Value:
  2070. A Jet error status. Success means call us with the next record.
  2071. Failure means don't call again and pass our status back to the
  2072. caller of FrsEnumerateTable().
  2073. --*/
  2074. {
  2075. return InfoInOutLogTableWorker(ThreadCtx, TableCtx, Coc, InfoTable,
  2076. L"Outbound Log Table");
  2077. }
  2078. DWORD
  2079. InfoPrintSingleTable(
  2080. IN PNTFRSAPI_INFO Info,
  2081. IN PWCHAR TableName,
  2082. IN TABLE_TYPE TableType,
  2083. IN PREPLICA Replica,
  2084. IN ULONG InfoIndexx,
  2085. IN PENUMERATE_TABLE_ROUTINE InfoTableWorker
  2086. )
  2087. /*++
  2088. Routine Description:
  2089. Display data for the specified table using the InfoPrint interface.
  2090. Arguments:
  2091. Info - ptr to the API Info ctx.
  2092. TableName - The name of the table
  2093. TableType - the Type code for the table.
  2094. Replica, -- ptr to the replica struct for the replica set.
  2095. InfoIndexx -- The ID of the index to use when enumerating the table.
  2096. InfoTableWorker -- The function to call to display each record.
  2097. Return Value:
  2098. jet error Status
  2099. --*/
  2100. {
  2101. #undef DEBSUB
  2102. #define DEBSUB "InfoPrintSingleTable:"
  2103. JET_ERR jerr = JET_errSuccess;
  2104. PINFO_TABLE InfoTable = NULL;
  2105. InfoTable = FrsAlloc(sizeof(*InfoTable));
  2106. InfoTable->ThreadCtx = FrsAllocType(THREAD_CONTEXT_TYPE);
  2107. InfoTable->TableCtx = DbsCreateTableContext(TableType);
  2108. InfoTable->Info = Info;
  2109. InfoTable->Tabs = 0; /* Tabs + 1*/ // Pitch this tabs stuff.
  2110. IPRINT1(Info, "\n***** %ws\n", TableName);
  2111. //
  2112. // Setup a Jet Session (returning the session ID in ThreadCtx).
  2113. //
  2114. jerr = DbsCreateJetSession(InfoTable->ThreadCtx);
  2115. if (!JET_SUCCESS(jerr)) {
  2116. IPRINT2(Info,"ERROR - %ws: DbsCreateJetSession jet error %s.\n",
  2117. TableName, ErrLabelJet(jerr));
  2118. goto RETURN;
  2119. }
  2120. //
  2121. // Init the table context and open the ID table.
  2122. //
  2123. jerr = DbsOpenTable(InfoTable->ThreadCtx,
  2124. InfoTable->TableCtx,
  2125. ReplicaAddrToId(Replica),
  2126. TableType,
  2127. NULL);
  2128. if (!JET_SUCCESS(jerr)) {
  2129. IPRINT2(Info,"ERROR - %ws: DbsOpenTable jet error %s.\n",
  2130. TableName, ErrLabelJet(jerr));
  2131. goto RETURN;
  2132. }
  2133. //
  2134. // Replica
  2135. //
  2136. InfoTable->Replica = Replica;
  2137. //
  2138. // Scan thru the Table
  2139. //
  2140. jerr = FrsEnumerateTable(InfoTable->ThreadCtx,
  2141. InfoTable->TableCtx,
  2142. InfoIndexx,
  2143. InfoTableWorker,
  2144. InfoTable);
  2145. //
  2146. // We're done. Return success if we made it to the end
  2147. //
  2148. if (jerr != JET_errNoCurrentRecord &&
  2149. jerr != JET_wrnTableEmpty) {
  2150. IPRINT2(Info,"ERROR - %ws: FrsEnumerateTable jet error %s.\n",
  2151. TableName, ErrLabelJet(jerr));
  2152. }
  2153. RETURN:
  2154. //
  2155. // Done
  2156. //
  2157. InfoTable = InfoFreeInfoTable(InfoTable, Info);
  2158. return jerr;
  2159. }
  2160. DWORD
  2161. InfoPrintTables(
  2162. IN PNTFRSAPI_INFO Info,
  2163. IN PWCHAR TableDescriptor,
  2164. IN TABLE_TYPE TableType,
  2165. IN ULONG InfoIndexx,
  2166. IN PENUMERATE_TABLE_ROUTINE InfoTableWorker
  2167. )
  2168. /*++
  2169. Routine Description:
  2170. Return internal info on a DB Table (see private\net\inc\ntfrsapi.h).
  2171. Arguments:
  2172. Info - RPC output buffer
  2173. TableDescriptor - Text string for output
  2174. TableType - Table type code (from schema.h)
  2175. InfoIndexx - Table index to use for enumeration (from schema.h)
  2176. Return Value:
  2177. Win32 Status
  2178. --*/
  2179. {
  2180. #undef DEBSUB
  2181. #define DEBSUB "InfoPrintTables:"
  2182. PVOID Key;
  2183. PREPLICA Replica = NULL;
  2184. extern PGEN_TABLE ReplicasByGuid;
  2185. //
  2186. // Check for single instance tables.
  2187. //
  2188. if ((TableType == ConfigTablex) ||
  2189. (TableType == ServiceTablex)) {
  2190. InfoPrintSingleTable(Info,
  2191. TableDescriptor,
  2192. TableType,
  2193. Replica,
  2194. InfoIndexx,
  2195. InfoTableWorker);
  2196. return ERROR_SUCCESS;
  2197. }
  2198. //
  2199. // For the given table type, dump info for all replica sets.
  2200. //
  2201. IPRINT1(Info, "NTFRS %ws\n", TableDescriptor);
  2202. Key = NULL;
  2203. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  2204. InfoPrintSingleTable(Info,
  2205. Replica->ReplicaName->Name,
  2206. TableType,
  2207. Replica,
  2208. InfoIndexx,
  2209. InfoTableWorker);
  2210. }
  2211. return ERROR_SUCCESS;
  2212. }
  2213. DWORD
  2214. InfoPrintMemory(
  2215. IN PNTFRSAPI_INFO Info,
  2216. IN DWORD Tabs
  2217. )
  2218. /*++
  2219. Routine Description:
  2220. Return internal info on memory usage (see private\net\inc\ntfrsapi.h).
  2221. Arguments:
  2222. Info - RPC output buffer
  2223. Tabs - number of tabs
  2224. Return Value:
  2225. Win32 Status
  2226. --*/
  2227. {
  2228. #undef DEBSUB
  2229. #define DEBSUB "InfoPrintMemory:"
  2230. FrsPrintAllocStats(0, Info, Tabs);
  2231. FrsPrintRpcStats(0, Info, Tabs);
  2232. return ERROR_SUCCESS;
  2233. }
  2234. DWORD
  2235. InfoPrintThreads(
  2236. IN PNTFRSAPI_INFO Info,
  2237. IN DWORD Tabs
  2238. )
  2239. /*++
  2240. Routine Description:
  2241. Return internal info on thread usage (see private\net\inc\ntfrsapi.h).
  2242. Arguments:
  2243. Info - RPC output buffer
  2244. Tabs - number of tabs
  2245. Return Value:
  2246. Win32 Status
  2247. --*/
  2248. {
  2249. #undef DEBSUB
  2250. #define DEBSUB "InfoPrintThreads:"
  2251. FrsPrintThreadStats(0, Info, Tabs);
  2252. return ERROR_SUCCESS;
  2253. }
  2254. VOID
  2255. FrsPrintStageStats(
  2256. IN ULONG Severity,
  2257. IN PNTFRSAPI_INFO Info, OPTIONAL
  2258. IN DWORD Tabs
  2259. );
  2260. DWORD
  2261. InfoPrintStage(
  2262. IN PNTFRSAPI_INFO Info,
  2263. IN DWORD Tabs
  2264. )
  2265. /*++
  2266. Routine Description:
  2267. Return internal info on thread usage (see private\net\inc\ntfrsapi.h).
  2268. Arguments:
  2269. Info - RPC output buffer
  2270. Tabs - number of tabs
  2271. Return Value:
  2272. Win32 Status
  2273. --*/
  2274. {
  2275. #undef DEBSUB
  2276. #define DEBSUB "InfoPrintStage:"
  2277. FrsPrintStageStats(0, Info, Tabs);
  2278. return ERROR_SUCCESS;
  2279. }
  2280. DWORD
  2281. InfoVerify(
  2282. IN ULONG BlobSize,
  2283. IN OUT PBYTE Blob
  2284. )
  2285. /*++
  2286. Routine Description:
  2287. Verify the consistency of the blob.
  2288. Arguments:
  2289. BlobSize - total bytes of Blob
  2290. Blob - details desired info and provides buffer for info
  2291. Return Value:
  2292. Win32 Status
  2293. --*/
  2294. {
  2295. #undef DEBSUB
  2296. #define DEBSUB "InfoVerify:"
  2297. DWORD WStatus;
  2298. PBYTE EoB;
  2299. PBYTE EoI;
  2300. PBYTE BoL;
  2301. PBYTE BoF;
  2302. PNTFRSAPI_INFO Info = (PNTFRSAPI_INFO)Blob;
  2303. //
  2304. // Assume success
  2305. //
  2306. WStatus = ERROR_SUCCESS;
  2307. //
  2308. // Not a valid blob
  2309. //
  2310. if (BlobSize < NTFRSAPI_INFO_HEADER_SIZE) {
  2311. WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
  2312. goto CLEANUP;
  2313. }
  2314. //
  2315. // BlobSize must include the entire Blob
  2316. //
  2317. if (BlobSize != Info->SizeInChars) {
  2318. WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
  2319. goto CLEANUP;
  2320. }
  2321. //
  2322. // Return our info version
  2323. //
  2324. Info->NtFrsMajor = NTFRS_MAJOR;
  2325. Info->NtFrsMinor = NTFRS_MINOR;
  2326. SetFlag(Info->Flags, NTFRSAPI_INFO_FLAGS_VERSION);
  2327. //
  2328. // Bad major
  2329. //
  2330. if (Info->Major != Info->NtFrsMajor) {
  2331. WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
  2332. goto CLEANUP;
  2333. }
  2334. //
  2335. // Bad minor
  2336. //
  2337. if (Info->Minor != Info->NtFrsMinor) {
  2338. WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
  2339. goto CLEANUP;
  2340. }
  2341. //
  2342. // Not large enough to verify internal consistency
  2343. //
  2344. if (Info->SizeInChars < sizeof(NTFRSAPI_INFO)) {
  2345. WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
  2346. goto CLEANUP;
  2347. }
  2348. //
  2349. // Buffer full; done
  2350. //
  2351. if (FlagOn(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) {
  2352. goto CLEANUP;
  2353. }
  2354. //
  2355. // Verify internal offsets
  2356. //
  2357. // make this into a subroutine (table driven?)
  2358. //
  2359. EoB = Blob + BlobSize;
  2360. EoI = ((PBYTE)Info) + (Info->SizeInChars);
  2361. BoL = (PBYTE)(((PCHAR)Info) + Info->OffsetToLines);
  2362. BoF = (PBYTE)(((PCHAR)Info) + Info->OffsetToFree);
  2363. if (EoI > EoB ||
  2364. BoL > EoB ||
  2365. BoF > EoB ||
  2366. EoI < Blob ||
  2367. BoL < Blob ||
  2368. BoF < Blob) {
  2369. WStatus = FRS_ERR_INVALID_SERVICE_PARAMETER;
  2370. goto CLEANUP;
  2371. }
  2372. //
  2373. // No free space in buffer; done
  2374. //
  2375. if (BoF == EoB) {
  2376. SetFlag(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL);
  2377. goto CLEANUP;
  2378. }
  2379. CLEANUP:
  2380. return WStatus;
  2381. }
  2382. DWORD
  2383. Info(
  2384. IN ULONG BlobSize,
  2385. IN OUT PBYTE Blob
  2386. )
  2387. /*++
  2388. Routine Description:
  2389. Return internal info (see private\net\inc\ntfrsapi.h).
  2390. Arguments:
  2391. BlobSize - total bytes of Blob
  2392. Blob - details desired info and provides buffer for info
  2393. Return Value:
  2394. Win32 Status
  2395. --*/
  2396. {
  2397. #undef DEBSUB
  2398. #define DEBSUB "Info:"
  2399. DWORD WStatus;
  2400. PBYTE EoB;
  2401. PBYTE EoI;
  2402. PBYTE BoL;
  2403. PBYTE BoF;
  2404. ULONG i;
  2405. PNTFRSAPI_INFO Info = (PNTFRSAPI_INFO)Blob;
  2406. ULONG ProductType;
  2407. ULONG Arch;
  2408. try {
  2409. //
  2410. // Verify the blob
  2411. //
  2412. WStatus = InfoVerify(BlobSize, Blob);
  2413. if (!WIN_SUCCESS(WStatus)) {
  2414. goto cleanup;
  2415. }
  2416. //
  2417. // Full buffer; done
  2418. //
  2419. if (FlagOn(Info->Flags, NTFRSAPI_INFO_FLAGS_FULL)) {
  2420. goto cleanup;
  2421. }
  2422. if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_VERSION) {
  2423. IPRINT0(Info, "NtFrs Version Information\n");
  2424. IPRINT1(Info, " NtFrs Major : %d\n", NtFrsMajor);
  2425. IPRINT1(Info, " NtFrs Minor : %d\n", NtFrsMinor);
  2426. // IPRINT1(Info, " NtFrs Module : %s\n", NtFrsModule);
  2427. IPRINT2(Info, " NtFrs Compiled on : %s %s\n", NtFrsDate, NtFrsTime);
  2428. #if NTFRS_TEST
  2429. IPRINT0(Info, " NTFRS_TEST Enabled\n");
  2430. #else NTFRS_TEST
  2431. IPRINT0(Info, " NTFRS_TEST Disabled\n");
  2432. #endif NTFRS_TEST
  2433. i = 0;
  2434. while (LatestChanges[i] != NULL) {
  2435. IPRINT1(Info, " %s\n", LatestChanges[i]);
  2436. i++;
  2437. }
  2438. IPRINT4(Info, "OS Version %d.%d (%d) - %w\n",
  2439. OsInfo.dwMajorVersion, OsInfo.dwMinorVersion,
  2440. OsInfo.dwBuildNumber, OsInfo.szCSDVersion);
  2441. ProductType = (ULONG) OsInfo.wProductType;
  2442. IPRINT4(Info, "SP (%hd.%hd) SM: 0x%04hx PT: 0x%02x\n",
  2443. OsInfo.wServicePackMajor, OsInfo.wServicePackMinor,
  2444. OsInfo.wSuiteMask, ProductType);
  2445. Arch = SystemInfo.wProcessorArchitecture;
  2446. if (Arch >= ARRAY_SZ(ProcessorArchName)) {
  2447. Arch = ARRAY_SZ(ProcessorArchName)-1;
  2448. }
  2449. IPRINT5(Info, "Processor: %s Level: 0x%04hx Revision: 0x%04hx Processor num/mask: %d/%08x\n",
  2450. ProcessorArchName[Arch], SystemInfo.wProcessorLevel,
  2451. SystemInfo.wProcessorRevision, SystemInfo.dwNumberOfProcessors,
  2452. SystemInfo.dwActiveProcessorMask);
  2453. goto cleanup;
  2454. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_SETS) {
  2455. WStatus = InfoPrintDbSets(Info, 0);
  2456. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_DS) {
  2457. WStatus = InfoPrintDs(Info, 0);
  2458. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_MEMORY) {
  2459. WStatus = InfoPrintMemory(Info, 0);
  2460. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_IDTABLE) {
  2461. WStatus = InfoPrintTables(Info,
  2462. L"ID TABLES",
  2463. IDTablex,
  2464. GuidIndexx,
  2465. InfoIDTableWorker);
  2466. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_INLOG) {
  2467. WStatus = InfoPrintTables(Info,
  2468. L"INLOG TABLES",
  2469. INLOGTablex,
  2470. ILSequenceNumberIndexx,
  2471. InfoInLogTableWorker);
  2472. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_OUTLOG) {
  2473. WStatus = InfoPrintTables(Info,
  2474. L"OUTLOG TABLES",
  2475. OUTLOGTablex,
  2476. OLSequenceNumberIndexx,
  2477. InfoOutLogTableWorker);
  2478. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_CONFIGTABLE) {
  2479. WStatus = InfoPrintTables(Info,
  2480. L"CONFIG TABLE",
  2481. ConfigTablex,
  2482. ReplicaSetNameIndexx,
  2483. InfoConfigTableWorker);
  2484. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_THREADS) {
  2485. WStatus = InfoPrintThreads(Info, 0);
  2486. } else if (Info->TypeOfInfo == NTFRSAPI_INFO_TYPE_STAGE) {
  2487. WStatus = InfoPrintStage(Info, 0);
  2488. } else {
  2489. IPRINT1(Info, "NtFrs Doesn't understand TypeOfInfo %d\n",
  2490. Info->TypeOfInfo);
  2491. }
  2492. cleanup:;
  2493. } except (EXCEPTION_EXECUTE_HANDLER) {
  2494. GET_EXCEPTION_CODE(WStatus);
  2495. }
  2496. //
  2497. // Clean up any handles, events, memory, ...
  2498. //
  2499. try {
  2500. } except (EXCEPTION_EXECUTE_HANDLER) {
  2501. GET_EXCEPTION_CODE(WStatus);
  2502. }
  2503. return WStatus;
  2504. }