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.

6039 lines
181 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. dblookup.c
  5. Abstract:
  6. LSA Database - Lookup Sid and Name routines
  7. NOTE: This module should remain as portable code that is independent
  8. of the implementation of the LSA Database. As such, it is
  9. permitted to use only the exported LSA Database interfaces
  10. contained in db.h and NOT the private implementation
  11. dependent functions in dbp.h.
  12. Author:
  13. Scott Birrell (ScottBi) November 27, 1992
  14. Environment:
  15. Revision History:
  16. --*/
  17. #include <lsapch2.h>
  18. #include "dbp.h"
  19. #include <sidcache.h>
  20. #include <bndcache.h>
  21. #include <malloc.h>
  22. #include <ntdsa.h>
  23. #include <ntdsapi.h>
  24. #include <ntdsapip.h>
  25. #include "lsawmi.h"
  26. #include <lmapibuf.h>
  27. #include <dsgetdc.h>
  28. //////////////////////////////////////////////////////////////////////////
  29. // //
  30. // Lsa Lookup Sid and Name Private Global State Variables //
  31. // //
  32. //////////////////////////////////////////////////////////////////////////
  33. //
  34. // See comment in dbluutil.c
  35. //
  36. extern BOOLEAN LsapReturnSidTypeDeleted;
  37. //
  38. // The shortcut list is meant for well known security principals
  39. // whose SidTypeUse is WellKnownGroup, not User
  40. //
  41. struct {
  42. LUID LogonId;
  43. LSAP_WELL_KNOWN_SID_INDEX LookupIndex;
  44. } LsapShortcutLookupList[] = {
  45. { SYSTEM_LUID, LsapLocalSystemSidIndex },
  46. { ANONYMOUS_LOGON_LUID, LsapAnonymousSidIndex },
  47. { LOCALSERVICE_LUID, LsapLocalServiceSidIndex },
  48. { NETWORKSERVICE_LUID, LsapNetworkServiceSidIndex }
  49. };
  50. //
  51. // Handy macros for iterating over static arrays
  52. //
  53. #define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
  54. NTSTATUS
  55. LsapDbLookupSidsInTrustedForests(
  56. IN ULONG Count,
  57. IN PLSAPR_SID *Sids,
  58. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  59. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  60. IN OUT PULONG MappedCount,
  61. IN OUT PULONG CompletelyUnmappedCount,
  62. OUT NTSTATUS *NonFatalStatus
  63. );
  64. NTSTATUS
  65. LsapDbLookupSidsInTrustedForestsWorker(
  66. IN ULONG Count,
  67. IN PLSAPR_SID *Sids,
  68. OUT PLSAPR_REFERENCED_DOMAIN_LIST * ReferencedDomains,
  69. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  70. OUT BOOLEAN *fAllocateAllNodes,
  71. IN OUT PULONG MappedCount,
  72. OUT NTSTATUS *NonFatalStatus
  73. );
  74. NTSTATUS
  75. LsapLookupSids(
  76. IN LSAPR_HANDLE PolicyHandle,
  77. IN PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
  78. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  79. OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  80. IN LSAP_LOOKUP_LEVEL LookupLevel,
  81. IN OUT PULONG MappedCount,
  82. IN ULONG LookupOptions,
  83. IN ULONG ClientRevision
  84. );
  85. NTSTATUS
  86. LsapDomainHasForestTrust(
  87. IN PUNICODE_STRING DomainName, OPTIONAL
  88. IN PSID DomainSid, OPTIONAL
  89. IN OUT BOOLEAN *fTDLLock, OPTIONAL
  90. OUT PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY *TrustEntryOut OPTIONAL
  91. );
  92. NTSTATUS
  93. LsapDomainHasDirectTrust(
  94. IN PUNICODE_STRING DomainName, OPTIONAL
  95. IN PSID DomainSid, OPTIONAL
  96. IN OUT BOOLEAN *fTDLLock, OPTIONAL
  97. OUT PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY *TrustEntryOut OPTIONAL
  98. );
  99. NTSTATUS
  100. LsapDomainHasTransitiveTrust(
  101. IN PUNICODE_STRING DomainName, OPTIONAL
  102. IN PSID DomainSid, OPTIONAL
  103. OUT LSA_TRUST_INFORMATION *TrustInfo OPTIONAL
  104. );
  105. NTSTATUS
  106. LsapDomainHasDirectExternalTrust(
  107. IN PUNICODE_STRING DomainName, OPTIONAL
  108. IN PSID DomainSid, OPTIONAL
  109. IN OUT BOOLEAN *fTDLLock, OPTIONAL
  110. OUT PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY *TrustEntryOut OPTIONAL
  111. );
  112. //////////////////////////////////////////////////////////////////////////
  113. // //
  114. // Lsa Lookup Sid Routines //
  115. // //
  116. //////////////////////////////////////////////////////////////////////////
  117. NTSTATUS
  118. LsarLookupSids(
  119. IN LSAPR_HANDLE PolicyHandle,
  120. IN PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
  121. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  122. IN OUT PLSAPR_TRANSLATED_NAMES TranslatedNames,
  123. IN LSAP_LOOKUP_LEVEL LookupLevel,
  124. IN OUT PULONG MappedCount
  125. )
  126. /*++
  127. Routine Description:
  128. See LsapLookupSids. LsarLookupSids is called by NT4 and below clients
  129. --*/
  130. {
  131. NTSTATUS Status = STATUS_SUCCESS;
  132. ULONG Size;
  133. LSAPR_TRANSLATED_NAMES_EX TranslatedNamesEx = {0, NULL};
  134. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupSids(%ws) start\n", LsapDbLookupGetLevel(LookupLevel)) );
  135. //
  136. // Note that due to the IN/OUT nature of TranslatedSids, it is
  137. // possible that a client can pass something into the Sids field.
  138. // However, NT clients do not so it is safe, and correct to free
  139. // any values at this point. Not doing so would mean a malicious
  140. // client could cause starve the server.
  141. //
  142. if ( TranslatedNames->Names ) {
  143. MIDL_user_free( TranslatedNames->Names );
  144. TranslatedNames->Names = NULL;
  145. }
  146. //
  147. // Allocate the TranslatedName buffer to return
  148. //
  149. TranslatedNames->Entries = 0;
  150. Size = SidEnumBuffer->Entries * sizeof(LSAPR_TRANSLATED_NAME);
  151. TranslatedNames->Names = midl_user_allocate( Size );
  152. if ( !TranslatedNames->Names ) {
  153. Status = STATUS_INSUFFICIENT_RESOURCES;
  154. goto Cleanup;
  155. }
  156. RtlZeroMemory( TranslatedNames->Names, Size );
  157. TranslatedNames->Entries = SidEnumBuffer->Entries;
  158. Status = LsapLookupSids( PolicyHandle,
  159. SidEnumBuffer,
  160. ReferencedDomains,
  161. (PLSAPR_TRANSLATED_NAMES_EX) &TranslatedNamesEx,
  162. LookupLevel,
  163. MappedCount,
  164. 0,
  165. LSA_CLIENT_PRE_NT5 );
  166. if ( TranslatedNamesEx.Names != NULL ) {
  167. //
  168. // Map the new data structure back to the old one
  169. //
  170. ULONG i;
  171. ASSERT( TranslatedNamesEx.Entries == TranslatedNames->Entries );
  172. for (i = 0; i < TranslatedNamesEx.Entries; i++ ) {
  173. if (LsapReturnSidTypeDeleted
  174. && TranslatedNamesEx.Names[i].Use == SidTypeUnknown
  175. && TranslatedNamesEx.Names[i].DomainIndex != LSA_UNKNOWN_INDEX) {
  176. //
  177. // A domain was found, but the SID couldn't be resolved
  178. // assume it has been deleted
  179. //
  180. TranslatedNames->Names[i].Use = SidTypeDeletedAccount;
  181. } else {
  182. TranslatedNames->Names[i].Use = TranslatedNamesEx.Names[i].Use;
  183. }
  184. TranslatedNames->Names[i].Name = TranslatedNamesEx.Names[i].Name;
  185. TranslatedNames->Names[i].DomainIndex = TranslatedNamesEx.Names[i].DomainIndex;
  186. }
  187. //
  188. // Free the Ex structure
  189. //
  190. midl_user_free( TranslatedNamesEx.Names );
  191. } else {
  192. TranslatedNames->Entries = 0;
  193. midl_user_free( TranslatedNames->Names );
  194. TranslatedNames->Names = NULL;
  195. }
  196. Cleanup:
  197. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupSids(%ws) end (0x%x)\n", LsapDbLookupGetLevel(LookupLevel), Status) );
  198. return Status;
  199. }
  200. NTSTATUS
  201. LsarLookupSids2(
  202. IN LSAPR_HANDLE PolicyHandle,
  203. IN PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
  204. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  205. OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  206. IN LSAP_LOOKUP_LEVEL LookupLevel,
  207. IN OUT PULONG MappedCount,
  208. IN ULONG LookupOptions,
  209. IN ULONG ClientRevision
  210. )
  211. /*++
  212. Routine Description:
  213. This routine is the server entry point for the IDL LsarLookupSids2.
  214. See LsapLookupSids. This API is used by win2k clients.
  215. Arguments:
  216. RpcHandle -- an RPC binding handle
  217. Rest -- See LsarLookupSids2
  218. Return Values:
  219. See LsarLookupSids2
  220. --*/
  221. {
  222. NTSTATUS Status;
  223. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupSids2(%ws) start\n", LsapDbLookupGetLevel(LookupLevel)) );
  224. Status = LsapLookupSids(PolicyHandle,
  225. SidEnumBuffer,
  226. ReferencedDomains,
  227. TranslatedNames,
  228. LookupLevel,
  229. MappedCount,
  230. LookupOptions,
  231. ClientRevision);
  232. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupSids2(%ws) end (0x%x)\n", LsapDbLookupGetLevel(LookupLevel), Status) );
  233. return Status;
  234. }
  235. NTSTATUS
  236. LsarLookupSids3(
  237. IN handle_t RpcHandle,
  238. IN PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
  239. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  240. OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  241. IN LSAP_LOOKUP_LEVEL LookupLevel,
  242. IN OUT PULONG MappedCount,
  243. IN ULONG LookupOptions,
  244. IN ULONG ClientRevision
  245. )
  246. /*++
  247. Routine Description:
  248. This routine is the server entry point for the IDL LsarLookupSids3.
  249. It accepts an RPC binding handle, instead of a LSA context handle; otherwise
  250. it behaves identically to LsarLookupSids2
  251. Arguments:
  252. RpcHandle -- an RPC binding handle
  253. Rest -- See LsapLookupSids
  254. Return Values:
  255. See LsapLookupSids
  256. --*/
  257. {
  258. NTSTATUS Status;
  259. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupSids3(%ws) start\n", LsapDbLookupGetLevel(LookupLevel)) );
  260. Status = LsapLookupSids(NULL,
  261. SidEnumBuffer,
  262. ReferencedDomains,
  263. TranslatedNames,
  264. LookupLevel,
  265. MappedCount,
  266. LookupOptions,
  267. ClientRevision);
  268. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupSids3(%ws) end (0x%x)\n", LsapDbLookupGetLevel(LookupLevel), Status) );
  269. return Status;
  270. }
  271. NTSTATUS
  272. LsapLookupSids(
  273. IN LSAPR_HANDLE PolicyHandle,
  274. IN PLSAPR_SID_ENUM_BUFFER SidEnumBuffer,
  275. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  276. OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  277. IN LSAP_LOOKUP_LEVEL LookupLevel,
  278. IN OUT PULONG MappedCount,
  279. IN ULONG LookupOptions,
  280. IN ULONG ClientRevision
  281. )
  282. /*++
  283. Routine Description:
  284. This routine is the LSA Server worker routine for the LsaLookupSids
  285. API.
  286. The LsaLookupSids API attempts to find names corresponding to Sids.
  287. If a name can not be mapped to a Sid, the Sid is converted to character
  288. form. The caller must have POLICY_LOOKUP_NAMES access to the Policy
  289. object.
  290. WARNING: This routine allocates memory for its output. The caller is
  291. responsible for freeing this memory after use. See description of the
  292. Names parameter.
  293. Arguments:
  294. PolicyHandle - Handle from an LsaOpenPolicy call.
  295. SidEnumBuffer - Pointer to an enumeration buffer containing a count
  296. and a pointer to an array of Count pointers to Sids to be mapped
  297. to names. The Sids may be well_known SIDs, SIDs of User accounts
  298. Group Accounts, Alias accounts, or Domains.
  299. ReferencedDomains - Receives a pointer to a structure describing the
  300. domains used for the translation. The entries in this structure
  301. are referenced by the structure returned via the Names parameter.
  302. Unlike the Names parameter, which contains an array entry
  303. for (each translated name, this strutcure will only contain
  304. component for each domain utilized in the translation.
  305. When this information is no longer needed, it must be released
  306. by passing the returned pointer to LsaFreeMemory().
  307. TranslatedNames - Pointer to a structure which will reference an array
  308. records describing each translated name. The nth entry in this array
  309. provides a translation for the nth entry in the Sids parameter.
  310. All of the returned names will be isolated names or NULL strings
  311. (domain names are returned as NULL strings). If the caller needs
  312. composite names, they can be generated by prepending the
  313. isolated name with the domain name and a backslash. For example,
  314. if (the name Sally is returned, and it is from the domain Manufact,
  315. then the composite name would be "Manufact" + "\" + "Sally" or
  316. "Manufact\Sally".
  317. When this information is no longer needed, it must be released
  318. by passing the returned pointer to LsaFreeMemory().
  319. If a Sid is not translatable, then the following will occur:
  320. 1) If the SID's domain is known, then a reference domain record
  321. will be generated with the domain's name. In this case, the
  322. name returned via the Names parameter is a Unicode representation
  323. of the relative ID of the account, such as "(3cmd14)" or the null
  324. string, if the Sid is that of a domain. So, you might end up
  325. with a resultant name of "Manufact\(314) for the example with
  326. Sally above, if Sally's relative id is 314.
  327. 2) If not even the SID's domain could be located, then a full
  328. Unicode representation of the SID is generated and no domain
  329. record is referenced. In this case, the returned string might
  330. be something like: "(S-1-672194-21-314)".
  331. When this information is no longer needed, it must be released
  332. by passing the returned pointer to LsaFreeMemory().
  333. LookupLevel - Specifies the Level of Lookup to be performed on this
  334. machine. Values of this field are are follows:
  335. LsapLookupWksta - First Level Lookup performed on a workstation
  336. normally configured for Windows-Nt. The lookup searches the
  337. Well-Known Sids/Names, and the Built-in Domain and Account Domain
  338. in the local SAM Database. If not all Sids or Names are
  339. identified, performs a "handoff" of a Second level Lookup to the
  340. LSA running on a Controller for the workstation's Primary Domain
  341. (if any).
  342. LsapLookupPDC - Second Level Lookup performed on a Primary Domain
  343. Controller. The lookup searches the Account Domain of the
  344. SAM Database on the controller. If not all Sids or Names are
  345. found, the Trusted Domain List (TDL) is obtained from the
  346. LSA's Policy Database and Third Level lookups are performed
  347. via "handoff" to each Trusted Domain in the List.
  348. LsapLookupTDL - Third Level Lookup performed on a controller
  349. for a Trusted Domain. The lookup searches the Account Domain of
  350. the SAM Database on the controller only.
  351. MappedCount - Pointer to location that contains a count of the Sids
  352. mapped so far. On exit, this will be updated.
  353. LookupOptions - flags to control the lookup. Currently non defined
  354. ClientRevision -- the version of the client
  355. Return Values:
  356. NTSTATUS - Standard Nt Result Code
  357. STATUS_SUCCESS - The call completed successfully and all Sids have
  358. been translated to names.
  359. STATUS_SOME_NOT_MAPPED - At least one of the Sids provided was
  360. translated to a Name, but not all Sids could be translated. This
  361. is a success status.
  362. STATUS_NONE_MAPPED - None of the Sids provided could be translated
  363. to names. This is an error status, but output is returned. Such
  364. output includes partial translations of Sids whose domain could
  365. be identified, together with their Relative Id in Unicode format,
  366. and character representations of Sids whose domain could not
  367. be identified.
  368. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  369. to complete the operation.
  370. STATUS_DOMAIN_CTRLR_CONFIG_ERROR - Target machine not configured
  371. as a DC when expected.
  372. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  373. such as memory to complete the call.
  374. --*/
  375. {
  376. NTSTATUS Status, SecondaryStatus, TempStatus;
  377. PLSAPR_SID *Sids = (PLSAPR_SID *) SidEnumBuffer->SidInfo;
  378. ULONG Count = SidEnumBuffer->Entries;
  379. BOOLEAN PolicyHandleReferencedHere = FALSE;
  380. PPOLICY_DNS_DOMAIN_INFO PolicyDnsDomainInfo = NULL;
  381. PTRUSTED_CONTROLLERS_INFO TrustedControllersInfo = NULL;
  382. LSA_HANDLE ControllerPolicyHandle = NULL;
  383. ULONG DomainIndex;
  384. ULONG SidIndex;
  385. LSAPR_TRUST_INFORMATION TrustInformation;
  386. PLSAPR_TRANSLATED_NAME_EX OutputNames = NULL;
  387. ULONG OutputNamesLength;
  388. PLSAPR_TRUST_INFORMATION Domains = NULL;
  389. ULONG CompletelyUnmappedCount = Count;
  390. ULONG LocalDomainsToSearch = 0;
  391. BOOLEAN AlreadyTranslated = FALSE;
  392. LUID LogonId;
  393. ULONG DomainLookupScope;
  394. ULONG PreviousMappedCount;
  395. //
  396. // Set to FALSE when the client is less than nt5
  397. //
  398. BOOLEAN fDoExtendedLookups = TRUE;
  399. LsarpReturnCheckSetup();
  400. LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_LookupSids);
  401. SecondaryStatus = STATUS_SUCCESS;
  402. //
  403. // Parameter checks
  404. //
  405. if ( NULL == Sids ) {
  406. Status = STATUS_INVALID_PARAMETER;
  407. goto LookupSidsError;
  408. }
  409. //
  410. // Perform an access check
  411. //
  412. Status = LsapDbLookupAccessCheck( PolicyHandle );
  413. if (!NT_SUCCESS(Status)) {
  414. goto LookupSidsError;
  415. }
  416. //
  417. // Determine what scope of resolution to use
  418. //
  419. DomainLookupScope = LsapGetDomainLookupScope(LookupLevel,
  420. ClientRevision);
  421. //
  422. // Init out parameters
  423. //
  424. TranslatedNames->Entries = SidEnumBuffer->Entries;
  425. TranslatedNames->Names = NULL;
  426. *ReferencedDomains = NULL;
  427. //
  428. // Verify that all of the Sids passed in are syntactically valid.
  429. //
  430. for (SidIndex = 0; SidIndex < Count; SidIndex++) {
  431. if ((Sids[SidIndex] != NULL) && RtlValidSid( (PSID) Sids[SidIndex])) {
  432. continue;
  433. }
  434. Status = STATUS_INVALID_PARAMETER;
  435. break;
  436. }
  437. if (!NT_SUCCESS( Status )) {
  438. goto LookupSidsError;
  439. }
  440. ASSERT( (LookupLevel == LsapLookupWksta)
  441. || (LookupLevel == LsapLookupPDC)
  442. || (LookupLevel == LsapLookupTDL)
  443. || (LookupLevel == LsapLookupGC)
  444. || (LookupLevel == LsapLookupXForestReferral)
  445. || (LookupLevel == LsapLookupXForestResolve) );
  446. //
  447. // Access and parameter checks are done -- fork off if this is a
  448. // referral
  449. //
  450. if (LookupLevel == LsapLookupXForestReferral) {
  451. NTSTATUS Status2;
  452. BOOLEAN fAllocateAllNodes = FALSE;
  453. *MappedCount = 0;
  454. Status = LsapDbLookupSidsInTrustedForestsWorker(Count,
  455. Sids,
  456. ReferencedDomains,
  457. TranslatedNames,
  458. &fAllocateAllNodes,
  459. MappedCount,
  460. &SecondaryStatus);
  461. if (fAllocateAllNodes) {
  462. //
  463. // Reallocate the memory in a form the server can return to RPC
  464. //
  465. Status2 = LsapLookupReallocateTranslations((PLSA_REFERENCED_DOMAIN_LIST*)ReferencedDomains,
  466. Count,
  467. (PLSA_TRANSLATED_NAME_EX*)&TranslatedNames->Names,
  468. NULL);
  469. if (!NT_SUCCESS(Status2)) {
  470. //
  471. // This is a fatal resource error - free the memory that
  472. // was returned to us by the chaining call
  473. //
  474. if (*ReferencedDomains) {
  475. midl_user_free(*ReferencedDomains);
  476. *ReferencedDomains = NULL;
  477. }
  478. if (TranslatedNames->Names) {
  479. midl_user_free(TranslatedNames->Names);
  480. TranslatedNames->Names = NULL;
  481. TranslatedNames->Entries = 0;
  482. }
  483. Status = Status2;
  484. }
  485. }
  486. //
  487. // There is nothing more to do
  488. //
  489. goto LookupSidsFinish;
  490. }
  491. //
  492. // Allocate Output Names array buffer. For now don't place its address on
  493. // the Free List as this buffer contains others that will be placed on
  494. // that list and the order of freeing is unknown.
  495. //
  496. OutputNamesLength = Count * sizeof(LSA_TRANSLATED_NAME_EX);
  497. OutputNames = MIDL_user_allocate(OutputNamesLength);
  498. Status = STATUS_INSUFFICIENT_RESOURCES;
  499. if (OutputNames == NULL) {
  500. goto LookupSidsError;
  501. }
  502. Status = STATUS_SUCCESS;
  503. TranslatedNames->Entries = SidEnumBuffer->Entries;
  504. TranslatedNames->Names = OutputNames;
  505. //
  506. // Initialize Output Names array, marking Sid Use as unknown and
  507. // specifying negative DomainIndex.
  508. //
  509. RtlZeroMemory( OutputNames, OutputNamesLength);
  510. for (SidIndex = 0; SidIndex < Count; SidIndex++) {
  511. OutputNames[SidIndex].Use = SidTypeUnknown;
  512. OutputNames[SidIndex].DomainIndex = LSA_UNKNOWN_INDEX;
  513. OutputNames[SidIndex].Flags = 0;
  514. }
  515. //
  516. // Create an empty Referenced Domain List.
  517. //
  518. Status = LsapDbLookupCreateListReferencedDomains( ReferencedDomains, 0 );
  519. if (!NT_SUCCESS(Status)) {
  520. goto LookupSidsError;
  521. }
  522. if ( Count == 1 ) {
  523. PUNICODE_STRING AccountName;
  524. PUNICODE_STRING AuthorityName;
  525. PSID UserSid;
  526. PSID DomainSid = NULL;
  527. ULONG Rid;
  528. PLSAP_LOGON_SESSION LogonSession;
  529. PTOKEN_USER TokenUserInformation;
  530. //
  531. // Let's see if we're trying to look up the currently logged on
  532. // user.
  533. //
  534. //
  535. // TokenUserInformation from this call must be freed by calling
  536. // LsapFreeLsaHeap().
  537. //
  538. Status = LsapQueryClientInfo(
  539. &TokenUserInformation,
  540. &LogonId
  541. );
  542. if ( !NT_SUCCESS( Status )) {
  543. goto NormalLookupPath;
  544. }
  545. if ( RtlEqualSid( TokenUserInformation->User.Sid, Sids[0] )) {
  546. ULONG i;
  547. LSAP_WELL_KNOWN_SID_INDEX ShortcutIndex = LsapDummyLastSidIndex;
  548. LsapFreeLsaHeap( TokenUserInformation );
  549. //
  550. // Got a match. Get the username and domain information
  551. // from the LogonId
  552. //
  553. LogonSession = LsapLocateLogonSession ( &LogonId );
  554. //
  555. // During setup, we may get NULL returned for the logon session.
  556. //
  557. if (LogonSession == NULL) {
  558. goto NormalLookupPath;
  559. }
  560. UserSid = LogonSession->UserSid;
  561. for (i = 0; i < NELEMENTS(LsapShortcutLookupList); i++ ) {
  562. if (RtlEqualLuid(&LogonId, &LsapShortcutLookupList[i].LogonId)) {
  563. ShortcutIndex = LsapShortcutLookupList[i].LookupIndex;
  564. }
  565. }
  566. if (ShortcutIndex != LsapDummyLastSidIndex) {
  567. AccountName = LsapDbWellKnownSidName( ShortcutIndex );
  568. AuthorityName = LsapDbWellKnownSidDescription( ShortcutIndex );
  569. } else {
  570. AccountName = &LogonSession->AccountName;
  571. AuthorityName = &LogonSession->AuthorityName;
  572. }
  573. //
  574. // N.B. To maintain app compatibility, return SidTypeUser for
  575. // the case of a single SID being looked up that is also the
  576. // SID of the caller. See bug 90589
  577. //
  578. OutputNames[0].Use = SidTypeUser;
  579. //
  580. // DomainSid will be allocated for us, free with MIDL_user_free
  581. //
  582. Status = LsapSplitSid( UserSid, &DomainSid, &Rid );
  583. if ( !NT_SUCCESS(Status)) {
  584. LsapReleaseLogonSession( LogonSession );
  585. goto NormalLookupPath;
  586. }
  587. RtlCopyMemory(
  588. &TrustInformation.Name,
  589. AuthorityName,
  590. sizeof( UNICODE_STRING )
  591. );
  592. TrustInformation.Sid = DomainSid;
  593. //
  594. // Fill in the Output Translated Name structure. Note that the
  595. // buffers for the SID and Unicode Name must be allocated via
  596. // MIDL_user_allocate() since they will be freed by the calling
  597. // RPC server stub routine lsarpc_LsarLookupSids() after marshalling.
  598. //
  599. OutputNames[0].DomainIndex = 0;
  600. Status = LsapRpcCopyUnicodeString(
  601. NULL,
  602. (PUNICODE_STRING) &OutputNames[0].Name,
  603. AccountName
  604. );
  605. //
  606. // Username, AccountName, and UserSid have all been copied
  607. // from the LogonSession structure, so we can release the AuLock now.
  608. //
  609. LsapReleaseLogonSession( LogonSession );
  610. if (!NT_SUCCESS(Status)) {
  611. MIDL_user_free(DomainSid);
  612. goto LookupSidsError;
  613. }
  614. //
  615. // Make an entry in the list of Referenced Domains.
  616. //
  617. Status = LsapDbLookupAddListReferencedDomains(
  618. *ReferencedDomains,
  619. &TrustInformation,
  620. (PLONG) &OutputNames[0].DomainIndex
  621. );
  622. //
  623. // DomainSid has been copied, free it now
  624. //
  625. MIDL_user_free( DomainSid );
  626. if (!NT_SUCCESS(Status)) {
  627. goto NormalLookupPath;
  628. }
  629. ASSERT( OutputNames[0].DomainIndex == 0 );
  630. *MappedCount = 1;
  631. LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_LookupSids);
  632. return( STATUS_SUCCESS );
  633. } else {
  634. LsapFreeLsaHeap( TokenUserInformation );
  635. }
  636. }
  637. NormalLookupPath:
  638. //
  639. // The local domains to be searched always include the Accounts
  640. // domain. For initial lookup targets only, the BUILT_IN domain is
  641. // also searched.
  642. //
  643. if ( LookupLevel != LsapLookupGC ) {
  644. LocalDomainsToSearch = LSAP_DB_SEARCH_ACCOUNT_DOMAIN;
  645. if (LookupLevel == LsapLookupWksta) {
  646. LocalDomainsToSearch |= LSAP_DB_SEARCH_BUILT_IN_DOMAIN;
  647. //
  648. // This is the lowest Lookup Level, normally targeted at a
  649. // Workstation but possibly targeted at a DC. Make a first pass of
  650. // the array of Sids to identify any well-known Isolated Sids. These
  651. // are Well Known Sids that do not belong to a real domain.
  652. //
  653. Status = LsapDbLookupIsolatedWellKnownSids(
  654. Count,
  655. Sids,
  656. *ReferencedDomains,
  657. TranslatedNames,
  658. MappedCount,
  659. &CompletelyUnmappedCount
  660. );
  661. if (!NT_SUCCESS(Status)) {
  662. goto LookupSidsError;
  663. }
  664. //
  665. // If all Sids are now mapped or partially mapped, finish.
  666. //
  667. if (CompletelyUnmappedCount == (ULONG) 0) {
  668. goto LookupSidsFinish;
  669. }
  670. }
  671. ASSERT( (LookupLevel == LsapLookupWksta)
  672. || (LookupLevel == LsapLookupPDC)
  673. || (LookupLevel == LsapLookupTDL)
  674. || (LookupLevel == LsapLookupXForestResolve) );
  675. //
  676. // There are some remaining completely unmapped Sids. They may belong to
  677. // a local SAM Domain. Currently, there are two such domains, the
  678. // Built-in Domain and the Accounts Domain. For initial Lookup Level
  679. // we search both of these domains. For higher Lookup Levels we search
  680. // only the Accounts domain.
  681. //
  682. Status = LsapDbLookupSidsInLocalDomains(
  683. Count,
  684. Sids,
  685. *ReferencedDomains,
  686. TranslatedNames,
  687. MappedCount,
  688. &CompletelyUnmappedCount,
  689. LocalDomainsToSearch
  690. );
  691. if (!NT_SUCCESS(Status)) {
  692. goto LookupSidsError;
  693. }
  694. }
  695. //
  696. // If all Sids are now mapped or partially mapped, finish.
  697. //
  698. if (CompletelyUnmappedCount == (ULONG) 0) {
  699. goto LookupSidsFinish;
  700. }
  701. //
  702. // Not all of the Sids have been identified in the local domains(s).
  703. // The next step in the search depends on the level of this lookup
  704. // and how we are configured as follows:
  705. //
  706. // Lookup Level Configuration Lookup search next
  707. //
  708. // LsapLookupWksta Win Nt Primary Domain
  709. // LanMan Nt Trusted Domains
  710. //
  711. // LsapLookupPDC Win Nt error
  712. // LanMan Nt Trusted Domains
  713. //
  714. // LsaLookupTDL Win Nt error
  715. // LanMan Nt none
  716. //
  717. if (LookupLevel == LsapLookupWksta) {
  718. if (LsapProductType != NtProductLanManNt) {
  719. ULONG MappedByCache = 0;
  720. //
  721. // This boolean indicates whether a post nt4 server
  722. // processed our remote lookups. This will be set
  723. // to TRUE when the current machine is part of a domain and
  724. // the secure channel is to a post nt4 DC
  725. //
  726. BOOLEAN fDownlevelSecureChannel = FALSE;
  727. MappedByCache = *MappedCount;
  728. //
  729. // Try the cache first
  730. //
  731. Status = LsapDbMapCachedSids(
  732. Sids,
  733. Count,
  734. FALSE, // don't use old entries
  735. *ReferencedDomains,
  736. TranslatedNames,
  737. MappedCount
  738. );
  739. if (!NT_SUCCESS(Status)) {
  740. goto LookupSidsError;
  741. }
  742. //
  743. // Note: we must update the CompletelyUnmappedCount here since
  744. // we may have potentially incremented the MappedCount
  745. //
  746. MappedByCache = *MappedCount - MappedByCache;
  747. CompletelyUnmappedCount -= MappedByCache;
  748. if (*MappedCount == Count) {
  749. goto LookupSidsFinish;
  750. }
  751. Status = LsapDbLookupGetDomainInfo(NULL,
  752. &PolicyDnsDomainInfo);
  753. if (!NT_SUCCESS(Status)) {
  754. goto LookupSidsError;
  755. }
  756. //
  757. // If there is no Primary Domain as in the case of a WORKGROUP,
  758. // just finish up. Set a default result code STATUS_SUCCESS. This
  759. // will be translated to STATUS_SOME_NOT_MAPPED or STATUS_NONE_MAPPED
  760. // as appropriate.
  761. //
  762. Status = STATUS_SUCCESS;
  763. if (PolicyDnsDomainInfo->Sid == NULL) {
  764. goto LookupSidsFinish;
  765. }
  766. //
  767. // There is a Primary Domain. Search it for Sids. Since a
  768. // Primary Domain is also a Trusted Domain, we use the
  769. // Trusted Domain search routine. This routine will "hand off"
  770. // the search to a Domain Controller's LSA.
  771. //
  772. RtlCopyMemory(
  773. &TrustInformation.Name,
  774. &PolicyDnsDomainInfo->Name,
  775. sizeof( UNICODE_STRING)
  776. );
  777. TrustInformation.Sid = (PSID) PolicyDnsDomainInfo->Sid;
  778. Status = LsapDbLookupSidsInPrimaryDomain(
  779. Count,
  780. Sids,
  781. &TrustInformation,
  782. *ReferencedDomains,
  783. TranslatedNames,
  784. LsapLookupPDC,
  785. MappedCount,
  786. &CompletelyUnmappedCount,
  787. &TempStatus,
  788. &fDownlevelSecureChannel
  789. );
  790. if (!NT_SUCCESS(Status)) {
  791. goto LookupSidsError;
  792. }
  793. if (TempStatus == STATUS_TRUSTED_RELATIONSHIP_FAILURE) {
  794. MappedByCache = *MappedCount;
  795. Status = LsapDbMapCachedSids(
  796. Sids,
  797. Count,
  798. TRUE, // Use old entries
  799. *ReferencedDomains,
  800. TranslatedNames,
  801. MappedCount
  802. );
  803. if (!NT_SUCCESS(Status)) {
  804. goto LookupSidsError;
  805. }
  806. MappedByCache = *MappedCount - MappedByCache;
  807. CompletelyUnmappedCount -= MappedByCache;
  808. }
  809. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  810. SecondaryStatus = TempStatus;
  811. }
  812. if (*MappedCount == Count) {
  813. goto LookupSidsFinish;
  814. }
  815. //
  816. // Now, search by sid history if we are a member of an DS aware
  817. // domain and our secure channel DC is not DS aware
  818. //
  819. if ( fDownlevelSecureChannel
  820. && (PolicyDnsDomainInfo->DnsDomainName.Length > 0) ) {
  821. Status = LsapDbLookupSidsInGlobalCatalogWks(
  822. Count,
  823. Sids,
  824. (PLSAPR_REFERENCED_DOMAIN_LIST) *ReferencedDomains,
  825. TranslatedNames,
  826. MappedCount,
  827. &CompletelyUnmappedCount,
  828. &TempStatus
  829. );
  830. if (!NT_SUCCESS(Status)) {
  831. goto LookupSidsError;
  832. }
  833. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  834. SecondaryStatus = TempStatus;
  835. }
  836. }
  837. goto LookupSidsFinish;
  838. }
  839. }
  840. //
  841. // We reach here in two cases:
  842. //
  843. // * Initial Level lookups targeted at DC's
  844. // * Higher Level Lookups (must be targeted at DC's)
  845. //
  846. // For the highest level lookup, that on an individual TDC, there
  847. // is no more searching to do, since we have already searched the
  848. // Accounts Domain and we do not follow trust relationships on DC's
  849. // beyond one level.
  850. //
  851. if (LookupLevel == LsapLookupTDL) {
  852. goto LookupSidsFinish;
  853. }
  854. ASSERT( (LookupLevel == LsapLookupWksta)
  855. || (LookupLevel == LsapLookupPDC)
  856. || (LookupLevel == LsapLookupGC)
  857. || (LookupLevel == LsapLookupXForestResolve) );
  858. //
  859. // We are either the initial target of the lookup but not configured
  860. // as a workstation, or we are the target of a Primary Domain
  861. // level lookup. In either case, we must be configured as a DC.
  862. //
  863. if (LsapProductType != NtProductLanManNt) {
  864. Status = STATUS_DOMAIN_CTRLR_CONFIG_ERROR;
  865. goto LookupSidsError;
  866. }
  867. if (DomainLookupScope & LSAP_LOOKUP_RESOLVE_ISOLATED_DOMAINS) {
  868. //
  869. // Lookup the items as domain SID's
  870. //
  871. PreviousMappedCount = *MappedCount;
  872. Status = LsapDbLookupSidsAsDomainSids(DomainLookupScope,
  873. Count,
  874. Sids,
  875. (PLSAPR_REFERENCED_DOMAIN_LIST) *ReferencedDomains,
  876. TranslatedNames,
  877. MappedCount);
  878. if (!NT_SUCCESS(Status)) {
  879. goto LookupSidsError;
  880. }
  881. CompletelyUnmappedCount -= (*MappedCount - PreviousMappedCount);
  882. }
  883. if (DomainLookupScope & LSAP_LOOKUP_TRUSTED_DOMAIN_TRANSITIVE) {
  884. //
  885. // Next, check the global catalog for sids that belong to post nt4 domains
  886. //
  887. Status = LsapDbLookupSidsInGlobalCatalog(
  888. Count,
  889. Sids,
  890. (PLSAPR_REFERENCED_DOMAIN_LIST) *ReferencedDomains,
  891. TranslatedNames,
  892. MappedCount,
  893. &CompletelyUnmappedCount,
  894. TRUE,
  895. &TempStatus
  896. );
  897. if (!NT_SUCCESS(Status)) {
  898. goto LookupSidsError;
  899. }
  900. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  901. SecondaryStatus = TempStatus;
  902. }
  903. }
  904. if (DomainLookupScope & LSAP_LOOKUP_TRUSTED_FOREST) {
  905. ASSERT( (LookupLevel == LsapLookupWksta)
  906. || (LookupLevel == LsapLookupPDC)
  907. || (LookupLevel == LsapLookupGC));
  908. //
  909. // Next check for trusted forest SID's
  910. //
  911. Status = LsapDbLookupSidsInTrustedForests(
  912. Count,
  913. Sids,
  914. (PLSAPR_REFERENCED_DOMAIN_LIST) *ReferencedDomains,
  915. TranslatedNames,
  916. MappedCount,
  917. &CompletelyUnmappedCount,
  918. &TempStatus
  919. );
  920. if (!NT_SUCCESS(Status)) {
  921. goto LookupSidsError;
  922. }
  923. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  924. SecondaryStatus = TempStatus;
  925. }
  926. }
  927. if (DomainLookupScope & LSAP_LOOKUP_TRUSTED_DOMAIN_DIRECT) {
  928. ASSERT((LookupLevel == LsapLookupWksta)
  929. || (LookupLevel == LsapLookupPDC));
  930. //
  931. // Obtain the Trusted Domain List and search all Trusted Domains
  932. // except ourselves.
  933. //
  934. Status = LsapDbLookupSidsInTrustedDomains(
  935. Count,
  936. Sids,
  937. !(DomainLookupScope & LSAP_LOOKUP_TRUSTED_DOMAIN_TRANSITIVE),
  938. // if we didn't go the GC, then
  939. // include intraforest trusts
  940. (PLSAPR_REFERENCED_DOMAIN_LIST) *ReferencedDomains,
  941. TranslatedNames,
  942. LsapLookupTDL,
  943. MappedCount,
  944. &CompletelyUnmappedCount,
  945. &TempStatus
  946. );
  947. if (!NT_SUCCESS(Status)) {
  948. goto LookupSidsError;
  949. }
  950. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  951. SecondaryStatus = TempStatus;
  952. }
  953. }
  954. LookupSidsFinish:
  955. //
  956. // If there are any unknown Sids (including partially mapped Sids)
  957. // we need to translate them to character form. We do this translation
  958. // at the lowest lookup level in all non-error cases and also in the
  959. // error case where none were mapped.
  960. //
  961. if (NT_SUCCESS(Status)) {
  962. if ((LookupLevel == LsapLookupWksta) &&
  963. (CompletelyUnmappedCount != 0) &&
  964. (AlreadyTranslated == FALSE)) {
  965. AlreadyTranslated = TRUE;
  966. //
  967. // The remaining unmapped Sids are unknown. They are either
  968. // completely unmapped, i.e. their domain is unknown, or
  969. // partially unmapped, their domain being known but their Rid
  970. // not being recognized. For completely unmapped Sids, translate
  971. // the entire Sid to character form. For partially unmapped
  972. // Sids, translate the Relative Id only to character form.
  973. //
  974. Status = LsapDbLookupTranslateUnknownSids(
  975. Count,
  976. Sids,
  977. *ReferencedDomains,
  978. TranslatedNames,
  979. *MappedCount
  980. );
  981. if (!NT_SUCCESS(Status)) {
  982. goto LookupSidsError;
  983. }
  984. }
  985. }
  986. //
  987. // If some but not all Sids were mapped, return informational status
  988. // STATUS_SOME_NOT_MAPPED. If no Sids were mapped, return error
  989. // STATUS_NONE_MAPPED.
  990. //
  991. if (NT_SUCCESS(Status)) {
  992. if (*MappedCount < Count) {
  993. Status = STATUS_SOME_NOT_MAPPED;
  994. if (*MappedCount == 0) {
  995. Status = STATUS_NONE_MAPPED;
  996. }
  997. }
  998. }
  999. //
  1000. // If no sids could be mapped it is likely due to the
  1001. // secondary status
  1002. //
  1003. if ( (STATUS_NONE_MAPPED == Status)
  1004. && (STATUS_NONE_MAPPED != SecondaryStatus)
  1005. && LsapRevisionCanHandleNewErrorCodes( ClientRevision )
  1006. && !NT_SUCCESS( SecondaryStatus ) ) {
  1007. Status = SecondaryStatus;
  1008. goto LookupSidsError;
  1009. }
  1010. LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_LookupSids);
  1011. LsarpReturnPrologue();
  1012. return(Status);
  1013. LookupSidsError:
  1014. //
  1015. // If the LookupLevel is the lowest (Workstation Level, free up
  1016. // the Names and Referenced Domains arrays.
  1017. //
  1018. if (LookupLevel == LsapLookupWksta) {
  1019. //
  1020. // If necessary, free the Names array.
  1021. //
  1022. if (TranslatedNames->Names != NULL) {
  1023. OutputNames = TranslatedNames->Names;
  1024. for (SidIndex = 0; SidIndex < Count; SidIndex++ ) {
  1025. if (OutputNames[SidIndex].Name.Buffer != NULL) {
  1026. MIDL_user_free( OutputNames[SidIndex].Name.Buffer );
  1027. OutputNames[SidIndex].Name.Buffer = NULL;
  1028. }
  1029. }
  1030. MIDL_user_free( TranslatedNames->Names );
  1031. TranslatedNames->Names = NULL;
  1032. }
  1033. //
  1034. // If necessary, free the Referenced Domain List.
  1035. //
  1036. if (*ReferencedDomains != NULL) {
  1037. Domains = (*ReferencedDomains)->Domains;
  1038. if (Domains != NULL) {
  1039. for (DomainIndex = 0;
  1040. DomainIndex < (*ReferencedDomains)->Entries;
  1041. DomainIndex++) {
  1042. if (Domains[ DomainIndex ].Name.Buffer != NULL) {
  1043. MIDL_user_free( Domains[ DomainIndex ].Name.Buffer );
  1044. Domains[ DomainIndex ].Name.Buffer = NULL;
  1045. }
  1046. if (Domains[ DomainIndex ].Sid != NULL) {
  1047. MIDL_user_free( Domains[ DomainIndex ].Sid );
  1048. Domains[ DomainIndex ].Sid = NULL;
  1049. }
  1050. }
  1051. MIDL_user_free( ( *ReferencedDomains)->Domains );
  1052. }
  1053. MIDL_user_free( *ReferencedDomains );
  1054. *ReferencedDomains = NULL;
  1055. }
  1056. }
  1057. //
  1058. // If the primary status was a success code, but the secondary
  1059. // status was an error, propagate the secondary status.
  1060. //
  1061. if ((!NT_SUCCESS(SecondaryStatus)) && NT_SUCCESS(Status)) {
  1062. Status = SecondaryStatus;
  1063. }
  1064. goto LookupSidsFinish;
  1065. }
  1066. NTSTATUS
  1067. LsapDbEnumerateSids(
  1068. IN LSAPR_HANDLE ContainerHandle,
  1069. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  1070. IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
  1071. OUT PLSAP_DB_SID_ENUMERATION_BUFFER DbEnumerationBuffer,
  1072. IN ULONG PreferedMaximumLength
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. This function enumerates Sids of objects of a given type within a container
  1077. object. Since there may be more information than can be returned in a
  1078. single call of the routine, multiple calls can be made to get all of the
  1079. information. To support this feature, the caller is provided with a
  1080. handle that can be used across calls. On the initial call,
  1081. EnumerationContext should point to a variable that has been initialized
  1082. to 0.
  1083. Arguments:
  1084. ContainerHandle - Handle to a container object.
  1085. ObjectTypeId - Type of object to be enumerated. The type must be one
  1086. for which all objects have Sids.
  1087. EnumerationContext - API-specific handle to allow multiple calls
  1088. (see Routine Description above).
  1089. DbEnumerationBuffer - Receives a pointer to a structure that will receive
  1090. the count of entries returned in an enumeration information array, and
  1091. a pointer to the array. Currently, the only information returned is
  1092. the object Sids. These Sids may be used together with object type to
  1093. open the objects and obtain any further information available.
  1094. PreferedMaximumLength - prefered maximum length of returned data (in 8-bit
  1095. bytes). This is not a hard upper limit, but serves as a guide. Due to
  1096. data conversion between systems with different natural data sizes, the
  1097. actual amount of data returned may be greater than this value.
  1098. CountReturned - Pointer to variable which will receive a count of the
  1099. entries returned.
  1100. Return Values:
  1101. NTSTATUS - Standard Nt Result Code
  1102. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  1103. to complete the operation.
  1104. STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
  1105. is returned if no objects have been enumerated because the
  1106. EnumerationContext value passed in is too high.
  1107. --*/
  1108. {
  1109. NTSTATUS Status = STATUS_SUCCESS;
  1110. LSAP_DB_ENUMERATION_ELEMENT LastElement;
  1111. PLSAP_DB_ENUMERATION_ELEMENT FirstElement, NextElement = NULL, FreeElement;
  1112. ULONG DataLengthUsed;
  1113. ULONG ThisBufferLength;
  1114. PSID *Sids = NULL;
  1115. BOOLEAN PreferedMaximumReached = FALSE;
  1116. ULONG EntriesRead;
  1117. ULONG Index, EnumerationIndex;
  1118. BOOLEAN TrustedClient = ((LSAP_DB_HANDLE) ContainerHandle)->Trusted;
  1119. LastElement.Next = NULL;
  1120. FirstElement = &LastElement;
  1121. //
  1122. // If no enumeration buffer provided, return an error.
  1123. //
  1124. if ( !ARGUMENT_PRESENT(DbEnumerationBuffer) ||
  1125. !ARGUMENT_PRESENT(EnumerationContext ) ) {
  1126. return(STATUS_INVALID_PARAMETER);
  1127. }
  1128. //
  1129. // Enumerate objects, stopping when the length of data to be returned
  1130. // reaches or exceeds the Prefered Maximum Length, or reaches the
  1131. // absolute maximum allowed for LSA object enumerations. We allow
  1132. // the last object enumerated to bring the total amount of data to
  1133. // be returned beyond the Prefered Maximum Length, but not beyond the
  1134. // absolute maximum length.
  1135. //
  1136. EnumerationIndex = *EnumerationContext;
  1137. for(DataLengthUsed = 0, EntriesRead = 0;
  1138. DataLengthUsed < PreferedMaximumLength;
  1139. DataLengthUsed += ThisBufferLength, EntriesRead++) {
  1140. //
  1141. // If the absolute maximum length has been exceeded, back off
  1142. // the last object enumerated.
  1143. //
  1144. if ((DataLengthUsed > LSA_MAXIMUM_ENUMERATION_LENGTH) &&
  1145. (!TrustedClient)) {
  1146. //
  1147. // If preferred length was zero, NextElement may be NULL
  1148. //
  1149. if (NextElement != NULL) {
  1150. FirstElement = NextElement->Next;
  1151. MIDL_user_free( NextElement->Sid );
  1152. MIDL_user_free( NextElement );
  1153. }
  1154. break;
  1155. }
  1156. //
  1157. // Allocate memory for next enumeration element. Set the Sid
  1158. // field to NULL for cleanup purposes.
  1159. //
  1160. NextElement = MIDL_user_allocate(sizeof (LSAP_DB_ENUMERATION_ELEMENT));
  1161. if (NextElement == NULL) {
  1162. Status = STATUS_INSUFFICIENT_RESOURCES;
  1163. break;
  1164. }
  1165. //
  1166. // Find the next object's Sid, and fill in its object information.
  1167. // Note that memory will be allocated via MIDL_user_allocate
  1168. // and must be freed when no longer required.
  1169. //
  1170. Status = LsapDbFindNextSid(
  1171. ContainerHandle,
  1172. &EnumerationIndex,
  1173. ObjectTypeId,
  1174. (PLSAPR_SID *) &NextElement->Sid
  1175. );
  1176. //
  1177. // Stop the enumeration if any error or warning occurs. Note
  1178. // that the warning STATUS_NO_MORE_ENTRIES will be returned when
  1179. // we've gone beyond the last index.
  1180. //
  1181. if (Status != STATUS_SUCCESS) {
  1182. //
  1183. // Since NextElement is not on the list, it will not get
  1184. // freed at the end so we must free it here.
  1185. //
  1186. MIDL_user_free( NextElement );
  1187. break;
  1188. }
  1189. //
  1190. // Get the length of the data allocated for the object's Sid
  1191. //
  1192. ThisBufferLength = RtlLengthSid( NextElement->Sid );
  1193. //
  1194. // Link the object just found to the front of the enumeration list
  1195. //
  1196. NextElement->Next = FirstElement;
  1197. FirstElement = NextElement;
  1198. }
  1199. //
  1200. // If an error other than STATUS_NO_MORE_ENTRIES occurred, return it.
  1201. // If STATUS_NO_MORE_ENTRIES was returned, we have enumerated all of the
  1202. // entries. In this case, return STATUS_SUCCESS if we enumerated at
  1203. // least one entry, otherwise propagate STATUS_NO_MORE_ENTRIES back to
  1204. // the caller.
  1205. //
  1206. if (!NT_SUCCESS(Status)) {
  1207. if (Status != STATUS_NO_MORE_ENTRIES) {
  1208. goto EnumerateSidsError;
  1209. }
  1210. if (EntriesRead == 0) {
  1211. goto EnumerateSidsError;
  1212. }
  1213. Status = STATUS_SUCCESS;
  1214. }
  1215. //
  1216. // Some entries were read, allocate an information buffer for returning
  1217. // them.
  1218. //
  1219. Sids = (PSID *) MIDL_user_allocate( sizeof (PSID) * EntriesRead );
  1220. if (Sids == NULL) {
  1221. Status = STATUS_INSUFFICIENT_RESOURCES;
  1222. goto EnumerateSidsError;
  1223. }
  1224. //
  1225. // Memory was successfully allocated for the return buffer.
  1226. // Copy in the enumerated Sids.
  1227. //
  1228. for (NextElement = FirstElement, Index = 0;
  1229. NextElement != &LastElement;
  1230. NextElement = NextElement->Next, Index++) {
  1231. ASSERT(Index < EntriesRead);
  1232. Sids[Index] = NextElement->Sid;
  1233. }
  1234. EnumerateSidsFinish:
  1235. //
  1236. // Free the enumeration element structures (if any).
  1237. //
  1238. for (NextElement = FirstElement; NextElement != &LastElement;) {
  1239. //
  1240. // If an error has occurred, dispose of memory allocated
  1241. // for any Sids.
  1242. //
  1243. if (!(NT_SUCCESS(Status) || (Status == STATUS_NO_MORE_ENTRIES))) {
  1244. if (NextElement->Sid != NULL) {
  1245. MIDL_user_free(NextElement->Sid);
  1246. }
  1247. }
  1248. //
  1249. // Free the memory allocated for the enumeration element.
  1250. //
  1251. FreeElement = NextElement;
  1252. NextElement = NextElement->Next;
  1253. MIDL_user_free(FreeElement);
  1254. }
  1255. //
  1256. // Fill in return enumeration structure (0 and NULL in error case).
  1257. //
  1258. DbEnumerationBuffer->EntriesRead = EntriesRead;
  1259. DbEnumerationBuffer->Sids = Sids;
  1260. *EnumerationContext = EnumerationIndex;
  1261. return(Status);
  1262. EnumerateSidsError:
  1263. //
  1264. // If necessary, free memory allocated for returning the Sids.
  1265. //
  1266. if (Sids != NULL) {
  1267. MIDL_user_free( Sids );
  1268. Sids = NULL;
  1269. }
  1270. EntriesRead = 0;
  1271. goto EnumerateSidsFinish;
  1272. }
  1273. NTSTATUS
  1274. LsapDbFindNextSid(
  1275. IN LSAPR_HANDLE ContainerHandle,
  1276. IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
  1277. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  1278. OUT PLSAPR_SID *NextSid
  1279. )
  1280. /*++
  1281. Routine Description:
  1282. This function finds the next Sid of object of a given type within a
  1283. container object. The given object type must be one where objects
  1284. have Sids. The Sids returned can be used on subsequent open calls to
  1285. access the objects.
  1286. Arguments:
  1287. ContainerHandle - Handle to container object.
  1288. EnumerationContext - Pointer to a variable containing the index of
  1289. the object to be found. A zero value indicates that the first
  1290. object is to be found.
  1291. ObjectTypeId - Type of the objects whose Sids are being enumerated.
  1292. NextSid - Receives a pointer to the next Sid found.
  1293. Return Value:
  1294. NTSTATUS - Standard Nt Result Code
  1295. STATUS_INVALID_HANDLE - Invalid ContainerHandle specified
  1296. STATUS_NO_MORE_ENTRIES - Warning that no more entries exist.
  1297. --*/
  1298. {
  1299. NTSTATUS Status, SecondaryStatus;
  1300. ULONG SidKeyValueLength = 0;
  1301. UNICODE_STRING SubKeyNameU;
  1302. UNICODE_STRING SidKeyNameU;
  1303. OBJECT_ATTRIBUTES ObjectAttributes;
  1304. HANDLE ContDirKeyHandle = NULL;
  1305. HANDLE SidKeyHandle = NULL;
  1306. PSID ObjectSid = NULL;
  1307. //
  1308. // Zeroise pointers for cleanup routine
  1309. //
  1310. SidKeyNameU.Buffer = NULL;
  1311. SubKeyNameU.Buffer = NULL;
  1312. //
  1313. // Setup object attributes for opening the appropriate Containing
  1314. // Directory. For example, if we're looking for Account objects,
  1315. // the containing Directory is "Accounts". The Unicode strings for
  1316. // containing Directories are set up during Lsa Initialization.
  1317. //
  1318. InitializeObjectAttributes(
  1319. &ObjectAttributes,
  1320. &LsapDbContDirs[ObjectTypeId],
  1321. OBJ_CASE_INSENSITIVE,
  1322. ((LSAP_DB_HANDLE) ContainerHandle)->KeyHandle,
  1323. NULL
  1324. );
  1325. Status = RtlpNtOpenKey(
  1326. &ContDirKeyHandle,
  1327. KEY_READ,
  1328. &ObjectAttributes,
  1329. 0
  1330. );
  1331. if (!NT_SUCCESS(Status)) {
  1332. ContDirKeyHandle = NULL; // For error processing
  1333. goto FindNextError;
  1334. }
  1335. //
  1336. // Initialize the Unicode String in which the next object's Logical Name
  1337. // will be returned. The Logical Name of an object equals its Registry
  1338. // Key relative to its Containing Directory, and is also equal to
  1339. // the Relative Id of the object represented in character form as an
  1340. // 8-digit number with leading zeros.
  1341. //
  1342. // NOTE: The size of buffer allocated for the Logical Name must be
  1343. // calculated dynamically when the Registry supports long names, because
  1344. // it is possible that the Logical Name of an object will be equal to a
  1345. // character representation of the full Sid, not just the Relative Id
  1346. // part.
  1347. //
  1348. SubKeyNameU.MaximumLength = (USHORT) LSAP_DB_LOGICAL_NAME_MAX_LENGTH;
  1349. SubKeyNameU.Length = 0;
  1350. SubKeyNameU.Buffer = LsapAllocateLsaHeap(SubKeyNameU.MaximumLength);
  1351. if (SubKeyNameU.Buffer == NULL) {
  1352. Status = STATUS_INSUFFICIENT_RESOURCES;
  1353. goto FindNextError;
  1354. }
  1355. //
  1356. // Now enumerate the next subkey.
  1357. //
  1358. Status = RtlpNtEnumerateSubKey(
  1359. ContDirKeyHandle,
  1360. &SubKeyNameU,
  1361. *EnumerationContext,
  1362. NULL
  1363. );
  1364. if (!NT_SUCCESS(Status)) {
  1365. goto FindNextError;
  1366. }
  1367. //
  1368. // Construct a path to the Sid attribute of the object relative to
  1369. // the containing directory. This path has the form
  1370. //
  1371. // <Object Logical Name>"\Sid"
  1372. //
  1373. // The Logical Name of the object has just been returned by the
  1374. // above call to RtlpNtEnumerateSubKey.
  1375. //
  1376. Status = LsapDbJoinSubPaths(
  1377. &SubKeyNameU,
  1378. &LsapDbNames[Sid],
  1379. &SidKeyNameU
  1380. );
  1381. if (!NT_SUCCESS(Status)) {
  1382. goto FindNextError;
  1383. }
  1384. //
  1385. // Setup object attributes for opening the Sid attribute
  1386. //
  1387. InitializeObjectAttributes(
  1388. &ObjectAttributes,
  1389. &SidKeyNameU,
  1390. OBJ_CASE_INSENSITIVE,
  1391. ContDirKeyHandle,
  1392. NULL
  1393. );
  1394. //
  1395. // Open the Sid attribute
  1396. //
  1397. Status = RtlpNtOpenKey(
  1398. &SidKeyHandle,
  1399. KEY_READ,
  1400. &ObjectAttributes,
  1401. 0
  1402. );
  1403. if (!NT_SUCCESS(Status)) {
  1404. SidKeyHandle = NULL;
  1405. goto FindNextError;
  1406. }
  1407. //
  1408. // Now query the size of the buffer required to read the Sid
  1409. // attribute's value.
  1410. //
  1411. SidKeyValueLength = 0;
  1412. Status = RtlpNtQueryValueKey(
  1413. SidKeyHandle,
  1414. NULL,
  1415. NULL,
  1416. &SidKeyValueLength,
  1417. NULL
  1418. );
  1419. //
  1420. // We expect buffer overflow to be returned from a query buffer size
  1421. // call.
  1422. //
  1423. if (Status == STATUS_BUFFER_OVERFLOW) {
  1424. Status = STATUS_SUCCESS;
  1425. } else {
  1426. if ( NT_SUCCESS( Status )) {
  1427. ASSERT( FALSE );
  1428. Status = STATUS_INTERNAL_ERROR;
  1429. }
  1430. goto FindNextError;
  1431. }
  1432. if ( SidKeyValueLength == 0 ) {
  1433. ASSERT( FALSE );
  1434. Status = STATUS_INTERNAL_ERROR;
  1435. goto FindNextError;
  1436. }
  1437. //
  1438. // Allocate memory for reading the Sid attribute.
  1439. //
  1440. ObjectSid = MIDL_user_allocate(SidKeyValueLength);
  1441. if (ObjectSid == NULL) {
  1442. Status = STATUS_INSUFFICIENT_RESOURCES;
  1443. goto FindNextError;
  1444. }
  1445. //
  1446. // Supplied buffer is large enough to hold the SubKey's value.
  1447. // Query the value.
  1448. //
  1449. Status = RtlpNtQueryValueKey(
  1450. SidKeyHandle,
  1451. NULL,
  1452. ObjectSid,
  1453. &SidKeyValueLength,
  1454. NULL
  1455. );
  1456. if (!NT_SUCCESS(Status)) {
  1457. goto FindNextError;
  1458. }
  1459. if ( SidKeyValueLength == 0 ) {
  1460. ASSERT( FALSE );
  1461. Status = STATUS_INTERNAL_ERROR;
  1462. goto FindNextError;
  1463. }
  1464. (*EnumerationContext)++;
  1465. //
  1466. // Return the Sid.
  1467. //
  1468. *NextSid = ObjectSid;
  1469. FindNextFinish:
  1470. //
  1471. // If necessary, close the Sid key handle
  1472. //
  1473. if (SidKeyHandle != NULL) {
  1474. SecondaryStatus = NtClose(SidKeyHandle);
  1475. #if DBG
  1476. if (!NT_SUCCESS(SecondaryStatus)) {
  1477. DbgPrint("LsapDbFindNextSid: NtClose failed 0x%lx\n", Status);
  1478. }
  1479. #endif // DBG
  1480. }
  1481. //
  1482. // If necessary, close the containing directory handle
  1483. //
  1484. if (ContDirKeyHandle != NULL) {
  1485. SecondaryStatus = NtClose(ContDirKeyHandle);
  1486. #if DBG
  1487. if (!NT_SUCCESS(SecondaryStatus)) {
  1488. DbgPrint(
  1489. "LsapDbFindNextSid: NtClose failed 0x%lx\n",
  1490. Status
  1491. );
  1492. }
  1493. #endif // DBG
  1494. }
  1495. //
  1496. // If necessary, free the Unicode String buffer allocated by
  1497. // LsapDbJoinSubPaths for the Registry key name of the Sid attribute
  1498. // relative to the containing directory Registry key.
  1499. //
  1500. if (SidKeyNameU.Buffer != NULL) {
  1501. RtlFreeUnicodeString( &SidKeyNameU );
  1502. }
  1503. //
  1504. // If necessary, free the Unicode String buffer allocated for
  1505. // Registry key name of the object relative to its containing
  1506. // directory.
  1507. //
  1508. if (SubKeyNameU.Buffer != NULL) {
  1509. LsapFreeLsaHeap( SubKeyNameU.Buffer );
  1510. }
  1511. return(Status);
  1512. FindNextError:
  1513. //
  1514. // If necessary, free the memory allocated for the object's Sid.
  1515. //
  1516. if (ObjectSid != NULL) {
  1517. MIDL_user_free(ObjectSid);
  1518. *NextSid = NULL;
  1519. }
  1520. goto FindNextFinish;
  1521. }
  1522. NTSTATUS
  1523. LsapDbLookupIsolatedWellKnownSids(
  1524. IN ULONG Count,
  1525. IN PLSAPR_SID *Sids,
  1526. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  1527. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  1528. IN OUT PULONG MappedCount,
  1529. IN OUT PULONG CompletelyUnmappedCount
  1530. )
  1531. /*++
  1532. Routine Description:
  1533. This function attempts to identify Sids as Isolated Well-Known Sids
  1534. (Well-Known Sids that do not belong to a domain) and translate them to
  1535. names. Note that Domain Sids for the Well Known domains themselves
  1536. (e.g the Sid of the Built-in Domain) will be identified.
  1537. WARNING: This function allocates memory for translated names. The
  1538. caller is responsible for freeing this memory after it is no longer
  1539. required.
  1540. Arguments:
  1541. Count - Specifies the count of Sids provided in the array Sids.
  1542. Sids - Pointer to an array of Sids to be examined.
  1543. TranslatedNames - Pointer to structure that will be initialized to
  1544. references an array of Name translations for the Sids.
  1545. ReferencedDomains - Pointer to a structure that will be initialized to
  1546. reference a list of the domains used for the translation.
  1547. The entries in this structure are referenced by the
  1548. structure returned via the Names parameter. Unlike the Names
  1549. parameter, which contains an array entry for (each translated name,
  1550. this structure will only contain one component for each domain
  1551. utilized in the translation.
  1552. If the specified location contains NULL, a structure will be allocated
  1553. via MIDL_user_allocate.
  1554. MappedCount - Pointer to location that contains on entry, the number
  1555. of Sids in Sids that have been translated so far. This number
  1556. is updated if any further Sids are translated by this call.
  1557. CompletelyUnmappedCount - Pointer to location containing the
  1558. count of completely unmapped Sids. A Sid is completely unmapped
  1559. if it is unknown and also its Domain Prefix Sid is not recognized.
  1560. This count is updated on exit, the number of completely unmapped
  1561. Sids whose Domain Prefices are identified by this routine being
  1562. subtracted from the input value.
  1563. Return Value:
  1564. NTSTATUS - Standard Nt Result Code
  1565. STATUS_SUCCESS - The call completed successfully. Note that some
  1566. or all of the Sids may remain partially or completely unmapped.
  1567. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  1568. such as memory to complete the call.
  1569. STATUS_INVALID_PARAMETER - Invalid parameter or parameter combination.
  1570. - *MappedCount > Count
  1571. --*/
  1572. {
  1573. NTSTATUS Status = STATUS_SUCCESS;
  1574. ULONG SidNumber;
  1575. ULONG UnmappedSidsRemaining;
  1576. PLSAPR_TRANSLATED_NAME_EX OutputNames = NULL;
  1577. ULONG PrefixSidLength;
  1578. UCHAR SubAuthorityCount;
  1579. LSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex;
  1580. LSAPR_TRUST_INFORMATION TrustInformation;
  1581. PLSAPR_SID Sid = NULL;
  1582. PLSAPR_SID PrefixSid = NULL;
  1583. OutputNames = TranslatedNames->Names;
  1584. UnmappedSidsRemaining = Count;
  1585. //
  1586. // Attempt to identify Sids as Well Known Isolated Sids
  1587. //
  1588. for (SidNumber = 0; SidNumber < Count; SidNumber++) {
  1589. Sid = Sids[SidNumber];
  1590. //
  1591. // Attempt to identify the next Sid using the Well Known Sids table,
  1592. // excluding those Sids that are also in the Built In domain. For
  1593. // those, we drop through to the Built in Domain search.
  1594. //
  1595. if (LsapDbLookupIndexWellKnownSid( Sid, &WellKnownSidIndex ) &&
  1596. !SID_IS_RESOLVED_BY_SAM(WellKnownSidIndex)) {
  1597. //
  1598. // Sid is identified. Copy its Well Known Name field
  1599. // UNICODE_STRING structure. Note that not all Well Known
  1600. // Sids have Well Known Names. For those Sids without a
  1601. // Well Known Name, this UNICODE_STRING structure specifies
  1602. // the NULL string.
  1603. //
  1604. Status = LsapRpcCopyUnicodeString(
  1605. NULL,
  1606. (PUNICODE_STRING) &(OutputNames[SidNumber].Name),
  1607. LsapDbWellKnownSidName(WellKnownSidIndex)
  1608. );
  1609. if (!NT_SUCCESS(Status)) {
  1610. break;
  1611. }
  1612. //
  1613. // Get the Sid's Use.
  1614. //
  1615. OutputNames[SidNumber].Use = LsapDbWellKnownSidNameUse(WellKnownSidIndex);
  1616. PrefixSid = NULL;
  1617. //
  1618. // If the Sid is a Domain Sid, store pointer to
  1619. // it in the Trust Information.
  1620. //
  1621. if (OutputNames[SidNumber].Use == SidTypeDomain) {
  1622. TrustInformation.Sid = Sid;
  1623. } else {
  1624. //
  1625. // The Sid is not a domain Sid. Construct the
  1626. // Prefix Sid. This is equal to the original Sid
  1627. // excluding the lowest subauthority (Relative Id).
  1628. //
  1629. SubAuthorityCount = *RtlSubAuthorityCountSid((PSID) Sid);
  1630. PrefixSidLength = RtlLengthRequiredSid(SubAuthorityCount - 1);
  1631. Status = STATUS_INSUFFICIENT_RESOURCES;
  1632. PrefixSid = MIDL_user_allocate( PrefixSidLength );
  1633. if (PrefixSid == NULL) {
  1634. break;
  1635. }
  1636. Status = STATUS_SUCCESS;
  1637. RtlCopyMemory( PrefixSid, Sid, PrefixSidLength );
  1638. (*RtlSubAuthorityCountSid( (PSID) PrefixSid ))--;
  1639. TrustInformation.Sid = PrefixSid;
  1640. }
  1641. //
  1642. // Lookup this Domain Sid or Prefix Sid in the Referenced Domain
  1643. // List. If it is already there, return the DomainIndex for the
  1644. // existing entry and free up the memory allocated for the
  1645. // Prefix Sid (if any).
  1646. //
  1647. if (LsapDbLookupListReferencedDomains(
  1648. ReferencedDomains,
  1649. TrustInformation.Sid,
  1650. (PLONG) &(OutputNames[SidNumber].DomainIndex)
  1651. )) {
  1652. if ((OutputNames[SidNumber].Use == SidTypeDomain) ||
  1653. (OutputNames[SidNumber].Name.Buffer != NULL)) {
  1654. UnmappedSidsRemaining--;
  1655. }
  1656. if (PrefixSid != NULL) {
  1657. MIDL_user_free(PrefixSid);
  1658. PrefixSid = NULL;
  1659. }
  1660. continue;
  1661. }
  1662. //
  1663. // This Domain or Prefix Sid is not currently on the
  1664. // Referenced Domain List. Complete a Trust Information
  1665. // entry and add it to the List. Copy in the Domain Name
  1666. // (Domain Sids) or NULL string. Note that we use
  1667. // RtlCopyMemory to copy a UNICODE_STRING structure onto
  1668. // a LSAPR_UNICODE_STRING structure.
  1669. //
  1670. RtlCopyMemory(
  1671. &TrustInformation.Name,
  1672. &WellKnownSids[WellKnownSidIndex].DomainName,
  1673. sizeof(UNICODE_STRING)
  1674. );
  1675. //
  1676. // If the Sid has been recognized as a Well Known Sid and
  1677. // is either a Domain Sid or has a well-known name, count
  1678. // it as being mapped and add the Built-in Domain to the
  1679. // Referenced Domain List.
  1680. //
  1681. if ((OutputNames[SidNumber].Use == SidTypeDomain) ||
  1682. (OutputNames[SidNumber].Name.Length != 0)) {
  1683. UnmappedSidsRemaining--;
  1684. //
  1685. // Make an entry in the list of Referenced Domains. Note
  1686. // that in the case of well-known Sids, the Prefix Sid
  1687. // may or may not be the Sid of a Domain. For those well
  1688. // known Sids whose prefix Sid is not a domain Sid, the
  1689. // Name field in the Trust Information has been set to the
  1690. // NULL string.
  1691. //
  1692. Status = LsapDbLookupAddListReferencedDomains(
  1693. ReferencedDomains,
  1694. &TrustInformation,
  1695. (PLONG) &OutputNames[SidNumber].DomainIndex
  1696. );
  1697. if (!NT_SUCCESS(Status)) {
  1698. break;
  1699. }
  1700. } else {
  1701. //
  1702. // The Sid is recognized as a Well Known Sid, but is
  1703. // not a Domain Sid and does not have a Well Known Name
  1704. // (signified by a zero length name string). Filter this
  1705. // out.
  1706. //
  1707. OutputNames[SidNumber].Use = SidTypeUnknown;
  1708. OutputNames[SidNumber].Name.Length = (USHORT) 0;
  1709. OutputNames[SidNumber].Name.MaximumLength = (USHORT) 0;
  1710. OutputNames[SidNumber].Name.Buffer = NULL;
  1711. }
  1712. //
  1713. // If memory was allocated for a Prefix Sid, free it. Note that
  1714. // the LsapDbLookupAddListTrustedDomains routine will have made
  1715. // a copy of the Sid.
  1716. //
  1717. if (PrefixSid != NULL) {
  1718. MIDL_user_free(PrefixSid);
  1719. PrefixSid = NULL;
  1720. }
  1721. }
  1722. }
  1723. if (!NT_SUCCESS( Status )) {
  1724. goto LookupIsolatedWellKnownSidsError;
  1725. }
  1726. LookupIsolatedWellKnownSidsFinish:
  1727. //
  1728. // If there is a final PrefixSid buffer, free it.
  1729. //
  1730. if (PrefixSid != NULL) {
  1731. MIDL_user_free(PrefixSid);
  1732. PrefixSid = NULL;
  1733. }
  1734. //
  1735. // Return output parameters.
  1736. //
  1737. *MappedCount = Count - UnmappedSidsRemaining;
  1738. *CompletelyUnmappedCount = UnmappedSidsRemaining;
  1739. return(Status);
  1740. LookupIsolatedWellKnownSidsError:
  1741. goto LookupIsolatedWellKnownSidsFinish;
  1742. }
  1743. BOOLEAN
  1744. LsapDbLookupIndexWellKnownSid(
  1745. IN PLSAPR_SID Sid,
  1746. OUT PLSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex
  1747. )
  1748. /*++
  1749. Routine Description:
  1750. This function looks up a Sid to determine if it is well-known. If so,
  1751. an index into the table of well-known Sids is returned.
  1752. Arguments:
  1753. Sid - Pointer to Sid to be looked up.
  1754. WellKnownSidIndex - Pointer to variable that will receive the
  1755. index of the Sid if well known.
  1756. Return Value:
  1757. BOOLEAN - TRUE if the Sid is well-known, else FALSE
  1758. --*/
  1759. {
  1760. LSAP_WELL_KNOWN_SID_INDEX Index;
  1761. //
  1762. // Scan the table of well-known Sids looking for a match.
  1763. //
  1764. for(Index = LsapNullSidIndex; Index<LsapDummyLastSidIndex; Index++) {
  1765. //
  1766. // Allow NULL entries in the table of well-known Sids for now.
  1767. //
  1768. if (WellKnownSids[Index].Sid == NULL) {
  1769. continue;
  1770. }
  1771. //
  1772. // If a match is found, return the index to the caller.
  1773. //
  1774. if (RtlEqualSid((PSID) Sid, WellKnownSids[Index].Sid)) {
  1775. *WellKnownSidIndex = Index;
  1776. return TRUE;
  1777. }
  1778. }
  1779. //
  1780. // The Sid is not a well-known Sid. Return FALSE.
  1781. //
  1782. return FALSE;
  1783. }
  1784. ULONG LsapDbGetSizeTextSid(
  1785. IN PSID Sid
  1786. )
  1787. /*++
  1788. Routine Description:
  1789. This function computes the size of ASCIIZ buffer required for a
  1790. Sid in character form. Temporarily, the size returned is an over-
  1791. estimate, because 9 digits are allowed for the decimal equivalent
  1792. of each 32-bit SubAuthority value.
  1793. Arguments:
  1794. Sid - Pointer to Sid to be sized
  1795. Return Value:
  1796. ULONG - The required size of buffer is returned.
  1797. --*/
  1798. {
  1799. ULONG TextSidSize = 0;
  1800. //
  1801. // Count the Sid prefix and revision "S-rev-". The revision can
  1802. // theoretically be 8 bits which requires 3 digits
  1803. //
  1804. TextSidSize = sizeof("S-nnn-");
  1805. //
  1806. // Add in the size of the identifier authority
  1807. //
  1808. TextSidSize += 15; // log base 10 of 48 (= 6-byte number)
  1809. //
  1810. // If the Sid has SubAuthorities, count 9 bytes for each one
  1811. //
  1812. if (((PLSAPR_SID) Sid)->SubAuthorityCount > 0) {
  1813. TextSidSize += (ULONG)
  1814. (9 * ((PLSAPR_SID) Sid)->SubAuthorityCount);
  1815. }
  1816. return TextSidSize;
  1817. }
  1818. NTSTATUS
  1819. LsapDbSidToTextSid(
  1820. IN PSID Sid,
  1821. OUT PSZ TextSid
  1822. )
  1823. /*++
  1824. Routine Description:
  1825. This function converts a Sid to character text and places it in the
  1826. supplied buffer. The buffer is assumed to be of sufficient size, as
  1827. can be computed by calling LsapDbGetSizeTextSid().
  1828. Arguments:
  1829. Sid - Pointer to Sid to be converted.
  1830. TextSid - Optional pointer to the buffer in which the converted
  1831. Sid will be placed as an ASCIIZ. A NULL pointer ma
  1832. Return Value:
  1833. NTSTATUS - Standard Nt Result Code
  1834. --*/
  1835. {
  1836. PLSAPR_SID ISid = Sid;
  1837. ULONG Index;
  1838. ULONG IdentifierAuthorityValue;
  1839. UCHAR Buffer[LSAP_MAX_SIZE_TEXT_SID];
  1840. sprintf(Buffer, "S-%u-", (USHORT) ISid->Revision );
  1841. strcpy(TextSid, Buffer);
  1842. if ((ISid->IdentifierAuthority.Value[0] != 0) ||
  1843. (ISid->IdentifierAuthority.Value[1] != 0)) {
  1844. sprintf(Buffer, "0x%02hx%02hx%02hx%02hx%02hx%02hx",
  1845. (USHORT)ISid->IdentifierAuthority.Value[0],
  1846. (USHORT)ISid->IdentifierAuthority.Value[1],
  1847. (USHORT)ISid->IdentifierAuthority.Value[2],
  1848. (USHORT)ISid->IdentifierAuthority.Value[3],
  1849. (USHORT)ISid->IdentifierAuthority.Value[4],
  1850. (USHORT)ISid->IdentifierAuthority.Value[5] );
  1851. strcat(TextSid, Buffer);
  1852. } else {
  1853. IdentifierAuthorityValue =
  1854. (ULONG)ISid->IdentifierAuthority.Value[5] +
  1855. (ULONG)(ISid->IdentifierAuthority.Value[4] << 8) +
  1856. (ULONG)(ISid->IdentifierAuthority.Value[3] << 16) +
  1857. (ULONG)(ISid->IdentifierAuthority.Value[2] << 24);
  1858. sprintf(Buffer, "%lu", IdentifierAuthorityValue);
  1859. strcat(TextSid, Buffer);
  1860. }
  1861. //
  1862. // Now format the Sub Authorities (if any) as text.
  1863. //
  1864. for (Index = 0; Index < (ULONG) ISid->SubAuthorityCount; Index++ ) {
  1865. sprintf(Buffer, "-%lu", ISid->SubAuthority[Index]);
  1866. strcat(TextSid, Buffer);
  1867. }
  1868. return STATUS_SUCCESS;
  1869. }
  1870. NTSTATUS
  1871. LsapDbSidToUnicodeSid(
  1872. IN PSID Sid,
  1873. OUT PUNICODE_STRING SidU,
  1874. IN BOOLEAN AllocateDestinationString
  1875. )
  1876. /*++
  1877. Routine Description:
  1878. This function converts a Sid to Unicode form and optionally allocates
  1879. (via MIDL_user_allocate) memory for the string buffer.
  1880. Arguments:
  1881. Sid - Pointer to Sid to be translated.
  1882. SidU - Pointer to Unicode string that will receive the Unicode
  1883. Sid text.
  1884. AllocateDestinationString - If TRUE, the buffer for the destination
  1885. string will be allocated. If FALSE, it is assummed that the
  1886. destination Unicode string references a buffer of sufficient size.
  1887. Return Value:
  1888. --*/
  1889. {
  1890. NTSTATUS Status;
  1891. ULONG TextSidSize;
  1892. PSZ TextSid = NULL;
  1893. ANSI_STRING SidAnsi;
  1894. if (AllocateDestinationString) {
  1895. SidU->Buffer = NULL;
  1896. }
  1897. //
  1898. // First, query the amount of memory required for a buffer that
  1899. // will hold the Sid as an ASCIIZ character string.
  1900. //
  1901. TextSidSize = LsapDbGetSizeTextSid(Sid);
  1902. //
  1903. // Now allocate a buffer for the Text Sid.
  1904. //
  1905. TextSid = LsapAllocateLsaHeap(TextSidSize);
  1906. if (TextSid == NULL) {
  1907. Status = STATUS_INSUFFICIENT_RESOURCES;
  1908. goto Cleanup;
  1909. }
  1910. //
  1911. // Convert the Sid to ASCIIZ and place in the buffer.
  1912. //
  1913. Status = LsapDbSidToTextSid(Sid, TextSid);
  1914. if (!NT_SUCCESS(Status)) {
  1915. goto Cleanup;
  1916. }
  1917. //
  1918. // Now convert the text Sid to Unicode form via ANSI string form.
  1919. // If we are to allocate the output buffer, do so via the
  1920. // midl_USER_allocate routine.
  1921. //
  1922. RtlInitString(&SidAnsi, TextSid);
  1923. if (AllocateDestinationString) {
  1924. SidU->MaximumLength = (USHORT) RtlAnsiStringToUnicodeSize(&SidAnsi);
  1925. SidU->Buffer = MIDL_user_allocate( SidU->MaximumLength );
  1926. if ( SidU->Buffer == NULL ) {
  1927. Status = STATUS_INSUFFICIENT_RESOURCES;
  1928. goto Cleanup;
  1929. }
  1930. SidU->Length = 0;
  1931. }
  1932. //
  1933. // Now convert the Ansi String to a Unicode string. The buffer is
  1934. // already allocated. Free Text Sid buffer before checking conversion
  1935. // status.
  1936. //
  1937. Status = RtlAnsiStringToUnicodeString(SidU, &SidAnsi, FALSE);
  1938. Cleanup:
  1939. if ( TextSid != NULL) {
  1940. LsapFreeLsaHeap(TextSid);
  1941. }
  1942. if (!NT_SUCCESS(Status)) {
  1943. if (AllocateDestinationString) {
  1944. if ( SidU->Buffer != NULL ) {
  1945. MIDL_user_free(SidU->Buffer);
  1946. SidU->Buffer = NULL;
  1947. }
  1948. }
  1949. }
  1950. return Status;
  1951. }
  1952. NTSTATUS
  1953. LsapDbLookupTranslateUnknownSids(
  1954. IN ULONG Count,
  1955. IN PLSAPR_SID *Sids,
  1956. IN PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  1957. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  1958. IN ULONG MappedCount
  1959. )
  1960. /*++
  1961. Routine Description:
  1962. This function translates unmapped Sids to a character representation.
  1963. If the Domain of a Sid is unknown, the entire Sid is translated,
  1964. otherwise the Relative Id only is translated.
  1965. Parameters:
  1966. Count - Specifies the number of Sids in the array.
  1967. Sids - Pointer to an array of Sids. Some of these will already
  1968. have been translated.
  1969. ReferencedDomains - Pointer to Referenced Domains List header.
  1970. TranslatedNames - Pointer to structure that references the array of
  1971. translated names. The nth element of the referenced array
  1972. corresponds to the nth Sid in the Sids array. Some of the
  1973. Sids may be already translated and will be ignored. Those that are
  1974. not yet translated have zero length Unicode structures with NULL
  1975. buffer pointers. Already translated Sids are ignored.
  1976. MappedCount - Specifies the number of Sids that have already been
  1977. translated.
  1978. Return Values:
  1979. NTSTATUS - Standard Nt Result Code
  1980. STATUS_SUCCESS - The call completed successfully
  1981. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  1982. such as memory, to complete the call.
  1983. --*/
  1984. {
  1985. NTSTATUS Status = STATUS_SUCCESS;
  1986. ULONG SidIndex;
  1987. ULONG UnmappedCount;
  1988. PSID Sid;
  1989. UNICODE_STRING NameU;
  1990. PLSA_TRANSLATED_NAME_EX Names = (PLSA_TRANSLATED_NAME_EX) TranslatedNames->Names;
  1991. ULONG CleanupFreeListOptions = (ULONG) 0;
  1992. UnmappedCount = Count - MappedCount;
  1993. //
  1994. // Examine the array of Sids, looking for Unknown ones to translate.
  1995. // Translate any Unknown ones found to character representations,
  1996. // and stop either when all of them have been accounted for, or when
  1997. // the end of the array is reached.
  1998. //
  1999. if (MappedCount == Count) {
  2000. goto TranslateUnknownSidsFinish;
  2001. }
  2002. if (MappedCount > Count) {
  2003. goto TranslateUnknownSidsError;
  2004. }
  2005. for (SidIndex = 0, UnmappedCount = Count - MappedCount;
  2006. (SidIndex < Count) && (UnmappedCount > 0);
  2007. SidIndex++) {
  2008. Sid = Sids[SidIndex];
  2009. //
  2010. // If the Sid has already been mapped, ignore it.
  2011. //
  2012. if (Names[SidIndex].Use != SidTypeUnknown) {
  2013. continue;
  2014. }
  2015. //
  2016. // Found an unmapped Sid. If the domain is known, convert the
  2017. // Relative Id of the Sid to a Unicode String, limited to 8
  2018. // characters and with leading zeros.
  2019. //
  2020. if (Names[SidIndex].DomainIndex >= 0) {
  2021. //
  2022. // Convert the Relative Id to a Unicode Name and store in
  2023. // the Translation.
  2024. //
  2025. Status = LsapRtlSidToUnicodeRid( Sid, &NameU );
  2026. if (!NT_SUCCESS(Status)) {
  2027. goto TranslateUnknownSidsError;
  2028. }
  2029. } else {
  2030. //
  2031. // The Domain is unknown. In this case, convert the whole Sid
  2032. // to the standard character representation.
  2033. //
  2034. Status = RtlConvertSidToUnicodeString( &NameU, Sid, TRUE );
  2035. if (!NT_SUCCESS(Status)) {
  2036. goto TranslateUnknownSidsError;
  2037. }
  2038. }
  2039. //
  2040. // Copy the Unicode Name to the output, allocating memory for
  2041. // its buffer via MIDL_user_allocate
  2042. //
  2043. Status = LsapRpcCopyUnicodeString(
  2044. NULL,
  2045. &Names[SidIndex].Name,
  2046. &NameU
  2047. );
  2048. RtlFreeUnicodeString(&NameU);
  2049. if (!NT_SUCCESS(Status)) {
  2050. goto TranslateUnknownSidsError;
  2051. }
  2052. //
  2053. // Decrement the remaining Unmapped Count
  2054. //
  2055. UnmappedCount--;
  2056. }
  2057. TranslateUnknownSidsFinish:
  2058. return(Status);
  2059. TranslateUnknownSidsError:
  2060. goto TranslateUnknownSidsFinish;
  2061. }
  2062. NTSTATUS
  2063. LsapDbLookupSidsInLocalDomains(
  2064. IN ULONG Count,
  2065. IN PLSAPR_SID *Sids,
  2066. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2067. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  2068. IN OUT PULONG MappedCount,
  2069. IN OUT PULONG CompletelyUnmappedCount,
  2070. IN ULONG Options
  2071. )
  2072. /*++
  2073. Routine Description:
  2074. This function looks up Sids in the local SAM domains and attempts to
  2075. translate them to names. Currently, there are two local SAM domains,
  2076. the Built-in domain (which has a well-known Sid and name) and the
  2077. Account Domain (which has a configurable Sid and name).
  2078. Arguments:
  2079. Count - Number of Sids in the Sids array, Note that some of these
  2080. may already have been mapped elsewhere, as specified by the
  2081. MappedCount parameter.
  2082. Sids - Pointer to array of pointers to Sids to be translated.
  2083. Zero or all of the Sids may already have been translated
  2084. elsewhere. If any of the Sids have been translated, the
  2085. Names parameter will point to a location containing a non-NULL
  2086. array of Name translation structures corresponding to the
  2087. Sids. If the nth Sid has been translated, the nth name
  2088. translation structure will contain either a non-NULL name
  2089. or a non-negative offset into the Referenced Domain List. If
  2090. the nth Sid has not yet been translated, the nth name
  2091. translation structure will contain a zero-length name string
  2092. and a negative value for the Referenced Domain List index.
  2093. ReferencedDomains - Pointer to a structure in which the list of domains
  2094. used in the translation is maintained. The entries in this structure
  2095. are referenced by the structure returned via the Sids parameter.
  2096. Unlike the Sids parameter, which contains an array entry for each
  2097. translated name, this structure will only contain one component for
  2098. each domain utilized in the translation.
  2099. TranslatedNames - Pointer to a structure in which the translations to Names
  2100. corresponding to the Sids specified on Sids is maintained. The
  2101. nth entry in this array provides a translation (where known) for the
  2102. nth element in the Sids parameter.
  2103. MappedCount - Pointer to location in which a count of the Names that
  2104. have been completely translated is maintained.
  2105. CompletelyUnmappedCount - Pointer to a location in which a count of the
  2106. Names that have not been translated (either partially, by identification
  2107. of a Domain Prefix, or completely) is maintained.
  2108. Options - Specifies optional actions.
  2109. LSAP_DB_SEARCH_BUILT_IN_DOMAIN - Search the Built In Domain
  2110. LSAP_DB_SEARCH_ACCOUNT_DOMAIN - Search the Account Domain
  2111. Return Values:
  2112. NTSTATUS - Standard Nt Result Code
  2113. STATUS_SUCCESS - The call completed successfully. Note that some
  2114. or all of the Sids may remain partially or completely unmapped.
  2115. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  2116. such as memory, to complete the call.
  2117. STATUS_INTERNAL_DB_ERROR - A corruption has been detected in
  2118. the LSA Database.
  2119. STATUS_INVALID_PARAMETER - Invalid parameter
  2120. - No handle to the Policy object was provided on a request
  2121. to search the Account Domain.
  2122. --*/
  2123. {
  2124. NTSTATUS
  2125. Status = STATUS_SUCCESS,
  2126. SecondaryStatus = STATUS_SUCCESS;
  2127. LSAPR_TRUST_INFORMATION
  2128. TrustInformation;
  2129. ULONG
  2130. UpdatedMappedCount = *MappedCount;
  2131. LSAPR_HANDLE
  2132. TrustedPolicyHandle = NULL;
  2133. LSAP_WELL_KNOWN_SID_INDEX
  2134. WellKnownSidIndex;
  2135. PLSAPR_POLICY_ACCOUNT_DOM_INFO
  2136. PolicyAccountDomainInfo = NULL;
  2137. //
  2138. // If there are no completely unmapped Sids remaining, return.
  2139. //
  2140. if (*CompletelyUnmappedCount == (ULONG) 0) {
  2141. goto LookupSidsInLocalDomainsFinish;
  2142. }
  2143. //
  2144. // If requested, lookup Sids in the BUILT-IN Domain.
  2145. //
  2146. if (Options & LSAP_DB_SEARCH_BUILT_IN_DOMAIN) {
  2147. //
  2148. // Set up the Trust Information structure for this domain.
  2149. //
  2150. TrustInformation.Sid = LsapBuiltInDomainSid;
  2151. Status = STATUS_INTERNAL_DB_ERROR;
  2152. if (!LsapDbLookupIndexWellKnownSid(
  2153. LsapBuiltInDomainSid,
  2154. &WellKnownSidIndex
  2155. )) {
  2156. goto LookupSidsInLocalDomainsError;
  2157. }
  2158. Status = STATUS_SUCCESS;
  2159. //
  2160. // Obtain the name of the Built In Domain from the table of
  2161. // Well Known Sids. It suffices to copy the Unicode structures
  2162. // since we do not need a separate copy of the name buffer.
  2163. //
  2164. TrustInformation.Name = *((PLSAPR_UNICODE_STRING)
  2165. LsapDbWellKnownSidName(WellKnownSidIndex));
  2166. Status = LsapDbLookupSidsInLocalDomain(
  2167. LSAP_DB_SEARCH_BUILT_IN_DOMAIN,
  2168. Count,
  2169. Sids,
  2170. &TrustInformation,
  2171. ReferencedDomains,
  2172. TranslatedNames,
  2173. &UpdatedMappedCount,
  2174. CompletelyUnmappedCount
  2175. );
  2176. if (!NT_SUCCESS(Status)) {
  2177. goto LookupSidsInLocalDomainsError;
  2178. }
  2179. //
  2180. // If all Sids are now mapped or partially mapped, finish.
  2181. //
  2182. if (*CompletelyUnmappedCount == (ULONG) 0) {
  2183. goto LookupSidsInLocalDomainsFinish;
  2184. }
  2185. }
  2186. //
  2187. // If requested, search the Account Domain.
  2188. //
  2189. if (Options & LSAP_DB_SEARCH_ACCOUNT_DOMAIN) {
  2190. //
  2191. // The Sid and Name of the Account Domain are both configurable, and
  2192. // we need to obtain them from the Policy Object. Now obtain the
  2193. // Account Domain Sid and Name by querying the appropriate
  2194. // Policy Information Class.
  2195. //
  2196. Status = LsapDbLookupGetDomainInfo((PPOLICY_ACCOUNT_DOMAIN_INFO *) &PolicyAccountDomainInfo,
  2197. NULL);
  2198. if (!NT_SUCCESS(Status)) {
  2199. goto LookupSidsInLocalDomainsError;
  2200. }
  2201. //
  2202. // Set up the Trust Information structure for the Account Domain.
  2203. //
  2204. TrustInformation.Sid = PolicyAccountDomainInfo->DomainSid;
  2205. RtlCopyMemory(
  2206. &TrustInformation.Name,
  2207. &PolicyAccountDomainInfo->DomainName,
  2208. sizeof (UNICODE_STRING)
  2209. );
  2210. //
  2211. // Now search the Account Domain for more Sid translations.
  2212. //
  2213. Status = LsapDbLookupSidsInLocalDomain(
  2214. LSAP_DB_SEARCH_ACCOUNT_DOMAIN,
  2215. Count,
  2216. Sids,
  2217. &TrustInformation,
  2218. ReferencedDomains,
  2219. TranslatedNames,
  2220. &UpdatedMappedCount,
  2221. CompletelyUnmappedCount
  2222. );
  2223. if (!NT_SUCCESS(Status)) {
  2224. goto LookupSidsInLocalDomainsError;
  2225. }
  2226. }
  2227. LookupSidsInLocalDomainsFinish:
  2228. //
  2229. // Return the updated total count of Sids mapped.
  2230. //
  2231. *MappedCount = UpdatedMappedCount;
  2232. return(Status);
  2233. LookupSidsInLocalDomainsError:
  2234. if (NT_SUCCESS(Status)) {
  2235. Status = SecondaryStatus;
  2236. }
  2237. goto LookupSidsInLocalDomainsFinish;
  2238. }
  2239. NTSTATUS
  2240. LsapDbLookupSidsInLocalDomain(
  2241. IN ULONG LocalDomain,
  2242. IN ULONG Count,
  2243. IN PLSAPR_SID *Sids,
  2244. IN PLSAPR_TRUST_INFORMATION TrustInformation,
  2245. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2246. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  2247. IN OUT PULONG MappedCount,
  2248. IN OUT PULONG CompletelyUnmappedCount
  2249. )
  2250. /*++
  2251. Routine Description:
  2252. This function looks up Sids in a SAM domain on the local system
  2253. attempts to translate them to names.
  2254. Arguments:
  2255. LocalDomain - Indicates which local domain to look in. Valid values
  2256. are:
  2257. LSAP_DB_SEARCH_BUILT_IN_DOMAIN
  2258. LSAP_DB_SEARCH_ACCOUNT_DOMAIN
  2259. Count - Number of Sids in the Sids array, Note that some of these
  2260. may already have been mapped elsewhere, as specified by the
  2261. MappedCount parameter.
  2262. Sids - Pointer to array of pointers to Sids to be translated.
  2263. Zero or all of the Sids may already have been translated
  2264. elsewhere. If any of the Sids have been translated, the
  2265. Names parameter will point to a location containing a non-NULL
  2266. array of Name translation structures corresponding to the
  2267. Sids. If the nth Sid has been translated, the nth name
  2268. translation structure will contain either a non-NULL name
  2269. or a non-negative offset into the Referenced Domain List. If
  2270. the nth Sid has not yet been translated, the nth name
  2271. translation structure will contain a zero-length name string
  2272. and a negative value for the Referenced Domain List index.
  2273. TrustInformation - Pointer to Trust Information specifying a Domain Sid
  2274. and Name.
  2275. ReferencedDomains - Pointer to a structure in which the list of domains
  2276. used in the translation is maintained. The entries in this structure
  2277. are referenced by the structure returned via the Sids parameter.
  2278. Unlike the Sids parameter, which contains an array entry for each
  2279. translated name, this structure will only contain one component for
  2280. each domain utilized in the translation.
  2281. TranslatedNames - Pointer to a structure in which the translations to Names
  2282. corresponding to the Sids specified on Sids is maintained. The
  2283. nth entry in this array provides a translation (where known) for the
  2284. nth element in the Sids parameter.
  2285. MappedCount - Pointer to location in which a count of the Names that
  2286. have been completely translated is maintained.
  2287. CompletelyUnmappedCount - Pointer to a location in which a count of the
  2288. Names that have not been translated (either partially, by identification
  2289. of a Domain Prefix, or completely) is maintained.
  2290. Return Values:
  2291. NTSTATUS - Standard Nt Result Code
  2292. STATUS_SUCCESS - The call completed successfully. Note that some
  2293. or all of the Sids may remain partially or completely unmapped.
  2294. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  2295. such as memory, to complete the call.
  2296. --*/
  2297. {
  2298. NTSTATUS
  2299. Status,
  2300. SecondaryStatus;
  2301. PLSA_TRANSLATED_NAME_EX
  2302. OutputNames = NULL;
  2303. SAMPR_HANDLE
  2304. LocalSamDomainHandle = NULL;
  2305. PLSAPR_UNICODE_STRING
  2306. Names = NULL;
  2307. PSID_NAME_USE
  2308. Use = NULL;
  2309. ULONG
  2310. RelativeIdCount,
  2311. RelativeIdIndex,
  2312. SidIndex,
  2313. LocalMappedCount = (ULONG) 0,
  2314. DomainSidCount = (ULONG) 0;
  2315. LONG
  2316. DomainIndex = LSA_UNKNOWN_INDEX,
  2317. DomainSidIndexList,
  2318. NextIndex,
  2319. TmpIndex;
  2320. PULONG
  2321. RelativeIds = NULL,
  2322. SidIndices = NULL;
  2323. PLSAPR_SID
  2324. DomainSid = TrustInformation->Sid;
  2325. SAMPR_RETURNED_USTRING_ARRAY
  2326. SamReturnedNames;
  2327. SAMPR_ULONG_ARRAY
  2328. SamReturnedUses;
  2329. UCHAR
  2330. SubAuthorityCountDomain;
  2331. PLSAPR_TRUST_INFORMATION
  2332. FreeTrustInformation = NULL;
  2333. //
  2334. // Make sure the SAM handles have been established.
  2335. //
  2336. Status = LsapOpenSam();
  2337. ASSERT(NT_SUCCESS(Status));
  2338. if ( !NT_SUCCESS( Status ) ) {
  2339. return( Status );
  2340. }
  2341. SamReturnedNames.Count = 0;
  2342. SamReturnedNames.Element = NULL;
  2343. SamReturnedUses.Count = 0;
  2344. SamReturnedUses.Element = NULL;
  2345. OutputNames = (PLSA_TRANSLATED_NAME_EX) TranslatedNames->Names;
  2346. SecondaryStatus = STATUS_SUCCESS;
  2347. if (*MappedCount + *CompletelyUnmappedCount > Count) {
  2348. Status = STATUS_INVALID_PARAMETER;
  2349. goto LookupSidsInLocalDomainError;
  2350. }
  2351. Status = STATUS_SUCCESS;
  2352. if (*CompletelyUnmappedCount == (ULONG) 0) {
  2353. goto LookupSidsInLocalDomainFinish;
  2354. }
  2355. //
  2356. // Now construct a list of Relative Ids to be looked up. Any Sids that
  2357. // do not belong to the specified domain are ignored. Any Sids that
  2358. // are not marked as having unknown Use are ignored, except for certain
  2359. // Well Known Sids that do not have a Well Known Name. These Sids
  2360. // have known Use and a name string length of 0.
  2361. //
  2362. // First, scan the array of Sids looking for completely unmapped ones
  2363. // that have the same domain prefix as the local domain we are dealing
  2364. // with. Note that we can omit any Sid whose Translated Name entry
  2365. // contains a non-zero DomainIndex since the domain of that Sid has
  2366. // already been identified. Once the number of Sids is known, allocate
  2367. // memory for an array of Relative Ids and a parallel array of indices
  2368. // into the original Sids array. The latter array will be used to locate
  2369. // entries in the TranslatedNames array to which information returned by
  2370. // the SamrLookupIdsInDomain() call will be copied.
  2371. //
  2372. for (RelativeIdCount = 0, SidIndex = 0, DomainSidIndexList = -1;
  2373. SidIndex < Count;
  2374. SidIndex++) {
  2375. if ((OutputNames[SidIndex].Use == SidTypeUnknown) &&
  2376. (OutputNames[SidIndex].DomainIndex == LSA_UNKNOWN_INDEX)) {
  2377. if (LsapRtlPrefixSid( (PSID) DomainSid, (PSID) Sids[SidIndex])) {
  2378. RelativeIdCount++;
  2379. } else if (RtlEqualSid( (PSID)DomainSid, (PSID)Sids[SidIndex])) {
  2380. //
  2381. // This is the domain sid itself. Update
  2382. // the output information directly, but don't add
  2383. // it to the list of RIDs to be looked up by SAM.
  2384. //
  2385. // NOTE that we don't yet know what our domain index
  2386. // is. So, just link these entries together and we'll
  2387. // set the index later.
  2388. //
  2389. OutputNames[SidIndex].DomainIndex = DomainSidIndexList;
  2390. DomainSidIndexList = SidIndex;
  2391. OutputNames[SidIndex].Use = SidTypeDomain;
  2392. OutputNames[SidIndex].Name.Buffer = NULL;
  2393. OutputNames[SidIndex].Name.Length = 0;
  2394. OutputNames[SidIndex].Name.MaximumLength = 0;
  2395. LocalMappedCount++;
  2396. DomainSidCount++;
  2397. }
  2398. }
  2399. }
  2400. //
  2401. // If we have any SIDs in this domain, then add it to the
  2402. // referenced domain list.
  2403. //
  2404. if ((RelativeIdCount != 0) || (DomainSidCount != 0)) {
  2405. //
  2406. // At least one Sid has the domain Sid as prefix (or is the
  2407. // domain SID). Add the domain to the list of Referenced
  2408. // Domains and obtain a Domain Index back.
  2409. //
  2410. Status = LsapDbLookupAddListReferencedDomains(
  2411. ReferencedDomains,
  2412. TrustInformation,
  2413. &DomainIndex
  2414. );
  2415. if (!NT_SUCCESS(Status)) {
  2416. goto LookupSidsInLocalDomainError;
  2417. }
  2418. //
  2419. // If any of the sids were this domain's sid, then they
  2420. // already have their OutputNames[] entry filled in except
  2421. // that the DomainIndex was unkown. It is now known, so
  2422. // fill it in. Any such entries to change have been linked
  2423. // together using DomainSidIndexList as a listhead.
  2424. //
  2425. for (NextIndex = DomainSidIndexList;
  2426. NextIndex != -1;
  2427. NextIndex = TmpIndex ) {
  2428. TmpIndex = OutputNames[NextIndex].DomainIndex;
  2429. OutputNames[NextIndex].DomainIndex = DomainIndex;
  2430. }
  2431. }
  2432. //
  2433. // If any of the remaining Sids have the specified Local
  2434. // domain Sid as prefix Sid, look them up
  2435. //
  2436. if (RelativeIdCount != 0) {
  2437. //
  2438. // Allocate memory for the Relative Id and cross reference arrays
  2439. //
  2440. RelativeIds = LsapAllocateLsaHeap( RelativeIdCount * sizeof(ULONG));
  2441. Status = STATUS_INSUFFICIENT_RESOURCES;
  2442. if (RelativeIds == NULL) {
  2443. goto LookupSidsInLocalDomainError;
  2444. }
  2445. SidIndices = LsapAllocateLsaHeap( RelativeIdCount * sizeof(ULONG));
  2446. if (SidIndices == NULL) {
  2447. goto LookupSidsInLocalDomainError;
  2448. }
  2449. Status = STATUS_SUCCESS;
  2450. //
  2451. // Obtain the SubAuthorityCount for the Domain Sid
  2452. //
  2453. SubAuthorityCountDomain = *RtlSubAuthorityCountSid( (PSID) DomainSid );
  2454. //
  2455. // Now setup the array of Relative Ids to be looked up, recording
  2456. // in the SidIndices array the index of the corresponding Sid within the
  2457. // original Sids array. Set the DomainIndex field for those Sids
  2458. // eligible for the SAM lookup.
  2459. //
  2460. for (RelativeIdIndex = 0, SidIndex = 0;
  2461. (RelativeIdIndex < RelativeIdCount) && (SidIndex < Count);
  2462. SidIndex++) {
  2463. if ((OutputNames[SidIndex].Use == SidTypeUnknown) &&
  2464. (OutputNames[SidIndex].DomainIndex == LSA_UNKNOWN_INDEX)) {
  2465. if (LsapRtlPrefixSid( (PSID) DomainSid, (PSID) Sids[SidIndex] )) {
  2466. SidIndices[RelativeIdIndex] = SidIndex;
  2467. RelativeIds[RelativeIdIndex] =
  2468. *RtlSubAuthoritySid(
  2469. (PSID) Sids[SidIndex],
  2470. SubAuthorityCountDomain
  2471. );
  2472. OutputNames[SidIndex].DomainIndex = DomainIndex;
  2473. RelativeIdIndex++;
  2474. }
  2475. }
  2476. }
  2477. //
  2478. // Lookup the Sids in the specified SAM Domain.
  2479. //
  2480. if (LocalDomain == LSAP_DB_SEARCH_BUILT_IN_DOMAIN ) {
  2481. LocalSamDomainHandle = LsapBuiltinDomainHandle;
  2482. } else {
  2483. ASSERT(LocalDomain == LSAP_DB_SEARCH_ACCOUNT_DOMAIN);
  2484. LocalSamDomainHandle = LsapAccountDomainHandle;
  2485. }
  2486. //
  2487. // Call SAM to lookup the Relative Id's
  2488. //
  2489. Status = SamrLookupIdsInDomain(
  2490. LocalSamDomainHandle,
  2491. RelativeIdCount,
  2492. RelativeIds,
  2493. &SamReturnedNames,
  2494. &SamReturnedUses
  2495. );
  2496. if (!NT_SUCCESS(Status)) {
  2497. if ( Status == STATUS_INVALID_SERVER_STATE ) {
  2498. Status = SamrLookupIdsInDomain(
  2499. LocalSamDomainHandle,
  2500. RelativeIdCount,
  2501. RelativeIds,
  2502. &SamReturnedNames,
  2503. &SamReturnedUses
  2504. );
  2505. }
  2506. //
  2507. // The only error allowed is STATUS_NONE_MAPPED. Filter this out.
  2508. //
  2509. if (Status != STATUS_NONE_MAPPED) {
  2510. goto LookupSidsInLocalDomainError;
  2511. }
  2512. Status = STATUS_SUCCESS;
  2513. }
  2514. //
  2515. // Now copy the information returned from SAM into the output
  2516. // Translated Sids array. As we go, compute a count of the names
  2517. // mapped by SAM.
  2518. //
  2519. for (RelativeIdIndex = 0;
  2520. RelativeIdIndex < SamReturnedNames.Count;
  2521. RelativeIdIndex++) {
  2522. SidIndex = SidIndices[RelativeIdIndex];
  2523. //
  2524. // Copy the Sid Use. If the Sid was mapped by this SAM call, copy
  2525. // its Name and increment the count of Sids mapped by this SAM call.
  2526. // Note that we don't need to set the DomainIndex since we did so
  2527. // earlier.
  2528. //
  2529. OutputNames[SidIndex].Use = SamReturnedUses.Element[RelativeIdIndex];
  2530. if (OutputNames[SidIndex].Use != SidTypeUnknown) {
  2531. Status = LsapRpcCopyUnicodeString(
  2532. NULL,
  2533. &OutputNames[SidIndex].Name,
  2534. (PUNICODE_STRING) &SamReturnedNames.Element[RelativeIdIndex]
  2535. );
  2536. if (!NT_SUCCESS(Status)) {
  2537. break;
  2538. }
  2539. LocalMappedCount++;
  2540. } else {
  2541. //
  2542. // This sid doesn't exist; if this search is on a domain
  2543. // controller, then we must consider that this sid maybe
  2544. // part of a sid history, thus we shouldn't map it
  2545. //
  2546. if ( (LsapProductType == NtProductLanManNt)
  2547. && (LocalDomain == LSAP_DB_SEARCH_ACCOUNT_DOMAIN) ) {
  2548. RelativeIdCount--;
  2549. }
  2550. }
  2551. }
  2552. if (!NT_SUCCESS(Status)) {
  2553. goto LookupSidsInLocalDomainError;
  2554. }
  2555. }
  2556. //
  2557. // Update the Mapped and Completely Unmapped Counts. To the Mapped Count
  2558. // add in the number of Sids that SAM completely identified. From the
  2559. // Completely Unmapped Count subtract the number of Sids presented to
  2560. // Sam, since all of these will be at least partially translated.
  2561. //
  2562. *MappedCount += LocalMappedCount;
  2563. *CompletelyUnmappedCount -= (RelativeIdCount + DomainSidCount);
  2564. LookupSidsInLocalDomainFinish:
  2565. //
  2566. // If necessary, free the Lsa Heap buffer allocated for the RelativeIds
  2567. // and SidIndices arrays.
  2568. //
  2569. if (RelativeIds != NULL) {
  2570. LsapFreeLsaHeap( RelativeIds );
  2571. RelativeIds = NULL;
  2572. }
  2573. if (SidIndices != NULL) {
  2574. LsapFreeLsaHeap( SidIndices );
  2575. SidIndices = NULL;
  2576. }
  2577. //
  2578. // If necessary, free the Names array returned from SAM.
  2579. //
  2580. if ( SamReturnedNames.Count != 0 ) {
  2581. SamIFree_SAMPR_RETURNED_USTRING_ARRAY ( &SamReturnedNames );
  2582. SamReturnedNames.Count = 0;
  2583. }
  2584. //
  2585. // If necessary, free the Uses array returned from SAM.
  2586. //
  2587. if ( SamReturnedUses.Count != 0 ) {
  2588. SamIFree_SAMPR_ULONG_ARRAY ( &SamReturnedUses );
  2589. SamReturnedUses.Count = 0;
  2590. }
  2591. return(Status);
  2592. LookupSidsInLocalDomainError:
  2593. //
  2594. // If necessary, free memory for the OutputTrustInformation Domain
  2595. // Name Buffer and Sid Buffer.
  2596. //
  2597. if (DomainIndex >= 0) {
  2598. FreeTrustInformation = &ReferencedDomains->Domains[DomainIndex];
  2599. if (FreeTrustInformation->Sid != NULL) {
  2600. MIDL_user_free( FreeTrustInformation->Sid );
  2601. FreeTrustInformation->Sid = NULL;
  2602. }
  2603. if (FreeTrustInformation->Name.Buffer != NULL) {
  2604. MIDL_user_free( FreeTrustInformation->Name.Buffer );
  2605. FreeTrustInformation->Name.Buffer = NULL;
  2606. FreeTrustInformation->Name.Length = 0;
  2607. FreeTrustInformation->Name.MaximumLength = 0;
  2608. }
  2609. }
  2610. //
  2611. // If necessary, free the Name buffer in each of the OutputNames entries
  2612. // written by this routine and set the Name slot to NULL.
  2613. //
  2614. for (RelativeIdIndex = 0;
  2615. RelativeIdIndex < SamReturnedNames.Count;
  2616. RelativeIdIndex++) {
  2617. SidIndex = SidIndices[RelativeIdIndex];
  2618. if (OutputNames[SidIndex].Name.Buffer != NULL) {
  2619. MIDL_user_free( OutputNames[SidIndex].Name.Buffer );
  2620. OutputNames[SidIndex].Name.Buffer = NULL;
  2621. OutputNames[SidIndex].Name.Length = 0;
  2622. OutputNames[SidIndex].Name.MaximumLength = 0;
  2623. }
  2624. }
  2625. //
  2626. // Restore the Use field for each entry we wrote to back to SidType
  2627. // Unknown.
  2628. //
  2629. for (RelativeIdIndex = 0;
  2630. RelativeIdIndex < SamReturnedNames.Count;
  2631. RelativeIdIndex++) {
  2632. SidIndex = SidIndices[RelativeIdIndex];
  2633. if (OutputNames[SidIndex].Name.Buffer != NULL) {
  2634. MIDL_user_free( OutputNames[SidIndex].Name.Buffer );
  2635. OutputNames[SidIndex].Name.Buffer = NULL;
  2636. OutputNames[SidIndex].Name.Length = 0;
  2637. OutputNames[SidIndex].Name.MaximumLength = 0;
  2638. }
  2639. OutputNames[SidIndex].Use = SidTypeUnknown;
  2640. OutputNames[SidIndex].DomainIndex = LSA_UNKNOWN_INDEX;
  2641. }
  2642. if (NT_SUCCESS(Status)) {
  2643. Status = SecondaryStatus;
  2644. }
  2645. goto LookupSidsInLocalDomainFinish;
  2646. }
  2647. NTSTATUS
  2648. LsapDbLookupSidsInPrimaryDomain(
  2649. IN ULONG Count,
  2650. IN PLSAPR_SID *Sids,
  2651. IN PLSAPR_TRUST_INFORMATION TrustInformation,
  2652. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2653. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  2654. IN LSAP_LOOKUP_LEVEL LookupLevel,
  2655. IN OUT PULONG MappedCount,
  2656. IN OUT PULONG CompletelyUnmappedCount,
  2657. OUT NTSTATUS *NonFatalStatus,
  2658. OUT BOOLEAN *fDownlevelSecureChannel
  2659. )
  2660. /*++
  2661. Routine Description:
  2662. This function attempts to translate Sids in a Primary Domain. A
  2663. Trusted Domain object must exist for the domain in the local Policy
  2664. Database. This object will be used to access the Domain's list of
  2665. Controllers and one or more callouts will be made to access the LSA
  2666. Policy Databases on these Controllers.
  2667. Arguments:
  2668. Count - Number of Sids in the Sids array, Note that some of these
  2669. may already have been mapped elsewhere, as specified by the
  2670. MappedCount parameter.
  2671. Sids - Pointer to array of pointers to Sids to be translated.
  2672. Zero or all of the Sids may already have been translated
  2673. elsewhere. dd esp la If any of the Sids have been translated, the
  2674. Names parameter will point to a location containing a non-NULL
  2675. array of Name translation structures corresponding to the
  2676. Sids. If the nth Sid has been translated, the nth name
  2677. translation structure will contain either a non-NULL name
  2678. or a non-negative offset into the Referenced Domain List. If
  2679. the nth Sid has not yet been translated, the nth name
  2680. translation structure will contain a zero-length name string
  2681. and a negative value for the Referenced Domain List index.
  2682. TrustInformation - Specifies the name and Sid of the Primary Domain.
  2683. ReferencedDomains - Pointer to a structure in which the list of domains
  2684. used in the translation is maintained. The entries in this structure
  2685. are referenced by the structure returned via the Sids parameter.
  2686. Unlike the Sids parameter, which contains an array entry for each
  2687. translated name, this structure will only contain one component for
  2688. each domain utilized in the translation.
  2689. TranslatedNames - Pointer to a structure in which the translations to Names
  2690. corresponding to the Sids specified on Sids is maintained. The
  2691. nth entry in this array provides a translation (where known) for the
  2692. nth element in the Sids parameter.
  2693. LookupLevel - Specifies the Level of Lookup to be performed on this
  2694. machine. Values of this field are are follows:
  2695. LsapLookupPDC - Second Level Lookup performed on a Primary Domain
  2696. Controller. The lookup searches the Account Domain of the
  2697. SAM Database on the controller. If not all Sids or Names are
  2698. found, the Trusted Domain List (TDL) is obtained from the
  2699. LSA's Policy Database and Third Level lookups are performed
  2700. via "handoff" to each Trusted Domain in the List.
  2701. LsapLookupTDL - Third Level Lookup performed on a controller
  2702. for a Trusted Domain. The lookup searches the Account Domain of
  2703. the SAM Database on the controller only.
  2704. NOTE: LsapLookupWksta is not valid for this parameter.
  2705. MappedCount - Pointer to location in which a count of the Names that
  2706. have been completely translated is maintained.
  2707. CompletelyUnmappedCount - Pointer to a location in which a count of the
  2708. Names that have not been translated (either partially, by identification
  2709. of a Domain Prefix, or completely) is maintained.
  2710. NonFatalStatus - a status to indicate reasons why no sids could have been
  2711. resolved
  2712. fDownlevelSecureChannel - TRUE if secure channel DC is nt4 or below; FALSE
  2713. otherwise
  2714. Return Values:
  2715. NTSTATUS - Standard Nt Result Code
  2716. STATUS_SUCCESS - The call completed successfully. Note that some
  2717. or all of the Sids may remain partially or completely unmapped.
  2718. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  2719. such as memory, to complete the call.
  2720. --*/
  2721. {
  2722. NTSTATUS Status = STATUS_SUCCESS;
  2723. NTSTATUS SecondaryStatus = STATUS_SUCCESS;
  2724. ULONG NextLevelCount;
  2725. ULONG NextLevelMappedCount;
  2726. ULONG SidIndex;
  2727. ULONG NextLevelSidIndex;
  2728. PLSAPR_REFERENCED_DOMAIN_LIST NextLevelReferencedDomains = NULL;
  2729. PLSAPR_REFERENCED_DOMAIN_LIST OutputReferencedDomains = NULL;
  2730. PLSA_TRANSLATED_NAME_EX NextLevelNames = NULL;
  2731. PLSAPR_SID *NextLevelSids = NULL;
  2732. LONG FirstEntryIndex;
  2733. PULONG SidIndices = NULL;
  2734. BOOLEAN PartialSidTranslationsAttempted = FALSE;
  2735. ULONG ServerRevision = 0;
  2736. LSAPR_TRUST_INFORMATION_EX TrustInfoEx;
  2737. LsapConvertTrustToEx(&TrustInfoEx, TrustInformation);
  2738. *NonFatalStatus = STATUS_SUCCESS;
  2739. // Assume we don't go to the GC
  2740. *fDownlevelSecureChannel = FALSE;
  2741. //
  2742. // If there are no completely unmapped Sids remaining, just return.
  2743. //
  2744. if (*CompletelyUnmappedCount == (ULONG) 0) {
  2745. goto LookupSidsInPrimaryDomainFinish;
  2746. }
  2747. NextLevelCount = *CompletelyUnmappedCount;
  2748. //
  2749. // Allocate an array to hold the indices of unmapped Sids
  2750. // relative to the original Sids and TranslatedNames->Names
  2751. // arrays.
  2752. //
  2753. SidIndices = MIDL_user_allocate(NextLevelCount * sizeof(ULONG));
  2754. Status = STATUS_INSUFFICIENT_RESOURCES;
  2755. if (SidIndices == NULL) {
  2756. goto LookupSidsInPrimaryDomainError;
  2757. }
  2758. //
  2759. // Allocate an array for the Sids to be looked up at the Domain
  2760. // Controller.
  2761. //
  2762. NextLevelSids = MIDL_user_allocate( sizeof(PSID) * NextLevelCount );
  2763. if (NextLevelSids == NULL) {
  2764. goto LookupSidsInPrimaryDomainError;
  2765. }
  2766. Status = STATUS_SUCCESS;
  2767. //
  2768. // Now scan the original array of Names and its parallel
  2769. // Translated Sids array. Copy over any Sids that are
  2770. // completely unmapped.
  2771. //
  2772. NextLevelSidIndex = (ULONG) 0;
  2773. for (SidIndex = 0;
  2774. SidIndex < Count && NextLevelSidIndex < NextLevelCount;
  2775. SidIndex++) {
  2776. if (LsapDbCompletelyUnmappedName(&TranslatedNames->Names[SidIndex])) {
  2777. NextLevelSids[NextLevelSidIndex] = Sids[SidIndex];
  2778. SidIndices[NextLevelSidIndex] = SidIndex;
  2779. NextLevelSidIndex++;
  2780. }
  2781. }
  2782. NextLevelMappedCount = (ULONG) 0;
  2783. Status = LsaDbLookupSidChainRequest(&TrustInfoEx,
  2784. NextLevelCount,
  2785. (PSID *) NextLevelSids,
  2786. (PLSA_REFERENCED_DOMAIN_LIST *) &NextLevelReferencedDomains,
  2787. &NextLevelNames,
  2788. LookupLevel,
  2789. &NextLevelMappedCount,
  2790. &ServerRevision
  2791. );
  2792. //
  2793. // If the callout to LsaLookupSids() was unsuccessful, disregard
  2794. // the error and set the domain name for any Sids having this
  2795. // domain Sid as prefix sid. We still want to return translations
  2796. // of Sids we have so far even if we are unable to callout to another
  2797. // LSA.
  2798. //
  2799. //
  2800. // Make sure we note the server revision
  2801. //
  2802. if ( 0 != ServerRevision ) {
  2803. if ( ServerRevision & LSA_CLIENT_PRE_NT5 ) {
  2804. *fDownlevelSecureChannel = TRUE;
  2805. }
  2806. }
  2807. if (!NT_SUCCESS(Status) && Status != STATUS_NONE_MAPPED) {
  2808. //
  2809. // Let the caller know there is a trust problem
  2810. //
  2811. if ( LsapDbIsStatusConnectionFailure(Status) ) {
  2812. *NonFatalStatus = Status;
  2813. }
  2814. Status = STATUS_SUCCESS;
  2815. goto LookupSidsInPrimaryDomainFinish;
  2816. }
  2817. //
  2818. // Cache any sids that came back
  2819. //
  2820. (void) LsapDbUpdateCacheWithSids(
  2821. NextLevelSids,
  2822. NextLevelCount,
  2823. NextLevelReferencedDomains,
  2824. NextLevelNames
  2825. );
  2826. //
  2827. // The callout to LsaLookupSids() was successful. We now have
  2828. // an additional list of Referenced Domains containing the
  2829. // Primary Domain and/or one or more of its Trusted Domains.
  2830. // Merge the two Referenced Domain Lists together, noting that
  2831. // since they are disjoint, the second list is simply
  2832. // concatenated with the first. The index of the first entry
  2833. // of the second list will be used to adjust all of the
  2834. // Domain Index entries in the Translated Names entries.
  2835. // Note that since the memory for the graph of the first
  2836. // Referenced Domain list has been allocated as individual
  2837. // nodes, we specify that the nodes in this graph can be
  2838. // referenced by the output Referenced Domain list.
  2839. //
  2840. Status = LsapDbLookupMergeDisjointReferencedDomains(
  2841. ReferencedDomains,
  2842. NextLevelReferencedDomains,
  2843. &OutputReferencedDomains,
  2844. LSAP_DB_USE_FIRST_MERGAND_GRAPH
  2845. );
  2846. if (!NT_SUCCESS(Status)) {
  2847. goto LookupSidsInPrimaryDomainError;
  2848. }
  2849. FirstEntryIndex = ReferencedDomains->Entries;
  2850. //
  2851. // Now update the original list of Translated Names. We
  2852. // update each entry that has newly been translated by copying
  2853. // the entry from the new list and adjusting its Referenced
  2854. // Domain List Index upwards by adding the index of the first
  2855. // entry in the Next level List..
  2856. //
  2857. for( NextLevelSidIndex = 0;
  2858. NextLevelSidIndex < NextLevelCount;
  2859. NextLevelSidIndex++ ) {
  2860. if ( !LsapDbCompletelyUnmappedName(&NextLevelNames[NextLevelSidIndex]) ) {
  2861. SidIndex = SidIndices[NextLevelSidIndex];
  2862. if (NextLevelNames[NextLevelSidIndex].Use != SidTypeUnknown) {
  2863. TranslatedNames->Names[SidIndex].Use
  2864. = NextLevelNames[NextLevelSidIndex].Use;
  2865. Status = LsapRpcCopyUnicodeString(
  2866. NULL,
  2867. (PUNICODE_STRING) &TranslatedNames->Names[SidIndex].Name,
  2868. &NextLevelNames[NextLevelSidIndex].Name
  2869. );
  2870. if (!NT_SUCCESS(Status)) {
  2871. break;
  2872. }
  2873. }
  2874. TranslatedNames->Names[SidIndex].DomainIndex =
  2875. FirstEntryIndex +
  2876. NextLevelNames[NextLevelSidIndex].DomainIndex;
  2877. //
  2878. // Update the count of completely unmapped Sids.
  2879. //
  2880. (*CompletelyUnmappedCount)--;
  2881. }
  2882. }
  2883. //
  2884. // Update the Referenced Domain List if a new one was produced
  2885. // from the merge. We retain the original top-level structure.
  2886. // We do this regardless of whether we succeeded or failed, so
  2887. // that we are guarenteed to get it cleaned up.
  2888. //
  2889. if (OutputReferencedDomains != NULL) {
  2890. if (ReferencedDomains->Domains != NULL) {
  2891. MIDL_user_free( ReferencedDomains->Domains );
  2892. ReferencedDomains->Domains = NULL;
  2893. }
  2894. *ReferencedDomains = *OutputReferencedDomains;
  2895. MIDL_user_free( OutputReferencedDomains );
  2896. OutputReferencedDomains = NULL;
  2897. }
  2898. if (!NT_SUCCESS(Status)) {
  2899. goto LookupSidsInPrimaryDomainError;
  2900. }
  2901. //
  2902. // Update the Mapped Count and close the Controller Policy
  2903. // Handle.
  2904. //
  2905. *MappedCount += NextLevelMappedCount;
  2906. LookupSidsInPrimaryDomainFinish:
  2907. //
  2908. // We can return partial translations for Sids that have the specified
  2909. // Domain Sid as Prefix Sid. We do this provided there has been
  2910. // no reported error. Errors resulting from callout to another
  2911. // LSA will have been suppressed.
  2912. //
  2913. if (NT_SUCCESS(Status) &&
  2914. (*MappedCount < Count) &&
  2915. !PartialSidTranslationsAttempted) {
  2916. SecondaryStatus = LsapDbLookupTranslateUnknownSidsInDomain(
  2917. Count,
  2918. Sids,
  2919. TrustInformation,
  2920. ReferencedDomains,
  2921. TranslatedNames,
  2922. LookupLevel,
  2923. MappedCount,
  2924. CompletelyUnmappedCount
  2925. );
  2926. PartialSidTranslationsAttempted = TRUE;
  2927. if (!NT_SUCCESS(SecondaryStatus)) {
  2928. goto LookupSidsInPrimaryDomainError;
  2929. }
  2930. }
  2931. //
  2932. // If necessary, free the Next Level Referenced Domain List.
  2933. // Note that this structure is allocated(all_nodes) since it was
  2934. // allocated by the client side of the Domain Controller LSA.
  2935. //
  2936. if (NextLevelReferencedDomains != NULL) {
  2937. MIDL_user_free( NextLevelReferencedDomains );
  2938. NextLevelReferencedDomains = NULL;
  2939. }
  2940. //
  2941. // If necessary, free the Next Level Sids array. We only free the
  2942. // top level.
  2943. //
  2944. if (NextLevelSids != NULL) {
  2945. MIDL_user_free( NextLevelSids );
  2946. NextLevelSids = NULL;
  2947. }
  2948. //
  2949. // If necessary, free the Next Level Translated Names array.
  2950. // Note that this array is allocated(all_nodes).
  2951. //
  2952. if (NextLevelNames != NULL) {
  2953. MIDL_user_free( NextLevelNames );
  2954. NextLevelNames = NULL;
  2955. }
  2956. //
  2957. // If necessary, free the array that maps Sid Indices from the
  2958. // Next Level to the Current Level.
  2959. //
  2960. if (SidIndices != NULL) {
  2961. MIDL_user_free( SidIndices );
  2962. SidIndices = NULL;
  2963. }
  2964. return(Status);
  2965. LookupSidsInPrimaryDomainError:
  2966. //
  2967. // If the primary status was a success code, but the secondary
  2968. // status was an error, propagate the secondary status.
  2969. //
  2970. if ((!NT_SUCCESS(SecondaryStatus)) && NT_SUCCESS(Status)) {
  2971. Status = SecondaryStatus;
  2972. }
  2973. goto LookupSidsInPrimaryDomainFinish;
  2974. }
  2975. NTSTATUS
  2976. LsapDbLookupSidsInTrustedDomains(
  2977. IN ULONG Count,
  2978. IN PLSAPR_SID *Sids,
  2979. IN BOOLEAN fIncludeIntraforest,
  2980. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2981. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  2982. IN LSAP_LOOKUP_LEVEL LookupLevel,
  2983. IN OUT PULONG MappedCount,
  2984. IN OUT PULONG CompletelyUnmappedCount,
  2985. OUT NTSTATUS *NonFatalStatus
  2986. )
  2987. /*++
  2988. Routine Description:
  2989. This function attempts to lookup Sids to see if they belong to
  2990. any of the Domains that are trusted by the Domain for which this
  2991. machine is a DC.
  2992. Arguments:
  2993. Sids - Pointer to an array of Sids to be looked up.
  2994. Count - Number of Sids in the Sids array, Note that some of these
  2995. may already have been mapped elsewhere, as specified by the
  2996. MappedCount parameter.
  2997. fIncludeIntraforest -- if TRUE, trusted domains in our local forest
  2998. are searched.
  2999. ReferencedDomains - Pointer to a Referenced Domain List structure.
  3000. The structure references an array of zero or more Trust Information
  3001. entries, one per referenced domain. This array will be appended to
  3002. or reallocated if necessary.
  3003. TranslatedNames - Pointer to structure that optionally references a list
  3004. of name translations for some of the Sids in the Sids array.
  3005. LookupLevel - Specifies the Level of Lookup to be performed on this
  3006. machine. Values of this field are are follows:
  3007. LsapLookupPDC - Second Level Lookup performed on a Primary Domain
  3008. Controller. The lookup searches the Account Domain of the
  3009. SAM Database on the controller. If not all Sids or Names are
  3010. found, the Trusted Domain List (TDL) is obtained from the
  3011. LSA's Policy Database and Third Level lookups are performed
  3012. via "handoff" to each Trusted Domain in the List.
  3013. LsapLookupTDL - Third Level Lookup performed on a controller
  3014. for a Trusted Domain. The lookup searches the Account Domain of
  3015. the SAM Database on the controller only.
  3016. NOTE: LsapLookupWksta is not valid for this parameter.
  3017. MappedCount - Pointer to location containing the number of Sids
  3018. in the Sids array that have already been mapped. This number
  3019. will be updated to reflect additional mapping done by this
  3020. routine.
  3021. CompletelyUnmappedCount - Pointer to location containing the
  3022. count of completely unmapped Sids. A Sid is completely unmapped
  3023. if it is unknown and also its Domain Prefix Sid is not recognized.
  3024. This count is updated on exit, the number of completely unmapped
  3025. Sids whose Domain Prefices are identified by this routine being
  3026. subtracted from the input value.
  3027. NonFatalStatus - a status to indicate reasons why no sids could have been
  3028. resolved
  3029. Return Values:
  3030. NTSTATUS - Standard Nt Result Code
  3031. STATUS_SUCCESS - The call completed successfully. Note that
  3032. some or all of the Sids may remain unmapped.
  3033. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  3034. such as memory, to complete the call.
  3035. --*/
  3036. {
  3037. NTSTATUS Status = STATUS_SUCCESS;
  3038. PLSAP_DB_LOOKUP_WORK_LIST WorkList = NULL;
  3039. *NonFatalStatus = STATUS_SUCCESS;
  3040. //
  3041. // Build a WorkList for this Lookup and put it on the Work Queue.
  3042. //
  3043. // NOTE: This routine does not need to hold the Lookup Work Queue
  3044. // lock to ensure validity of the WorkList pointer, because the
  3045. // pointer remains valid until this routine frees it via
  3046. // LsapDbLookupDeleteWorkList(). Although other threads may
  3047. // process the WorkList, do not delete it.
  3048. //
  3049. // A called routine must acquire the lock in order to access
  3050. // the WorkList after it has been added to the Work Queue.
  3051. //
  3052. Status = LsapDbLookupSidsBuildWorkList(
  3053. Count,
  3054. Sids,
  3055. fIncludeIntraforest,
  3056. ReferencedDomains,
  3057. TranslatedNames,
  3058. LookupLevel,
  3059. MappedCount,
  3060. CompletelyUnmappedCount,
  3061. &WorkList
  3062. );
  3063. if (!NT_SUCCESS(Status)) {
  3064. //
  3065. // If no Work List has been built because there are no
  3066. // eligible domains to search, exit, suppressing the error.
  3067. if (Status == STATUS_NONE_MAPPED) {
  3068. Status = STATUS_SUCCESS;
  3069. goto LookupSidsInTrustedDomainsFinish;
  3070. }
  3071. goto LookupSidsInTrustedDomainsError;
  3072. }
  3073. //
  3074. // Start the work, by dispatching one or more worker threads
  3075. // if necessary.
  3076. //
  3077. Status = LsapDbLookupDispatchWorkerThreads( WorkList );
  3078. if (!NT_SUCCESS(Status)) {
  3079. goto LookupSidsInTrustedDomainsError;
  3080. }
  3081. //
  3082. // Wait for completion/termination of all items on the Work List.
  3083. //
  3084. Status = LsapDbLookupAwaitCompletionWorkList( WorkList );
  3085. if (!NT_SUCCESS(Status)) {
  3086. goto LookupSidsInTrustedDomainsError;
  3087. }
  3088. LookupSidsInTrustedDomainsFinish:
  3089. if ( WorkList &&
  3090. !NT_SUCCESS( WorkList->NonFatalStatus ) )
  3091. {
  3092. //
  3093. // Propogate the error as non fatal
  3094. //
  3095. //
  3096. *NonFatalStatus = WorkList->NonFatalStatus;
  3097. }
  3098. //
  3099. // If a Work List was created, delete it from the Work Queue
  3100. //
  3101. if (WorkList != NULL) {
  3102. Status = LsapDbLookupDeleteWorkList( WorkList );
  3103. WorkList = NULL;
  3104. }
  3105. return(Status);
  3106. LookupSidsInTrustedDomainsError:
  3107. goto LookupSidsInTrustedDomainsFinish;
  3108. }
  3109. NTSTATUS
  3110. LsapDbLookupTranslateUnknownSidsInDomain(
  3111. IN ULONG Count,
  3112. IN PLSAPR_SID *Sids,
  3113. IN PLSAPR_TRUST_INFORMATION TrustInformation,
  3114. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3115. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  3116. IN LSAP_LOOKUP_LEVEL LookupLevel,
  3117. IN OUT PULONG MappedCount,
  3118. IN OUT PULONG CompletelyUnmappedCount
  3119. )
  3120. /*++
  3121. Routine Description:
  3122. This function looks among the unknown Sids in the given list and
  3123. translates the Domain Name for any whose Domain Prefix Sid matches
  3124. the given Domain Sid.
  3125. Arguments:
  3126. Count - Number of Sids in the Sids array, Note that some of these
  3127. may already have been mapped elsewhere, as specified by the
  3128. MappedCount parameter.
  3129. Sids - Pointer to array of pointers to Sids to be translated.
  3130. Zero or all of the Sids may already have been translated
  3131. elsewhere. If any of the Sids have been translated, the
  3132. Names parameter will point to a location containing a non-NULL
  3133. array of Name translation structures corresponding to the
  3134. Sids. If the nth Sid has been translated, the nth name
  3135. translation structure will contain either a non-NULL name
  3136. or a non-negative offset into the Referenced Domain List. If
  3137. the nth Sid has not yet been translated, the nth name
  3138. translation structure will contain a zero-length name string
  3139. and a negative value for the Referenced Domain List index.
  3140. TrustInformation - Pointer to Trust Information specifying a Domain Sid
  3141. and Name.
  3142. ReferencedDomains - Pointer to a Referenced Domain List structure.
  3143. The structure references an array of zero or more Trust Information
  3144. entries, one per referenced domain. This array will be appended to
  3145. or reallocated if necessary.
  3146. TranslatedNames - Pointer to structure that optionally references a list
  3147. of name translations for some of the Sids in the Sids array.
  3148. MappedCount - Pointer to location containing the number of Sids
  3149. in the Sids array that have already been mapped. This number
  3150. will be updated to reflect additional mapping done by this
  3151. routine.
  3152. CompletelyUnmappedCount - Pointer to location containing the
  3153. count of completely unmapped Sids. A Sid is completely unmapped
  3154. if it is unknown and also its Domain Prefix Sid is not recognized.
  3155. This count is updated on exit, the number of completely unmapped
  3156. Sids whose Domain Prefices are identified by this routine being
  3157. subtracted from the input value.
  3158. Return Values:
  3159. NTSTATUS - Standard Nt Result Code
  3160. STATUS_SUCCESS - The call completed successfully. Note that some
  3161. or all of the Sids may remain partially or completely unmapped.
  3162. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  3163. such as memory, to complete the call.
  3164. --*/
  3165. {
  3166. NTSTATUS Status = STATUS_SUCCESS;
  3167. ULONG RemainingCompletelyUnmappedCount;
  3168. ULONG SidIndex;
  3169. PSID DomainSid = TrustInformation->Sid;
  3170. BOOLEAN DomainAlreadyAdded = FALSE;
  3171. LONG DomainIndex = 0;
  3172. //
  3173. // Scan the array of Sids looking for ones whose domain has not been
  3174. // found.
  3175. //
  3176. for( SidIndex = 0,
  3177. RemainingCompletelyUnmappedCount = *CompletelyUnmappedCount;
  3178. (RemainingCompletelyUnmappedCount > 0) && (SidIndex < Count);
  3179. SidIndex++) {
  3180. //
  3181. // Check if this Sid is completely unmapped (i.e. its domain
  3182. // has not yet been identified.
  3183. //
  3184. if (LsapDbCompletelyUnmappedName(&TranslatedNames->Names[SidIndex])) {
  3185. //
  3186. // Found a completely unmapped Sid. If it belongs to the
  3187. // specified Domain, add the Domain to the Referenced Domain
  3188. // list if we have not already done so.
  3189. //
  3190. if (LsapRtlPrefixSid( DomainSid, (PSID) Sids[SidIndex])) {
  3191. if (!DomainAlreadyAdded) {
  3192. Status = LsapDbLookupAddListReferencedDomains(
  3193. ReferencedDomains,
  3194. TrustInformation,
  3195. &DomainIndex
  3196. );
  3197. if (!NT_SUCCESS(Status)) {
  3198. break;
  3199. }
  3200. DomainAlreadyAdded = TRUE;
  3201. }
  3202. //
  3203. // Reference the domain from the TranslatedNames entry
  3204. //
  3205. TranslatedNames->Names[SidIndex].DomainIndex = DomainIndex;
  3206. //
  3207. // This Sid is now partially translated, so reduce the
  3208. // count of completely unmapped Sids.
  3209. //
  3210. (*CompletelyUnmappedCount)--;
  3211. }
  3212. //
  3213. // Decrement count of completely unmapped Sids scanned.
  3214. //
  3215. RemainingCompletelyUnmappedCount--;
  3216. }
  3217. }
  3218. return(Status);
  3219. }
  3220. NTSTATUS
  3221. LsapDbLookupSidsInGlobalCatalog(
  3222. IN ULONG Count,
  3223. IN PLSAPR_SID *Sids,
  3224. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3225. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  3226. IN OUT PULONG MappedCount,
  3227. IN OUT PULONG CompletelyUnmappedCount,
  3228. IN BOOLEAN fDoSidHistory,
  3229. OUT NTSTATUS *NonFatalStatus
  3230. )
  3231. /*++
  3232. Routine Description:
  3233. This routine looks the list of sids that have yet to be resolved.
  3234. If the any of the sids belong to domain that are stored in the DS,
  3235. then therse sids are packages up and sent to a GC for translation.
  3236. Note: this will resolve sids from domains that we trust directly and
  3237. indirectly
  3238. Arguments:
  3239. Sids - Pointer to an array of Sids to be looked up.
  3240. Count - Number of Sids in the Sids array, Note that some of these
  3241. may already have been mapped elsewhere, as specified by the
  3242. MappedCount parameter.
  3243. ReferencedDomains - Pointer to a Referenced Domain List structure.
  3244. The structure references an array of zero or more Trust Information
  3245. entries, one per referenced domain. This array will be appended to
  3246. or reallocated if necessary.
  3247. TranslatedNames - Pointer to structure that optionally references a list
  3248. of name translations for some of the Sids in the Sids array.
  3249. MappedCount - Pointer to location containing the number of Sids
  3250. in the Sids array that have already been mapped. This number
  3251. will be updated to reflect additional mapping done by this
  3252. routine.
  3253. CompletelyUnmappedCount - Pointer to location containing the
  3254. count of completely unmapped Sids. A Sid is completely unmapped
  3255. if it is unknown and also its Domain Prefix Sid is not recognized.
  3256. This count is updated on exit, the number of completely unmapped
  3257. Sids whose Domain Prefices are identified by this routine being
  3258. subtracted from the input value.
  3259. fDoSidHistory - if TRUE then the sids will try to be resolved via sid history
  3260. NonFatalStatus - a status to indicate reasons why no sids could have been
  3261. resolved
  3262. Return Values:
  3263. NTSTATUS - Standard Nt Result Code
  3264. STATUS_SUCCESS - The call completed successfully. Note that
  3265. some or all of the Sids may remain unmapped.
  3266. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  3267. such as memory, to complete the call.
  3268. --*/
  3269. {
  3270. NTSTATUS Status = STATUS_SUCCESS;
  3271. ULONG cGcSids = 0;
  3272. PSID *GcSidArray = NULL;
  3273. BOOLEAN *PossibleGcSidArray = NULL;
  3274. SID_NAME_USE *GcSidNameUse = NULL;
  3275. ULONG *GcSidFlags = NULL;
  3276. UNICODE_STRING *GcNames = NULL;
  3277. ULONG *GcSidOriginalIndex = NULL;
  3278. SAMPR_RETURNED_USTRING_ARRAY NameArray;
  3279. UNICODE_STRING DomainName, UserName;
  3280. UNICODE_STRING BackSlash;
  3281. ULONG i;
  3282. // Parameter check
  3283. ASSERT( Count == TranslatedNames->Entries );
  3284. *NonFatalStatus = STATUS_SUCCESS;
  3285. if ( !SampUsingDsData() ) {
  3286. //
  3287. // Only useful if the ds is running
  3288. //
  3289. return STATUS_SUCCESS;
  3290. }
  3291. RtlZeroMemory( &NameArray, sizeof(NameArray) );
  3292. RtlInitUnicodeString( &BackSlash, L"\\" );
  3293. //
  3294. // Determine what sids are part of known nt5 domains
  3295. // and package into an array
  3296. //
  3297. PossibleGcSidArray = MIDL_user_allocate( Count * sizeof(BOOLEAN) );
  3298. if ( !PossibleGcSidArray ) {
  3299. Status = STATUS_INSUFFICIENT_RESOURCES;
  3300. goto Finish;
  3301. }
  3302. RtlZeroMemory( PossibleGcSidArray, Count * sizeof(BOOLEAN) );
  3303. for ( i = 0; i < Count; i++ ) {
  3304. PSID DomainSid = NULL;
  3305. ULONG Rid;
  3306. //
  3307. // Note: we want names that have just "unknown" set; they could be
  3308. // partially mapped, this is fine.
  3309. //
  3310. if ( (TranslatedNames->Names[i].Use == SidTypeUnknown) ) {
  3311. Status = LsapSplitSid( Sids[i],
  3312. &DomainSid,
  3313. &Rid );
  3314. if ( !NT_SUCCESS( Status ) ) {
  3315. goto Finish;
  3316. }
  3317. //
  3318. // OPTIMIZE -- if DomainSid is current sid and we don't look up
  3319. // by sid history then we shouldn't include the sid here
  3320. //
  3321. cGcSids++;
  3322. PossibleGcSidArray[i] = TRUE;
  3323. MIDL_user_free( DomainSid );
  3324. }
  3325. }
  3326. if ( 0 == cGcSids ) {
  3327. // nothing to do
  3328. goto Finish;
  3329. }
  3330. //
  3331. // Allocate lots of space to hold the resolved sids; this space will
  3332. // be freed at the end of the routine
  3333. //
  3334. GcSidArray = MIDL_user_allocate( cGcSids * sizeof(PSID) );
  3335. if ( !GcSidArray ) {
  3336. Status = STATUS_INSUFFICIENT_RESOURCES;
  3337. goto Finish;
  3338. }
  3339. RtlZeroMemory( GcSidArray, cGcSids * sizeof(PSID) );
  3340. GcSidOriginalIndex = MIDL_user_allocate( cGcSids * sizeof(ULONG) );
  3341. if ( !GcSidOriginalIndex ) {
  3342. Status = STATUS_INSUFFICIENT_RESOURCES;
  3343. goto Finish;
  3344. }
  3345. RtlZeroMemory( GcSidOriginalIndex, cGcSids * sizeof(ULONG) );
  3346. //
  3347. // Package up the sids
  3348. //
  3349. cGcSids = 0;
  3350. for ( i = 0; i < Count; i++ ) {
  3351. if ( PossibleGcSidArray[i] ) {
  3352. GcSidArray[cGcSids] = Sids[i];
  3353. GcSidOriginalIndex[cGcSids] = i;
  3354. cGcSids++;
  3355. }
  3356. }
  3357. // we are done with this
  3358. MIDL_user_free( PossibleGcSidArray );
  3359. PossibleGcSidArray = NULL;
  3360. GcSidNameUse = MIDL_user_allocate( cGcSids * sizeof(SID_NAME_USE) );
  3361. if ( !GcSidNameUse ) {
  3362. Status = STATUS_INSUFFICIENT_RESOURCES;
  3363. goto Finish;
  3364. }
  3365. GcSidFlags = MIDL_user_allocate( cGcSids * sizeof(ULONG) );
  3366. if ( !GcSidFlags ) {
  3367. Status = STATUS_INSUFFICIENT_RESOURCES;
  3368. goto Finish;
  3369. }
  3370. for ( i = 0; i < cGcSids; i++ ) {
  3371. GcSidNameUse[i] = SidTypeUnknown;
  3372. GcSidFlags[i] = 0;
  3373. }
  3374. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: Chaining a SID request to a GC\n"));
  3375. //
  3376. // Call into SAM to resolve the sids at a GC
  3377. //
  3378. Status = SamIGCLookupSids( cGcSids,
  3379. GcSidArray,
  3380. fDoSidHistory ? SAMP_LOOKUP_BY_SID_HISTORY : 0,
  3381. GcSidFlags,
  3382. GcSidNameUse,
  3383. &NameArray );
  3384. if (!NT_SUCCESS(Status)) {
  3385. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: Chain to GC request failed (0x%x)\n", Status));
  3386. }
  3387. if ( STATUS_DS_GC_NOT_AVAILABLE == Status ) {
  3388. //
  3389. // Ok, don't update the mapped count since no names were
  3390. // resolved
  3391. //
  3392. LsapDbLookupReportEvent0( 1,
  3393. EVENTLOG_WARNING_TYPE,
  3394. LSAEVENT_LOOKUP_GC_FAILED,
  3395. sizeof( ULONG ),
  3396. &Status);
  3397. *NonFatalStatus = Status;
  3398. Status = STATUS_SUCCESS;
  3399. goto Finish;
  3400. }
  3401. // Any other error is fatal
  3402. if ( !NT_SUCCESS( Status ) ) {
  3403. goto Finish;
  3404. }
  3405. //
  3406. // For each name resolved, put back in the original array and update
  3407. // the referenced domain's list
  3408. //
  3409. for ( i = 0; i < cGcSids; i++ ) {
  3410. BOOLEAN fStatus;
  3411. ULONG OriginalIndex;
  3412. PSID DomainSid = NULL;
  3413. LSAPR_TRUST_INFORMATION TrustInformation;
  3414. ULONG Rid;
  3415. ULONG DomainIndex = LSA_UNKNOWN_INDEX;
  3416. USHORT Length;
  3417. RtlZeroMemory( &TrustInformation, sizeof(TrustInformation) );
  3418. RtlZeroMemory( &DomainName, sizeof(DomainName) );
  3419. RtlZeroMemory( &UserName, sizeof(UserName) );
  3420. if (GcSidFlags[i] & SAMP_FOUND_XFOREST_REF) {
  3421. //
  3422. // Flag this entry to be resolved in a trusted forest
  3423. //
  3424. OriginalIndex = GcSidOriginalIndex[i];
  3425. TranslatedNames->Names[OriginalIndex].Flags |= LSA_LOOKUP_SID_XFOREST_REF;
  3426. }
  3427. if ( SidTypeUnknown == GcSidNameUse[i] ) {
  3428. //
  3429. // Move on to the next one, right away
  3430. //
  3431. goto IterationCleanup;
  3432. }
  3433. //
  3434. // This name was resolved! Find the domain reference element
  3435. //
  3436. if ( GcSidNameUse[i] != SidTypeDomain ) {
  3437. //
  3438. // Get downlevel domain name and then get sid
  3439. //
  3440. LsapRtlSplitNames( (UNICODE_STRING*) &NameArray.Element[i],
  3441. 1,
  3442. &BackSlash,
  3443. &DomainName,
  3444. &UserName );
  3445. if ( DomainName.Length > 0 ) {
  3446. ASSERT( DomainName.Buffer );
  3447. DomainName.Buffer[DomainName.Length/2] = L'\0';
  3448. Status = LsapGetDomainSidByNetbiosName( DomainName.Buffer,
  3449. &DomainSid );
  3450. DomainName.Buffer[DomainName.Length/2] = L'\\';
  3451. } else {
  3452. Status = STATUS_NO_SUCH_DOMAIN;
  3453. }
  3454. if ( STATUS_NO_SUCH_DOMAIN == Status ) {
  3455. //
  3456. // We don't know about this domain, thus we can't resolve
  3457. // this name so move on to the next one
  3458. // This can occur by either the returned name does not have
  3459. // domain embedded in it, or we can't find the domain locally
  3460. //
  3461. Status = STATUS_SUCCESS;
  3462. goto IterationCleanup;
  3463. }
  3464. if ( !NT_SUCCESS( Status ) ) {
  3465. // This is fatal
  3466. goto IterationCleanup;
  3467. }
  3468. } else {
  3469. DomainSid = GcSidArray[i];
  3470. }
  3471. fStatus = LsapDbLookupListReferencedDomains( ReferencedDomains,
  3472. DomainSid,
  3473. &DomainIndex );
  3474. if ( FALSE == fStatus ) {
  3475. //
  3476. // No entry for this domain -- add it
  3477. //
  3478. // Set the sid
  3479. TrustInformation.Sid = DomainSid;
  3480. DomainSid = NULL;
  3481. // Allocate and set the name
  3482. Status = LsapGetDomainNameBySid( TrustInformation.Sid,
  3483. (PUNICODE_STRING) &TrustInformation.Name );
  3484. if ( STATUS_NO_SUCH_DOMAIN == Status ) {
  3485. //
  3486. // We longer know about this domain, though we did
  3487. // before we sent the name off to the GC.
  3488. // Don't resolve this name, but do continue on with
  3489. // the next name
  3490. //
  3491. Status = STATUS_SUCCESS;
  3492. goto IterationCleanup;
  3493. }
  3494. // Any other error is a resource error
  3495. if ( !NT_SUCCESS( Status ) ) {
  3496. goto IterationCleanup;
  3497. }
  3498. //
  3499. // Add the entry
  3500. //
  3501. Status = LsapDbLookupAddListReferencedDomains( ReferencedDomains,
  3502. &TrustInformation,
  3503. &DomainIndex );
  3504. if ( !NT_SUCCESS( Status ) ) {
  3505. goto IterationCleanup;
  3506. }
  3507. }
  3508. // We should now have a domain index
  3509. ASSERT( LSA_UNKNOWN_INDEX != DomainIndex );
  3510. // Set the information in the returned array
  3511. OriginalIndex = GcSidOriginalIndex[i];
  3512. TranslatedNames->Names[OriginalIndex].Flags = ((GcSidFlags[i] & SAMP_FOUND_BY_SID_HISTORY) ? LSA_LOOKUP_SID_FOUND_BY_HISTORY : 0);
  3513. TranslatedNames->Names[OriginalIndex].Use = GcSidNameUse[i];
  3514. TranslatedNames->Names[OriginalIndex].DomainIndex = DomainIndex;
  3515. // Copy over the name
  3516. Length = UserName.MaximumLength;
  3517. if ( Length > 0 ) {
  3518. TranslatedNames->Names[OriginalIndex].Name.Buffer = MIDL_user_allocate( Length );
  3519. if ( !TranslatedNames->Names[OriginalIndex].Name.Buffer ) {
  3520. Status = STATUS_INSUFFICIENT_RESOURCES;
  3521. goto IterationCleanup;
  3522. }
  3523. RtlZeroMemory( TranslatedNames->Names[OriginalIndex].Name.Buffer, Length );
  3524. TranslatedNames->Names[OriginalIndex].Name.MaximumLength = UserName.MaximumLength;
  3525. TranslatedNames->Names[OriginalIndex].Name.Length = UserName.Length;
  3526. RtlCopyMemory( TranslatedNames->Names[OriginalIndex].Name.Buffer, UserName.Buffer, UserName.Length );
  3527. }
  3528. (*MappedCount) += 1;
  3529. (*CompletelyUnmappedCount) -= 1;
  3530. IterationCleanup:
  3531. if ( TrustInformation.Sid
  3532. && TrustInformation.Sid != GcSidArray[i] ) {
  3533. MIDL_user_free( TrustInformation.Sid );
  3534. }
  3535. if ( TrustInformation.Name.Buffer ) {
  3536. MIDL_user_free( TrustInformation.Name.Buffer );
  3537. }
  3538. if ( DomainSid && DomainSid != GcSidArray[i] ) {
  3539. MIDL_user_free( DomainSid );
  3540. }
  3541. if ( !NT_SUCCESS( Status ) ) {
  3542. break;
  3543. }
  3544. } // iterate over names returned from the GC search
  3545. Finish:
  3546. // Release any memory SAM allocated for us
  3547. SamIFree_SAMPR_RETURNED_USTRING_ARRAY( &NameArray );
  3548. if ( GcSidOriginalIndex ) {
  3549. MIDL_user_free( GcSidOriginalIndex );
  3550. }
  3551. if ( PossibleGcSidArray ) {
  3552. MIDL_user_free( PossibleGcSidArray );
  3553. }
  3554. if ( GcSidArray ) {
  3555. MIDL_user_free( GcSidArray );
  3556. }
  3557. if ( GcSidNameUse ) {
  3558. MIDL_user_free( GcSidNameUse );
  3559. }
  3560. if ( GcSidFlags ) {
  3561. MIDL_user_free( GcSidFlags );
  3562. }
  3563. if ( !NT_SUCCESS(Status) ) {
  3564. // Any memory we've allocated that hasn't been placed in the
  3565. // returned arrays here will get freed at a higher level on error.
  3566. // So don't try to free it here
  3567. NOTHING;
  3568. }
  3569. return Status;
  3570. }
  3571. NTSTATUS
  3572. LsapDbLookupSidsInGlobalCatalogWks(
  3573. IN ULONG Count,
  3574. IN PLSAPR_SID *Sids,
  3575. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3576. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  3577. IN OUT PULONG MappedCount,
  3578. IN OUT PULONG CompletelyUnmappedCount,
  3579. OUT NTSTATUS *NonFatalStatus
  3580. )
  3581. {
  3582. NTSTATUS Status = STATUS_SUCCESS;
  3583. NTSTATUS SecondaryStatus = STATUS_SUCCESS;
  3584. LSA_HANDLE ControllerPolicyHandle = NULL;
  3585. PLSAPR_UNICODE_STRING ControllerNames = NULL;
  3586. ULONG NextLevelCount;
  3587. ULONG NextLevelMappedCount;
  3588. ULONG SidIndex;
  3589. ULONG NextLevelSidIndex;
  3590. PLSAPR_REFERENCED_DOMAIN_LIST NextLevelReferencedDomains = NULL;
  3591. PLSAPR_REFERENCED_DOMAIN_LIST OutputReferencedDomains = NULL;
  3592. PLSA_TRANSLATED_NAME_EX NextLevelNames = NULL;
  3593. PLSAPR_SID *NextLevelSids = NULL;
  3594. LONG FirstEntryIndex;
  3595. PULONG SidIndices = NULL;
  3596. BOOLEAN PartialSidTranslationsAttempted = FALSE;
  3597. LPWSTR ServerName = NULL;
  3598. LPWSTR ServerPrincipalName = NULL;
  3599. PVOID ClientContext = NULL;
  3600. ULONG ServerRevision = 0;
  3601. *NonFatalStatus = STATUS_SUCCESS;
  3602. //
  3603. // If there are no completely unmapped Sids remaining, just return.
  3604. //
  3605. if (*CompletelyUnmappedCount == (ULONG) 0) {
  3606. goto LookupSidsInPrimaryDomainFinish;
  3607. }
  3608. //
  3609. // Open the Policy object on some GC in the forest.
  3610. //
  3611. Status = LsapDbOpenPolicyGc( &ControllerPolicyHandle );
  3612. if (!NT_SUCCESS(Status)) {
  3613. //
  3614. // We cannot access the Global Catalog. Suppress the error
  3615. // and translate Domain Prefix Sids for Sids belonging to
  3616. // the Primary Domain.
  3617. //
  3618. //
  3619. // If we can't open a open a secure channel if a DC call
  3620. // this a trust relationship problem
  3621. //
  3622. *NonFatalStatus = STATUS_DS_GC_NOT_AVAILABLE;
  3623. Status = STATUS_SUCCESS;
  3624. goto LookupSidsInPrimaryDomainFinish;
  3625. }
  3626. //
  3627. // We have successfully opened a Domain Controller's Policy
  3628. // Database. Now prepare to hand off a Sid lookup for the
  3629. // remaining unmapped Sids to that Controller. Here, this
  3630. // server side of the LSA is a client of the LSA on the
  3631. // target controller. We will construct an array of the
  3632. // remianing unmapped Sids, look them up and then merge the
  3633. // resulting ReferencedDomains and Translated Names into
  3634. // our existing list.
  3635. //
  3636. NextLevelCount = *CompletelyUnmappedCount;
  3637. //
  3638. // Allocate an array to hold the indices of unmapped Sids
  3639. // relative to the original Sids and TranslatedNames->Names
  3640. // arrays.
  3641. //
  3642. SidIndices = MIDL_user_allocate(NextLevelCount * sizeof(ULONG));
  3643. Status = STATUS_INSUFFICIENT_RESOURCES;
  3644. if (SidIndices == NULL) {
  3645. goto LookupSidsInPrimaryDomainError;
  3646. }
  3647. //
  3648. // Allocate an array for the Sids to be looked up at the Domain
  3649. // Controller.
  3650. //
  3651. NextLevelSids = MIDL_user_allocate( sizeof(PSID) * NextLevelCount );
  3652. if (NextLevelSids == NULL) {
  3653. goto LookupSidsInPrimaryDomainError;
  3654. }
  3655. Status = STATUS_SUCCESS;
  3656. //
  3657. // Now scan the original array of Names and its parallel
  3658. // Translated Sids array. Copy over any Sids that are
  3659. // completely unmapped.
  3660. //
  3661. NextLevelSidIndex = (ULONG) 0;
  3662. for (SidIndex = 0;
  3663. SidIndex < Count && NextLevelSidIndex < NextLevelCount;
  3664. SidIndex++) {
  3665. if (LsapDbCompletelyUnmappedName(&TranslatedNames->Names[SidIndex])) {
  3666. NextLevelSids[NextLevelSidIndex] = Sids[SidIndex];
  3667. SidIndices[NextLevelSidIndex] = SidIndex;
  3668. NextLevelSidIndex++;
  3669. }
  3670. }
  3671. NextLevelMappedCount = (ULONG) 0;
  3672. Status = LsaICLookupSids(
  3673. ControllerPolicyHandle,
  3674. NextLevelCount,
  3675. (PSID *) NextLevelSids,
  3676. (PLSA_REFERENCED_DOMAIN_LIST *) &NextLevelReferencedDomains,
  3677. &NextLevelNames,
  3678. LsapLookupGC,
  3679. 0,
  3680. &NextLevelMappedCount,
  3681. &ServerRevision
  3682. );
  3683. //
  3684. // If the callout to LsaLookupSids() was unsuccessful, disregard
  3685. // the error and set the domain name for any Sids having this
  3686. // domain Sid as prefix sid. We still want to return translations
  3687. // of Sids we have so far even if we are unable to callout to another
  3688. // LSA.
  3689. //
  3690. if (!NT_SUCCESS(Status)) {
  3691. //
  3692. // Let the caller know there is a trust problem
  3693. //
  3694. if ( (STATUS_TRUSTED_DOMAIN_FAILURE == Status)
  3695. || (STATUS_DS_GC_NOT_AVAILABLE == Status) ) {
  3696. *NonFatalStatus = Status;
  3697. }
  3698. Status = STATUS_SUCCESS;
  3699. goto LookupSidsInPrimaryDomainFinish;
  3700. }
  3701. //
  3702. // Cache any sids that came back
  3703. //
  3704. (void) LsapDbUpdateCacheWithSids(
  3705. NextLevelSids,
  3706. NextLevelCount,
  3707. NextLevelReferencedDomains,
  3708. NextLevelNames
  3709. );
  3710. //
  3711. // The callout to LsaLookupSids() was successful. We now have
  3712. // an additional list of Referenced Domains containing the
  3713. // Primary Domain and/or one or more of its Trusted Domains.
  3714. // Merge the two Referenced Domain Lists together, noting that
  3715. // since they are disjoint, the second list is simply
  3716. // concatenated with the first. The index of the first entry
  3717. // of the second list will be used to adjust all of the
  3718. // Domain Index entries in the Translated Names entries.
  3719. // Note that since the memory for the graph of the first
  3720. // Referenced Domain list has been allocated as individual
  3721. // nodes, we specify that the nodes in this graph can be
  3722. // referenced by the output Referenced Domain list.
  3723. //
  3724. Status = LsapDbLookupMergeDisjointReferencedDomains(
  3725. ReferencedDomains,
  3726. NextLevelReferencedDomains,
  3727. &OutputReferencedDomains,
  3728. LSAP_DB_USE_FIRST_MERGAND_GRAPH
  3729. );
  3730. if (!NT_SUCCESS(Status)) {
  3731. goto LookupSidsInPrimaryDomainError;
  3732. }
  3733. FirstEntryIndex = ReferencedDomains->Entries;
  3734. //
  3735. // Now update the original list of Translated Names. We
  3736. // update each entry that has newly been translated by copying
  3737. // the entry from the new list and adjusting its Referenced
  3738. // Domain List Index upwards by adding the index of the first
  3739. // entry in the Next level List..
  3740. //
  3741. for( NextLevelSidIndex = 0;
  3742. NextLevelSidIndex < NextLevelCount;
  3743. NextLevelSidIndex++ ) {
  3744. if ( !LsapDbCompletelyUnmappedName(&NextLevelNames[NextLevelSidIndex]) ) {
  3745. SidIndex = SidIndices[NextLevelSidIndex];
  3746. if (NextLevelNames[NextLevelSidIndex].Use != SidTypeUnknown) {
  3747. TranslatedNames->Names[SidIndex].Use
  3748. = NextLevelNames[NextLevelSidIndex].Use;
  3749. Status = LsapRpcCopyUnicodeString(
  3750. NULL,
  3751. (PUNICODE_STRING) &TranslatedNames->Names[SidIndex].Name,
  3752. &NextLevelNames[NextLevelSidIndex].Name
  3753. );
  3754. if (!NT_SUCCESS(Status)) {
  3755. break;
  3756. }
  3757. }
  3758. TranslatedNames->Names[SidIndex].DomainIndex =
  3759. FirstEntryIndex +
  3760. NextLevelNames[NextLevelSidIndex].DomainIndex;
  3761. //
  3762. // Update the count of completely unmapped Sids.
  3763. //
  3764. (*CompletelyUnmappedCount)--;
  3765. }
  3766. }
  3767. //
  3768. // Update the Referenced Domain List if a new one was produced
  3769. // from the merge. We retain the original top-level structure.
  3770. // We do this regardless of whether we succeeded or failed, so
  3771. // that we are guarenteed to get it cleaned up.
  3772. //
  3773. if (OutputReferencedDomains != NULL) {
  3774. if (ReferencedDomains->Domains != NULL) {
  3775. MIDL_user_free( ReferencedDomains->Domains );
  3776. ReferencedDomains->Domains = NULL;
  3777. }
  3778. *ReferencedDomains = *OutputReferencedDomains;
  3779. MIDL_user_free( OutputReferencedDomains );
  3780. OutputReferencedDomains = NULL;
  3781. }
  3782. if (!NT_SUCCESS(Status)) {
  3783. goto LookupSidsInPrimaryDomainError;
  3784. }
  3785. //
  3786. // Update the Mapped Count and close the Controller Policy
  3787. // Handle.
  3788. //
  3789. *MappedCount += NextLevelMappedCount;
  3790. SecondaryStatus = LsaClose( ControllerPolicyHandle );
  3791. ControllerPolicyHandle = NULL;
  3792. LookupSidsInPrimaryDomainFinish:
  3793. //
  3794. // If necessary, free the Next Level Referenced Domain List.
  3795. // Note that this structure is allocated(all_nodes) since it was
  3796. // allocated by the client side of the Domain Controller LSA.
  3797. //
  3798. if (NextLevelReferencedDomains != NULL) {
  3799. MIDL_user_free( NextLevelReferencedDomains );
  3800. NextLevelReferencedDomains = NULL;
  3801. }
  3802. //
  3803. // If necessary, free the Next Level Sids array. We only free the
  3804. // top level.
  3805. //
  3806. if (NextLevelSids != NULL) {
  3807. MIDL_user_free( NextLevelSids );
  3808. NextLevelSids = NULL;
  3809. }
  3810. //
  3811. // If necessary, free the Next Level Translated Names array.
  3812. // Note that this array is allocated(all_nodes).
  3813. //
  3814. if (NextLevelNames != NULL) {
  3815. MIDL_user_free( NextLevelNames );
  3816. NextLevelNames = NULL;
  3817. }
  3818. //
  3819. // If necessary, free the array that maps Sid Indices from the
  3820. // Next Level to the Current Level.
  3821. //
  3822. if (SidIndices != NULL) {
  3823. MIDL_user_free( SidIndices );
  3824. SidIndices = NULL;
  3825. }
  3826. //
  3827. // If necessary, close the Controller Policy Handle.
  3828. //
  3829. if ( ControllerPolicyHandle != NULL) {
  3830. SecondaryStatus = LsaClose( ControllerPolicyHandle );
  3831. ControllerPolicyHandle = NULL;
  3832. if (!NT_SUCCESS(SecondaryStatus)) {
  3833. goto LookupSidsInPrimaryDomainError;
  3834. }
  3835. }
  3836. return(Status);
  3837. LookupSidsInPrimaryDomainError:
  3838. //
  3839. // If the primary status was a success code, but the secondary
  3840. // status was an error, propagate the secondary status.
  3841. //
  3842. if ((!NT_SUCCESS(SecondaryStatus)) && NT_SUCCESS(Status)) {
  3843. Status = SecondaryStatus;
  3844. }
  3845. goto LookupSidsInPrimaryDomainFinish;
  3846. }
  3847. NTSTATUS
  3848. LsapDbLookupSidsInTrustedForests(
  3849. IN ULONG Count,
  3850. IN PLSAPR_SID *Sids,
  3851. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3852. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  3853. IN OUT PULONG MappedCount,
  3854. IN OUT PULONG CompletelyUnmappedCount,
  3855. OUT NTSTATUS *NonFatalStatus
  3856. )
  3857. /*++
  3858. Routine Description:
  3859. This routine is called during a LsapLookupPDC lookup. It takes all of the
  3860. SID's that have been marked as belonging to cross forest domains and
  3861. chains to request to either 1) a DC in the root domain of this forest, or
  3862. 2) a DC in ex-forest if the local DC is a DC in the root domain.
  3863. Arguments:
  3864. Count -- the number of entries in Sids
  3865. Sids -- the total collection of SIDs for the LsapLookupPDC request
  3866. ReferencedDomains -- the domains of Sids
  3867. TranslatedNames -- the names and characteristics of Sids
  3868. Mapped -- the number of Sids that have been fully mapped
  3869. CompletelyUnmappedCount -- the number of Sids whose domain portions haven't
  3870. been identified.
  3871. NonFatalStatus -- a connectivity problem, if any while chaining the request.
  3872. Return Values:
  3873. STATUS_SUCCESS, or resource error otherwise
  3874. --*/
  3875. {
  3876. NTSTATUS Status = STATUS_SUCCESS;
  3877. NTSTATUS NextLevelSecondaryStatus = STATUS_SUCCESS;
  3878. ULONG NextLevelCount = 0;
  3879. ULONG NextLevelMappedCount;
  3880. ULONG SidIndex;
  3881. ULONG NextLevelSidIndex;
  3882. PLSAPR_REFERENCED_DOMAIN_LIST NextLevelReferencedDomains = NULL;
  3883. PLSAPR_REFERENCED_DOMAIN_LIST OutputReferencedDomains = NULL;
  3884. PLSA_TRANSLATED_NAME_EX NextLevelNames = NULL;
  3885. LSA_TRANSLATED_NAMES_EX NextLevelNamesStruct;
  3886. PLSAPR_SID *NextLevelSids = NULL;
  3887. LONG FirstEntryIndex;
  3888. PULONG SidIndices = NULL;
  3889. LPWSTR ServerName = NULL;
  3890. LPWSTR ServerPrincipalName = NULL;
  3891. PVOID ClientContext = NULL;
  3892. ULONG ServerRevision = 0;
  3893. BOOLEAN *PossibleXForestSids = NULL;
  3894. BOOLEAN fAllocateAllNodes = FALSE;
  3895. *NonFatalStatus = STATUS_SUCCESS;
  3896. //
  3897. // If there are no completely unmapped Sids remaining, just return.
  3898. //
  3899. if (*CompletelyUnmappedCount == (ULONG) 0) {
  3900. goto LookupSidsInTrustedForestsFinish;
  3901. }
  3902. //
  3903. // Allocate an array to keep track of which SID's are going to
  3904. // be sent off
  3905. //
  3906. PossibleXForestSids = midl_user_allocate(Count * sizeof(BOOLEAN));
  3907. if (NULL == PossibleXForestSids) {
  3908. Status = STATUS_INSUFFICIENT_RESOURCES;
  3909. goto LookupSidsInTrustedForestsError;
  3910. }
  3911. RtlZeroMemory( PossibleXForestSids, Count * sizeof(BOOLEAN) );
  3912. NextLevelCount = 0;
  3913. for (SidIndex = 0; SidIndex < Count; SidIndex++) {
  3914. if (TranslatedNames->Names[SidIndex].Flags & LSA_LOOKUP_SID_XFOREST_REF) {
  3915. ULONG Buffer[SECURITY_MAX_SID_SIZE/sizeof( ULONG ) + 1 ];
  3916. PSID DomainSid = (PSID)Buffer;
  3917. DWORD Size = sizeof(Buffer);
  3918. ASSERT( sizeof( Buffer ) >= SECURITY_MAX_SID_SIZE );
  3919. if (GetWindowsAccountDomainSid(Sids[SidIndex], DomainSid, &Size)) {
  3920. NTSTATUS Status2;
  3921. Status2 = LsapDomainHasDirectExternalTrust(NULL,
  3922. DomainSid,
  3923. NULL,
  3924. NULL);
  3925. if (NT_SUCCESS(Status2)) {
  3926. //
  3927. // Don't send of for xforest resolution, since we
  3928. // can do it locally instead
  3929. //
  3930. continue;
  3931. } else if ( Status2 != STATUS_NO_SUCH_DOMAIN ) {
  3932. goto LookupSidsInTrustedForestsError;
  3933. }
  3934. }
  3935. PossibleXForestSids[SidIndex] = TRUE;
  3936. NextLevelCount++;
  3937. }
  3938. }
  3939. if (NextLevelCount == 0) {
  3940. goto LookupSidsInTrustedForestsFinish;
  3941. }
  3942. //
  3943. // Allocate an array to hold the indices of unmapped Sids
  3944. // relative to the original Sids and TranslatedNames->Names
  3945. // arrays.
  3946. //
  3947. SidIndices = MIDL_user_allocate(NextLevelCount * sizeof(ULONG));
  3948. if (SidIndices == NULL) {
  3949. Status = STATUS_INSUFFICIENT_RESOURCES;
  3950. goto LookupSidsInTrustedForestsError;
  3951. }
  3952. //
  3953. // Allocate an array for the Sids to be looked up at the Domain
  3954. // Controller.
  3955. //
  3956. NextLevelSids = MIDL_user_allocate( sizeof(PSID) * NextLevelCount );
  3957. if (NextLevelSids == NULL) {
  3958. Status = STATUS_INSUFFICIENT_RESOURCES;
  3959. goto LookupSidsInTrustedForestsError;
  3960. }
  3961. //
  3962. // Now scan the original array of Names and its parallel
  3963. // Translated Sids array. Copy over any Sids that are
  3964. // completely unmapped.
  3965. //
  3966. NextLevelSidIndex = (ULONG) 0;
  3967. for (SidIndex = 0;
  3968. SidIndex < Count && NextLevelSidIndex < NextLevelCount;
  3969. SidIndex++) {
  3970. if (PossibleXForestSids[SidIndex]) {
  3971. NextLevelSids[NextLevelSidIndex] = Sids[SidIndex];
  3972. SidIndices[NextLevelSidIndex] = SidIndex;
  3973. NextLevelSidIndex++;
  3974. }
  3975. }
  3976. NextLevelMappedCount = (ULONG) 0;
  3977. NextLevelNamesStruct.Entries = 0;
  3978. NextLevelNamesStruct.Names = NULL;
  3979. Status = LsapDbLookupSidsInTrustedForestsWorker(NextLevelCount,
  3980. (PLSAPR_SID *) NextLevelSids,
  3981. (PLSAPR_REFERENCED_DOMAIN_LIST *) &NextLevelReferencedDomains,
  3982. (PLSAPR_TRANSLATED_NAMES_EX)&NextLevelNamesStruct,
  3983. &fAllocateAllNodes,
  3984. &NextLevelMappedCount,
  3985. &NextLevelSecondaryStatus);
  3986. NextLevelNames = NextLevelNamesStruct.Names;
  3987. if (!NT_SUCCESS(Status)
  3988. && LsapDbIsStatusConnectionFailure(Status)) {
  3989. *NonFatalStatus = Status;
  3990. Status = STATUS_SUCCESS;
  3991. goto LookupSidsInTrustedForestsFinish;
  3992. } else if (NT_SUCCESS(Status)
  3993. && !NT_SUCCESS(NextLevelSecondaryStatus)) {
  3994. *NonFatalStatus = NextLevelSecondaryStatus;
  3995. goto LookupSidsInTrustedForestsFinish;
  3996. } else if (!NT_SUCCESS(Status)
  3997. && Status != STATUS_NONE_MAPPED) {
  3998. //
  3999. // Unhandled error; STATUS_NONE_MAPPED is handled to get
  4000. // partially resolved names.
  4001. //
  4002. goto LookupSidsInTrustedForestsError;
  4003. }
  4004. ASSERT(NT_SUCCESS(Status) || Status == STATUS_NONE_MAPPED);
  4005. Status = STATUS_SUCCESS;
  4006. //
  4007. // The callout to LsaLookupSids() was successful. We now have
  4008. // an additional list of Referenced Domains containing the
  4009. // Primary Domain and/or one or more of its Trusted Domains.
  4010. // Merge the two Referenced Domain Lists together, noting that
  4011. // since they are disjoint, the second list is simply
  4012. // concatenated with the first. The index of the first entry
  4013. // of the second list will be used to adjust all of the
  4014. // Domain Index entries in the Translated Names entries.
  4015. // Note that since the memory for the graph of the first
  4016. // Referenced Domain list has been allocated as individual
  4017. // nodes, we specify that the nodes in this graph can be
  4018. // referenced by the output Referenced Domain list.
  4019. //
  4020. Status = LsapDbLookupMergeDisjointReferencedDomains(
  4021. ReferencedDomains,
  4022. NextLevelReferencedDomains,
  4023. &OutputReferencedDomains,
  4024. LSAP_DB_USE_FIRST_MERGAND_GRAPH
  4025. );
  4026. if (!NT_SUCCESS(Status)) {
  4027. goto LookupSidsInTrustedForestsError;
  4028. }
  4029. FirstEntryIndex = ReferencedDomains->Entries;
  4030. //
  4031. // Now update the original list of Translated Names. We
  4032. // update each entry that has newly been translated by copying
  4033. // the entry from the new list and adjusting its Referenced
  4034. // Domain List Index upwards by adding the index of the first
  4035. // entry in the Next level List..
  4036. //
  4037. for( NextLevelSidIndex = 0;
  4038. NextLevelSidIndex < NextLevelCount;
  4039. NextLevelSidIndex++ ) {
  4040. if ( !LsapDbCompletelyUnmappedName(&NextLevelNames[NextLevelSidIndex]) ) {
  4041. SidIndex = SidIndices[NextLevelSidIndex];
  4042. if (NextLevelNames[NextLevelSidIndex].Use != SidTypeUnknown) {
  4043. TranslatedNames->Names[SidIndex].Use
  4044. = NextLevelNames[NextLevelSidIndex].Use;
  4045. Status = LsapRpcCopyUnicodeString(
  4046. NULL,
  4047. (PUNICODE_STRING) &TranslatedNames->Names[SidIndex].Name,
  4048. &NextLevelNames[NextLevelSidIndex].Name
  4049. );
  4050. if (!NT_SUCCESS(Status)) {
  4051. break;
  4052. }
  4053. }
  4054. TranslatedNames->Names[SidIndex].DomainIndex =
  4055. FirstEntryIndex +
  4056. NextLevelNames[NextLevelSidIndex].DomainIndex;
  4057. //
  4058. // Update the count of completely unmapped Sids.
  4059. //
  4060. (*CompletelyUnmappedCount)--;
  4061. }
  4062. }
  4063. //
  4064. // Update the Referenced Domain List if a new one was produced
  4065. // from the merge. We retain the original top-level structure.
  4066. // We do this regardless of whether we succeeded or failed, so
  4067. // that we are guarenteed to get it cleaned up.
  4068. //
  4069. if (OutputReferencedDomains != NULL) {
  4070. if (ReferencedDomains->Domains != NULL) {
  4071. MIDL_user_free( ReferencedDomains->Domains );
  4072. ReferencedDomains->Domains = NULL;
  4073. }
  4074. *ReferencedDomains = *OutputReferencedDomains;
  4075. MIDL_user_free( OutputReferencedDomains );
  4076. OutputReferencedDomains = NULL;
  4077. }
  4078. if (!NT_SUCCESS(Status)) {
  4079. goto LookupSidsInTrustedForestsError;
  4080. }
  4081. //
  4082. // Update the Mapped Count and close the Controller Policy
  4083. // Handle.
  4084. //
  4085. *MappedCount += NextLevelMappedCount;
  4086. LookupSidsInTrustedForestsFinish:
  4087. //
  4088. // If necessary, free the Next Level Referenced Domain List.
  4089. // Note the structure is not allocate_all_nodes
  4090. //
  4091. if (NextLevelReferencedDomains != NULL) {
  4092. if (!fAllocateAllNodes) {
  4093. if (NextLevelReferencedDomains->Domains) {
  4094. for (NextLevelSidIndex = 0;
  4095. NextLevelSidIndex < NextLevelReferencedDomains->Entries;
  4096. NextLevelSidIndex++) {
  4097. if (NextLevelReferencedDomains->Domains[NextLevelSidIndex].Name.Buffer) {
  4098. MIDL_user_free(NextLevelReferencedDomains->Domains[NextLevelSidIndex].Name.Buffer);
  4099. }
  4100. if (NextLevelReferencedDomains->Domains[NextLevelSidIndex].Sid) {
  4101. MIDL_user_free(NextLevelReferencedDomains->Domains[NextLevelSidIndex].Sid);
  4102. }
  4103. }
  4104. MIDL_user_free(NextLevelReferencedDomains->Domains);
  4105. }
  4106. }
  4107. MIDL_user_free( NextLevelReferencedDomains );
  4108. NextLevelReferencedDomains = NULL;
  4109. }
  4110. //
  4111. // If necessary, free the Next Level Sids array. We only free the
  4112. // top level.
  4113. //
  4114. if (NextLevelSids != NULL) {
  4115. MIDL_user_free( NextLevelSids );
  4116. NextLevelSids = NULL;
  4117. }
  4118. //
  4119. // If necessary, free the Next Level Translated Names array.
  4120. // Note that this array is !allocated(all_nodes).
  4121. //
  4122. if ( NextLevelNames != NULL ) {
  4123. if (!fAllocateAllNodes) {
  4124. for (NextLevelSidIndex = 0;
  4125. NextLevelSidIndex < NextLevelCount;
  4126. NextLevelSidIndex++) {
  4127. if (NextLevelNames[NextLevelSidIndex].Name.Buffer) {
  4128. MIDL_user_free(NextLevelNames[NextLevelSidIndex].Name.Buffer);
  4129. }
  4130. }
  4131. }
  4132. MIDL_user_free( NextLevelNames );
  4133. NextLevelNames = NULL;
  4134. }
  4135. //
  4136. // If necessary, free the array that maps Sid Indices from the
  4137. // Next Level to the Current Level.
  4138. //
  4139. if (SidIndices != NULL) {
  4140. MIDL_user_free( SidIndices );
  4141. SidIndices = NULL;
  4142. }
  4143. if (PossibleXForestSids != NULL) {
  4144. MIDL_user_free( PossibleXForestSids );
  4145. PossibleXForestSids = NULL;
  4146. }
  4147. return(Status);
  4148. LookupSidsInTrustedForestsError:
  4149. goto LookupSidsInTrustedForestsFinish;
  4150. }
  4151. NTSTATUS
  4152. LsapDbLookupSidsInTrustedForestsWorker(
  4153. IN ULONG Count,
  4154. IN PLSAPR_SID *Sids,
  4155. OUT PLSAPR_REFERENCED_DOMAIN_LIST * ReferencedDomains,
  4156. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  4157. OUT BOOLEAN* fAllocateAllNodes,
  4158. IN OUT PULONG MappedCount,
  4159. OUT NTSTATUS *NonFatalStatus
  4160. )
  4161. /*++
  4162. Routine Description:
  4163. This routine is called during a LsapLookupPDC lookup or a
  4164. LsapLookupXForestReferral. This routine assumes all of Sids belong
  4165. to cross forest domains and either resolves them if this DC is in the
  4166. root domain, or chains them to a DC in the root domain.
  4167. Arguments:
  4168. Count -- the number of entries in Sids
  4169. Sids -- the SID's belonging to a XForest domain
  4170. ReferencedDomains -- the domains of Sids
  4171. TranslatedNames -- the names and characteristics of Sids
  4172. fAllocateAllNodes -- describes how ReferencedDomains and TranslatesSids are
  4173. allocated.
  4174. Mapped -- the number of Sids that have been fully mapped
  4175. NonFatalStatus -- a connectivity problem, if any while chaining the request.
  4176. Return Values:
  4177. STATUS_SUCCESS, or resource error otherwise
  4178. --*/
  4179. {
  4180. NTSTATUS Status = STATUS_SUCCESS;
  4181. PLSAP_DB_LOOKUP_WORK_LIST WorkList = NULL;
  4182. *NonFatalStatus = STATUS_SUCCESS;
  4183. *fAllocateAllNodes = FALSE;
  4184. if (!LsapDbDcInRootDomain()) {
  4185. //
  4186. // We are not at the root domain -- forward request
  4187. //
  4188. PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
  4189. LSAPR_TRUST_INFORMATION_EX TrustInfoEx;
  4190. //
  4191. // Get our forest name
  4192. //
  4193. Status = LsapDbLookupGetDomainInfo(NULL,
  4194. &DnsDomainInfo);
  4195. if (!NT_SUCCESS(Status)) {
  4196. goto LookupSidsInTrustedForestFinish;
  4197. }
  4198. RtlZeroMemory(&TrustInfoEx, sizeof(TrustInfoEx));
  4199. TrustInfoEx.DomainName = *((LSAPR_UNICODE_STRING*)&DnsDomainInfo->DnsForestName);
  4200. Status = LsaDbLookupSidChainRequest(&TrustInfoEx,
  4201. Count,
  4202. (PSID*)Sids,
  4203. (PLSA_REFERENCED_DOMAIN_LIST *)ReferencedDomains,
  4204. (PLSA_TRANSLATED_NAME_EX * )&TranslatedNames->Names,
  4205. LsapLookupXForestReferral,
  4206. MappedCount,
  4207. NULL);
  4208. if (TranslatedNames->Names) {
  4209. TranslatedNames->Entries = Count;
  4210. *fAllocateAllNodes = TRUE;
  4211. }
  4212. if (!NT_SUCCESS(Status)) {
  4213. //
  4214. // The attempt to chain failed; record the error
  4215. // if it is interesting
  4216. //
  4217. if (LsapDbIsStatusConnectionFailure(Status)) {
  4218. *NonFatalStatus = Status;
  4219. }
  4220. //
  4221. // This should not fail the overall request
  4222. //
  4223. Status = STATUS_SUCCESS;
  4224. }
  4225. } else {
  4226. //
  4227. // Split the names up into different forests and issue a work
  4228. // request for each one
  4229. //
  4230. ULONG i;
  4231. ULONG CompletelyUnMapped = Count;
  4232. TranslatedNames->Names = MIDL_user_allocate(Count * sizeof(LSA_TRANSLATED_NAME_EX));
  4233. if (TranslatedNames->Names == NULL) {
  4234. Status = STATUS_INSUFFICIENT_RESOURCES;
  4235. goto LookupSidsInTrustedForestFinish;
  4236. }
  4237. TranslatedNames->Entries = Count;
  4238. //
  4239. // Initialize the Output Sids array. Zeroise all fields, then
  4240. // Mark all of the Output Sids as being unknown initially and
  4241. // set the DomainIndex fields to a negative number meaning
  4242. // "no domain"
  4243. //
  4244. RtlZeroMemory( TranslatedNames->Names, Count * sizeof(LSA_TRANSLATED_NAME_EX));
  4245. for (i = 0; i < Count; i++) {
  4246. TranslatedNames->Names[i].Use = SidTypeUnknown;
  4247. TranslatedNames->Names[i].DomainIndex = LSA_UNKNOWN_INDEX;
  4248. }
  4249. //
  4250. // Create an empty Referenced Domain List.
  4251. //
  4252. Status = LsapDbLookupCreateListReferencedDomains( ReferencedDomains, 0 );
  4253. if (!NT_SUCCESS(Status)) {
  4254. goto LookupSidsInTrustedForestFinish;
  4255. }
  4256. //
  4257. // Build a WorkList for this Lookup and put it on the Work Queue.
  4258. //
  4259. // NOTE: This routine does not need to hold the Lookup Work Queue
  4260. // lock to ensure validity of the WorkList pointer, because the
  4261. // pointer remains valid until this routine frees it via
  4262. // LsapDbLookupDeleteWorkList(). Although other threads may
  4263. // process the WorkList, do not delete it.
  4264. //
  4265. // A called routine must acquire the lock in order to access
  4266. // the WorkList after it has been added to the Work Queue.
  4267. //
  4268. Status = LsapDbLookupXForestSidsBuildWorkList(
  4269. Count,
  4270. Sids,
  4271. *ReferencedDomains,
  4272. TranslatedNames,
  4273. LsapLookupXForestResolve,
  4274. MappedCount,
  4275. &CompletelyUnMapped,
  4276. &WorkList
  4277. );
  4278. if (!NT_SUCCESS(Status)) {
  4279. //
  4280. // If no Work List has been built because there are no
  4281. // eligible domains to search, exit, suppressing the error.
  4282. if (Status == STATUS_NONE_MAPPED) {
  4283. Status = STATUS_SUCCESS;
  4284. }
  4285. goto LookupSidsInTrustedForestFinish;
  4286. }
  4287. //
  4288. // Start the work, by dispatching one or more worker threads
  4289. // if necessary.
  4290. //
  4291. Status = LsapDbLookupDispatchWorkerThreads( WorkList );
  4292. if (!NT_SUCCESS(Status)) {
  4293. goto LookupSidsInTrustedForestFinish;
  4294. }
  4295. //
  4296. // Wait for completion/termination of all items on the Work List.
  4297. //
  4298. Status = LsapDbLookupAwaitCompletionWorkList( WorkList );
  4299. if (!NT_SUCCESS(Status)) {
  4300. goto LookupSidsInTrustedForestFinish;
  4301. }
  4302. if ( !NT_SUCCESS(WorkList->NonFatalStatus) ) {
  4303. //
  4304. // Propogate the error as non fatal
  4305. //
  4306. *NonFatalStatus = WorkList->NonFatalStatus;
  4307. }
  4308. }
  4309. LookupSidsInTrustedForestFinish:
  4310. //
  4311. // If a Work List was created, delete it from the Work Queue
  4312. //
  4313. if (WorkList != NULL) {
  4314. Status = LsapDbLookupDeleteWorkList( WorkList );
  4315. WorkList = NULL;
  4316. }
  4317. return Status;
  4318. }
  4319. NTSTATUS
  4320. LsapDbLookupSidsAsDomainSids(
  4321. IN ULONG Flags,
  4322. IN ULONG Count,
  4323. IN PLSAPR_SID *Sids,
  4324. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  4325. IN OUT PLSAPR_TRANSLATED_NAMES_EX TranslatedNames,
  4326. IN OUT PULONG MappedCount
  4327. )
  4328. /*++
  4329. Routine Description:
  4330. This routine tries to match entries in Sids to domain Sids of
  4331. trusted domains.
  4332. There are three kinds of trusted domains:
  4333. 1) domains we directly trusts (both in and out of forest). The LSA TDL
  4334. is used for this.
  4335. 2) domains we trust transitively. The DS cross-ref is used for this.
  4336. 3) domains we trust via a forest trust. The LSA TDL is used
  4337. for this.
  4338. Arguments:
  4339. Flags -- LSAP_LOOKUP_TRUSTED_DOMAIN_DIRECT
  4340. LSAP_LOOKUP_TRUSTED_DOMAIN_TRANSITIVE
  4341. LSAP_LOOKUP_TRUSTED_DOMAIN_FOREST_NAMES
  4342. Count -- the number of entries in Sids
  4343. Sids -- the SID's belonging to a XForest domain
  4344. ReferencedDomains -- the domains of Sids
  4345. TranslatedNames -- the names and characteristics of Sids
  4346. Mapped -- the number of Sids that have been fully mapped
  4347. Return Values:
  4348. STATUS_SUCCESS, or resource error otherwise
  4349. --*/
  4350. {
  4351. NTSTATUS Status = STATUS_SUCCESS;
  4352. ULONG SidIndex;
  4353. BOOLEAN fTDLLock = FALSE;
  4354. LSA_TRUST_INFORMATION TrustInfo;
  4355. RtlZeroMemory(&TrustInfo, sizeof(TrustInfo));
  4356. for (SidIndex = 0; SidIndex < Count; SidIndex++) {
  4357. LSAPR_TRUSTED_DOMAIN_INFORMATION_EX *TrustInfoEx = NULL;
  4358. LSAPR_TRUSTED_DOMAIN_INFORMATION_EX TrustInfoBuffer;
  4359. PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY TrustEntry = NULL;
  4360. PBYTE Buffer[SECURITY_MAX_SID_SIZE];
  4361. PSID DomainSid = (PSID)Buffer;
  4362. ULONG Length;
  4363. ULONG DomainIndex;
  4364. BOOLEAN fStatus;
  4365. RtlZeroMemory(&TrustInfo, sizeof(TrustInfo));
  4366. if (!LsapDbCompletelyUnmappedName(&TranslatedNames->Names[SidIndex])) {
  4367. // Already resolved
  4368. continue;
  4369. }
  4370. //
  4371. // If this isn't a domain SID, bail
  4372. //
  4373. Length = sizeof(Buffer);
  4374. if (!GetWindowsAccountDomainSid(Sids[SidIndex],
  4375. DomainSid,
  4376. &Length)) {
  4377. continue;
  4378. }
  4379. if (!EqualSid(DomainSid, Sids[SidIndex])) {
  4380. continue;
  4381. }
  4382. if (Flags & LSAP_LOOKUP_TRUSTED_DOMAIN_TRANSITIVE) {
  4383. Status = LsapDomainHasTransitiveTrust(NULL,
  4384. Sids[SidIndex],
  4385. &TrustInfo);
  4386. if (NT_SUCCESS(Status)) {
  4387. TrustInfoEx = &TrustInfoBuffer;
  4388. RtlZeroMemory(&TrustInfoBuffer, sizeof(TrustInfoBuffer));
  4389. TrustInfoEx->FlatName = *(LSAPR_UNICODE_STRING*)&TrustInfo.Name;
  4390. TrustInfoEx->Sid = TrustInfo.Sid;
  4391. } else if (Status == STATUS_NO_SUCH_DOMAIN) {
  4392. Status = STATUS_SUCCESS;
  4393. } else {
  4394. // This is fatal
  4395. goto Exit;
  4396. }
  4397. }
  4398. if ((NULL == TrustInfoEx)
  4399. && (Flags & LSAP_LOOKUP_TRUSTED_DOMAIN_DIRECT)) {
  4400. Status = LsapDomainHasDirectTrust(NULL,
  4401. Sids[SidIndex],
  4402. &fTDLLock,
  4403. &TrustEntry);
  4404. if (NT_SUCCESS(Status)) {
  4405. TrustInfoEx = &TrustEntry->TrustInfoEx;
  4406. } else if (Status == STATUS_NO_SUCH_DOMAIN) {
  4407. Status = STATUS_SUCCESS;
  4408. } else {
  4409. // This is fatal
  4410. goto Exit;
  4411. }
  4412. }
  4413. if ((NULL == TrustInfoEx)
  4414. && (Flags & LSAP_LOOKUP_TRUSTED_FOREST_ROOT) ) {
  4415. Status = LsapDomainHasForestTrust(NULL,
  4416. Sids[SidIndex],
  4417. &fTDLLock,
  4418. &TrustEntry);
  4419. if (NT_SUCCESS(Status)) {
  4420. TrustInfoEx = &TrustEntry->TrustInfoEx;
  4421. } else if (Status == STATUS_NO_SUCH_DOMAIN) {
  4422. Status = STATUS_SUCCESS;
  4423. } else {
  4424. // This is fatal
  4425. goto Exit;
  4426. }
  4427. }
  4428. if (TrustInfoEx) {
  4429. //
  4430. // Match -- add it to the list of resolved SID's
  4431. //
  4432. fStatus = LsapDbLookupListReferencedDomains( ReferencedDomains,
  4433. Sids[SidIndex],
  4434. &DomainIndex );
  4435. if ( FALSE == fStatus ) {
  4436. LSA_TRUST_INFORMATION TempTrustInfo;
  4437. //
  4438. // No entry for this domain -- add it
  4439. //
  4440. RtlZeroMemory(&TempTrustInfo, sizeof(TempTrustInfo));
  4441. // Set the sid
  4442. TempTrustInfo.Sid = TrustInfoEx->Sid;
  4443. TempTrustInfo.Name = *(PUNICODE_STRING)&TrustInfoEx->FlatName;
  4444. //
  4445. // Add the entry
  4446. //
  4447. Status = LsapDbLookupAddListReferencedDomains( ReferencedDomains,
  4448. (PLSAPR_TRUST_INFORMATION) &TempTrustInfo,
  4449. &DomainIndex );
  4450. if ( !NT_SUCCESS( Status ) ) {
  4451. goto Exit;
  4452. }
  4453. }
  4454. // We should now have a domain index
  4455. ASSERT( LSA_UNKNOWN_INDEX != DomainIndex );
  4456. // Set the information in the returned array
  4457. TranslatedNames->Names[SidIndex].Use = SidTypeDomain;
  4458. TranslatedNames->Names[SidIndex].DomainIndex = DomainIndex;
  4459. RtlZeroMemory( &TranslatedNames->Names[SidIndex].Name, sizeof(UNICODE_STRING) );
  4460. //
  4461. // Increment the number of items mapped
  4462. //
  4463. (*MappedCount) += 1;
  4464. }
  4465. if (fTDLLock) {
  4466. LsapDbReleaseLockTrustedDomainList();
  4467. fTDLLock = FALSE;
  4468. }
  4469. if (TrustInfo.Name.Buffer) {
  4470. midl_user_free(TrustInfo.Name.Buffer);
  4471. TrustInfo.Name.Buffer = NULL;
  4472. }
  4473. if (TrustInfo.Sid) {
  4474. midl_user_free(TrustInfo.Sid);
  4475. TrustInfo.Sid = NULL;
  4476. }
  4477. if (!NT_SUCCESS(Status)) {
  4478. goto Exit;
  4479. }
  4480. }
  4481. Exit:
  4482. if (fTDLLock) {
  4483. LsapDbReleaseLockTrustedDomainList();
  4484. fTDLLock = FALSE;
  4485. }
  4486. if (TrustInfo.Name.Buffer) {
  4487. midl_user_free(TrustInfo.Name.Buffer);
  4488. TrustInfo.Name.Buffer = NULL;
  4489. }
  4490. if (TrustInfo.Sid) {
  4491. midl_user_free(TrustInfo.Sid);
  4492. TrustInfo.Sid = NULL;
  4493. }
  4494. return Status;
  4495. }