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

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