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.

7247 lines
226 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 <samisrv.h>
  27. #include <lmapibuf.h>
  28. #include <dsgetdc.h>
  29. //
  30. // Local function prototypes
  31. //
  32. #define LOOKUP_MATCH_NONE 0
  33. #define LOOKUP_MATCH_LOCALIZED 1
  34. #define LOOKUP_MATCH_HARDCODED 2
  35. #define LOOKUP_MATCH_BOTH 3
  36. BOOLEAN
  37. LsapDbLookupIndexWellKnownName(
  38. IN OPTIONAL PLSAPR_UNICODE_STRING Name,
  39. OUT PLSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex,
  40. IN DWORD dwMatchType
  41. );
  42. //
  43. // Hardcoded english strings for LocalService, NetworkService,
  44. // and LocalSystem since the account names may come from the
  45. // registry (which isn't localized).
  46. //
  47. #define LOCALSERVICE_NAME L"LocalService"
  48. #define NETWORKSERVICE_NAME L"NetworkService"
  49. #define SYSTEM_NAME L"SYSTEM"
  50. #define NTAUTHORITY_NAME L"NT AUTHORITY"
  51. struct {
  52. UNICODE_STRING KnownName;
  53. LSAP_WELL_KNOWN_SID_INDEX LookupIndex;
  54. } LsapHardcodedNameLookupList[] = {
  55. { { sizeof(LOCALSERVICE_NAME) - 2, sizeof(LOCALSERVICE_NAME), LOCALSERVICE_NAME },
  56. LsapLocalServiceSidIndex },
  57. { { sizeof(NETWORKSERVICE_NAME) - 2, sizeof(NETWORKSERVICE_NAME), NETWORKSERVICE_NAME },
  58. LsapNetworkServiceSidIndex },
  59. { { sizeof(SYSTEM_NAME) - 2, sizeof(SYSTEM_NAME), SYSTEM_NAME },
  60. LsapLocalSystemSidIndex }
  61. };
  62. //
  63. // Handy macros for iterating over static arrays
  64. //
  65. #define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
  66. NTSTATUS
  67. LsapDbLookupNamesInTrustedForests(
  68. IN ULONG LookupOptions,
  69. IN ULONG Count,
  70. IN PLSAPR_UNICODE_STRING Names,
  71. IN PLSAPR_UNICODE_STRING PrefixNames,
  72. IN PLSAPR_UNICODE_STRING SuffixNames,
  73. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  74. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  75. IN OUT PULONG MappedCount,
  76. IN OUT PULONG CompletelyUnmappedCount,
  77. OUT NTSTATUS *NonFatalStatus
  78. );
  79. NTSTATUS
  80. LsapDbLookupNamesInTrustedForestsWorker(
  81. IN ULONG Count,
  82. IN PLSAPR_UNICODE_STRING Names,
  83. IN PLSAPR_UNICODE_STRING PrefixNames,
  84. IN PLSAPR_UNICODE_STRING SuffixNames,
  85. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  86. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  87. OUT BOOLEAN* fAllocateAllNodes,
  88. IN OUT PULONG MappedCount,
  89. IN ULONG LookupOptions,
  90. OUT NTSTATUS *NonFatalStatus
  91. );
  92. NTSTATUS
  93. LsapLookupNames(
  94. IN LSAPR_HANDLE PolicyHandle,
  95. IN ULONG Count,
  96. IN PLSAPR_UNICODE_STRING Names,
  97. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  98. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  99. IN LSAP_LOOKUP_LEVEL LookupLevel,
  100. IN OUT PULONG MappedCount,
  101. IN ULONG LookupOptions,
  102. IN ULONG ClientRevision
  103. );
  104. NTSTATUS
  105. LsapDomainHasForestTrust(
  106. IN PUNICODE_STRING DomainName, OPTIONAL
  107. IN PSID DomainSid, OPTIONAL
  108. IN OUT BOOLEAN *fTDLLock, OPTIONAL
  109. OUT PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY *TrustEntryOut OPTIONAL
  110. );
  111. NTSTATUS
  112. LsapDomainHasDirectTrust(
  113. IN PUNICODE_STRING DomainName, OPTIONAL
  114. IN PSID DomainSid, OPTIONAL
  115. IN OUT BOOLEAN *fTDLLock, OPTIONAL
  116. OUT PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY *TrustEntryOut OPTIONAL
  117. );
  118. NTSTATUS
  119. LsapDomainHasTransitiveTrust(
  120. IN PUNICODE_STRING DomainName, OPTIONAL
  121. IN PSID DomainSid, OPTIONAL
  122. OUT LSA_TRUST_INFORMATION *TrustInfo OPTIONAL
  123. );
  124. NTSTATUS
  125. LsapDomainHasDirectExternalTrust(
  126. IN PUNICODE_STRING DomainName, OPTIONAL
  127. IN PSID DomainSid, OPTIONAL
  128. IN OUT BOOLEAN *fTDLLock, OPTIONAL
  129. OUT PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY *TrustEntryOut OPTIONAL
  130. );
  131. //////////////////////////////////////////////////////////////////////////
  132. // //
  133. // Lsa Lookup Name Routines //
  134. // //
  135. //////////////////////////////////////////////////////////////////////////
  136. NTSTATUS
  137. LsarLookupNames(
  138. IN LSAPR_HANDLE PolicyHandle,
  139. IN ULONG Count,
  140. IN PLSAPR_UNICODE_STRING Names,
  141. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  142. IN OUT PLSAPR_TRANSLATED_SIDS TranslatedSids,
  143. IN LSAP_LOOKUP_LEVEL LookupLevel,
  144. IN OUT PULONG MappedCount
  145. )
  146. /*++
  147. Routine Description:
  148. See LsapLookupNames.
  149. Note that in Extended Sid Mode, requests to this API are denied since
  150. only the RID is returned.
  151. --*/
  152. {
  153. NTSTATUS Status = STATUS_SUCCESS;
  154. ULONG Size;
  155. LSAPR_TRANSLATED_SIDS_EX2 TranslatedSidsEx2 = {0, NULL};
  156. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupNames(%ws) start\n", LsapDbLookupGetLevel(LookupLevel)) );
  157. //
  158. // Open SAM
  159. //
  160. Status = LsapOpenSam();
  161. ASSERT(NT_SUCCESS(Status));
  162. if ( !NT_SUCCESS( Status ) ) {
  163. return( Status );
  164. }
  165. if (SamIIsExtendedSidMode(LsapAccountDomainHandle)) {
  166. return STATUS_NOT_SUPPORTED;
  167. }
  168. if ( Count > LSA_MAXIMUM_LOOKUP_NAMES_COUNT ) {
  169. //
  170. // We shouldn't be getting this much names to lookup
  171. // after the change by BUG 501798
  172. //
  173. ASSERT( FALSE );
  174. return STATUS_INVALID_PARAMETER;
  175. }
  176. //
  177. // Note that due to the IN/OUT nature of TranslatedSids, it is
  178. // possible that a client can pass something into the Sids field.
  179. // However, NT clients do not so it is safe, and correct to free
  180. // any values at this point. Not doing so would mean a malicious
  181. // client could cause starve the server.
  182. //
  183. if ( TranslatedSids->Sids ) {
  184. MIDL_user_free( TranslatedSids->Sids );
  185. TranslatedSids->Sids = NULL;
  186. }
  187. //
  188. // Allocate the TranslatedName buffer to return
  189. //
  190. TranslatedSids->Entries = 0;
  191. Size = Count * sizeof(LSA_TRANSLATED_SID);
  192. TranslatedSids->Sids = midl_user_allocate( Size );
  193. if ( !TranslatedSids->Sids ) {
  194. Status = STATUS_INSUFFICIENT_RESOURCES;
  195. goto Cleanup;
  196. }
  197. RtlZeroMemory( TranslatedSids->Sids, Size );
  198. TranslatedSids->Entries = Count;
  199. Status = LsapLookupNames( PolicyHandle,
  200. Count,
  201. Names,
  202. ReferencedDomains,
  203. (PLSAPR_TRANSLATED_SIDS_EX2) &TranslatedSidsEx2,
  204. LookupLevel,
  205. MappedCount,
  206. 0, // no options
  207. LSA_CLIENT_PRE_NT5 );
  208. if ( TranslatedSidsEx2.Sids != NULL ) {
  209. //
  210. // Map the new data structure back to the old one
  211. //
  212. ULONG i;
  213. ASSERT( TranslatedSidsEx2.Entries == TranslatedSids->Entries );
  214. for (i = 0; i < TranslatedSidsEx2.Entries; i++ ) {
  215. PSID Sid = TranslatedSidsEx2.Sids[i].Sid;
  216. ULONG Rid = 0;
  217. if ( SidTypeDomain == TranslatedSidsEx2.Sids[i].Use ) {
  218. Rid = LSA_UNKNOWN_ID;
  219. } else if ( NULL != Sid ) {
  220. ULONG SubAuthCount = (ULONG) *RtlSubAuthorityCountSid(Sid);
  221. Rid = *RtlSubAuthoritySid(Sid, (SubAuthCount - 1));
  222. }
  223. TranslatedSids->Sids[i].Use = TranslatedSidsEx2.Sids[i].Use;
  224. TranslatedSids->Sids[i].RelativeId = Rid;
  225. TranslatedSids->Sids[i].DomainIndex = TranslatedSidsEx2.Sids[i].DomainIndex;
  226. if (TranslatedSidsEx2.Sids[i].Sid) {
  227. // N.B. The SID is not an embedded field server side
  228. midl_user_free(TranslatedSidsEx2.Sids[i].Sid);
  229. TranslatedSidsEx2.Sids[i].Sid = NULL;
  230. }
  231. }
  232. //
  233. // Free the Ex structure
  234. //
  235. midl_user_free( TranslatedSidsEx2.Sids );
  236. } else {
  237. TranslatedSids->Entries = 0;
  238. midl_user_free( TranslatedSids->Sids );
  239. TranslatedSids->Sids = NULL;
  240. }
  241. Cleanup:
  242. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupNames(%ws) end (0x%x)\n", LsapDbLookupGetLevel(LookupLevel), Status) );
  243. return Status;
  244. }
  245. NTSTATUS
  246. LsarLookupNames2(
  247. IN LSAPR_HANDLE PolicyHandle,
  248. IN ULONG Count,
  249. IN PLSAPR_UNICODE_STRING Names,
  250. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  251. IN OUT PLSAPR_TRANSLATED_SIDS_EX TranslatedSids,
  252. IN LSAP_LOOKUP_LEVEL LookupLevel,
  253. IN OUT PULONG MappedCount,
  254. IN ULONG LookupOptions,
  255. IN ULONG ClientRevision
  256. )
  257. /*++
  258. Routine Description:
  259. See LsapLookupNames.
  260. Note that in Extended Sid Mode, requests to this API are denied since
  261. only the RID is returned.
  262. --*/
  263. {
  264. NTSTATUS Status = STATUS_SUCCESS;
  265. ULONG Size;
  266. LSAPR_TRANSLATED_SIDS_EX2 TranslatedSidsEx2 = {0, NULL};
  267. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupNames2(%ws) start\n", LsapDbLookupGetLevel(LookupLevel)) );
  268. //
  269. // Open SAM
  270. //
  271. Status = LsapOpenSam();
  272. ASSERT(NT_SUCCESS(Status));
  273. if ( !NT_SUCCESS( Status ) ) {
  274. return( Status );
  275. }
  276. if (SamIIsExtendedSidMode(LsapAccountDomainHandle)) {
  277. return STATUS_NOT_SUPPORTED;
  278. }
  279. if ( Count > LSA_MAXIMUM_LOOKUP_NAMES_COUNT ) {
  280. //
  281. // We shouldn't be getting this much names to lookup
  282. // after the change by BUG 501798
  283. //
  284. ASSERT( FALSE );
  285. return STATUS_INVALID_PARAMETER;
  286. }
  287. //
  288. // Note that due to the IN/OUT nature of TranslatedSids, it is
  289. // possible that a client can pass something into the Sids field.
  290. // However, NT clients do not so it is safe, and correct to free
  291. // any values at this point. Not doing so would mean a malicious
  292. // client could cause starve the server.
  293. //
  294. if ( TranslatedSids->Sids ) {
  295. MIDL_user_free( TranslatedSids->Sids );
  296. TranslatedSids->Sids = NULL;
  297. }
  298. //
  299. // Allocate the TranslatedName buffer to return
  300. //
  301. TranslatedSids->Entries = 0;
  302. Size = Count * sizeof(LSA_TRANSLATED_SID_EX);
  303. TranslatedSids->Sids = midl_user_allocate( Size );
  304. if ( !TranslatedSids->Sids ) {
  305. Status = STATUS_INSUFFICIENT_RESOURCES;
  306. goto Cleanup;
  307. }
  308. RtlZeroMemory( TranslatedSids->Sids, Size );
  309. TranslatedSids->Entries = Count;
  310. Status = LsapLookupNames( PolicyHandle,
  311. Count,
  312. Names,
  313. ReferencedDomains,
  314. (PLSAPR_TRANSLATED_SIDS_EX2) &TranslatedSidsEx2,
  315. LookupLevel,
  316. MappedCount,
  317. 0, // no options
  318. LSA_CLIENT_NT5 );
  319. if ( TranslatedSidsEx2.Sids != NULL ) {
  320. //
  321. // Map the new data structure back to the old one
  322. //
  323. ULONG i;
  324. ASSERT( TranslatedSidsEx2.Entries == TranslatedSids->Entries );
  325. for (i = 0; i < TranslatedSidsEx2.Entries; i++ ) {
  326. PSID Sid = TranslatedSidsEx2.Sids[i].Sid;
  327. ULONG Rid = 0;
  328. if ( SidTypeDomain == TranslatedSidsEx2.Sids[i].Use ) {
  329. Rid = LSA_UNKNOWN_ID;
  330. } else if ( NULL != Sid ) {
  331. ULONG SubAuthCount = (ULONG) *RtlSubAuthorityCountSid(Sid);
  332. Rid = *RtlSubAuthoritySid(Sid, (SubAuthCount - 1));
  333. }
  334. TranslatedSids->Sids[i].Use = TranslatedSidsEx2.Sids[i].Use;
  335. TranslatedSids->Sids[i].RelativeId = Rid;
  336. TranslatedSids->Sids[i].DomainIndex = TranslatedSidsEx2.Sids[i].DomainIndex;
  337. TranslatedSids->Sids[i].Flags = TranslatedSidsEx2.Sids[i].Flags;
  338. if (TranslatedSidsEx2.Sids[i].Sid) {
  339. // N.B. The SID is not an embedded field server side
  340. midl_user_free(TranslatedSidsEx2.Sids[i].Sid);
  341. TranslatedSidsEx2.Sids[i].Sid = NULL;
  342. }
  343. }
  344. //
  345. // Free the Ex structure
  346. //
  347. midl_user_free( TranslatedSidsEx2.Sids );
  348. } else {
  349. TranslatedSids->Entries = 0;
  350. midl_user_free( TranslatedSids->Sids );
  351. TranslatedSids->Sids = NULL;
  352. }
  353. Cleanup:
  354. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupNames2(%ws) end (0x%x)\n", LsapDbLookupGetLevel(LookupLevel), Status) );
  355. return Status;
  356. }
  357. NTSTATUS
  358. LsarLookupNames3(
  359. IN LSAPR_HANDLE PolicyHandle,
  360. IN ULONG Count,
  361. IN PLSAPR_UNICODE_STRING Names,
  362. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  363. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  364. IN LSAP_LOOKUP_LEVEL LookupLevel,
  365. IN OUT PULONG MappedCount,
  366. IN ULONG LookupOptions,
  367. IN ULONG ClientRevision
  368. )
  369. /*++
  370. Routine Description:
  371. See LsapLookupNames
  372. This function does not take an LSA RPC Context handle. The access check
  373. performed is that the caller is NETLOGON.
  374. --*/
  375. {
  376. //
  377. // Access check is performed in LsarLookupNames3 when a NULL is passed in.
  378. //
  379. NTSTATUS Status;
  380. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupNames3(%ws) start\n", LsapDbLookupGetLevel(LookupLevel)) );
  381. Status = LsapLookupNames (PolicyHandle,
  382. Count,
  383. Names,
  384. ReferencedDomains,
  385. TranslatedSids,
  386. LookupLevel,
  387. MappedCount,
  388. LookupOptions,
  389. ClientRevision );
  390. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupNames3(%ws) end (0x%x)\n", LsapDbLookupGetLevel(LookupLevel), Status) );
  391. return Status;
  392. }
  393. NTSTATUS
  394. LsarLookupNames4(
  395. IN handle_t RpcHandle,
  396. IN ULONG Count,
  397. IN PLSAPR_UNICODE_STRING Names,
  398. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  399. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  400. IN LSAP_LOOKUP_LEVEL LookupLevel,
  401. IN OUT PULONG MappedCount,
  402. IN ULONG LookupOptions,
  403. IN ULONG ClientRevision
  404. )
  405. /*++
  406. Routine Description:
  407. See LsapLookupNames
  408. This function does not take an LSA RPC Context handle. The access check
  409. performed is that the caller is NETLOGON.
  410. --*/
  411. {
  412. //
  413. // Access check is performed in LsarLookupNames3 when a NULL is passed in.
  414. //
  415. NTSTATUS Status;
  416. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupNames4(%ws) start\n", LsapDbLookupGetLevel(LookupLevel)) );
  417. Status = LsapLookupNames(NULL,
  418. Count,
  419. Names,
  420. ReferencedDomains,
  421. TranslatedSids,
  422. LookupLevel,
  423. MappedCount,
  424. LookupOptions,
  425. ClientRevision );
  426. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: LsarLookupNames4(%ws) end (0x%x)\n", LsapDbLookupGetLevel(LookupLevel), Status) );
  427. return Status;
  428. }
  429. NTSTATUS
  430. LsapLookupNames(
  431. IN LSAPR_HANDLE PolicyHandle,
  432. IN ULONG Count,
  433. IN PLSAPR_UNICODE_STRING Names,
  434. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  435. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  436. IN LSAP_LOOKUP_LEVEL LookupLevel,
  437. IN OUT PULONG MappedCount,
  438. IN ULONG LookupOptions,
  439. IN ULONG ClientRevision
  440. )
  441. /*++
  442. Routine Description:
  443. This function is the LSA server worker routine for the LsaLookupNames
  444. API.
  445. The LsaLookupNames API attempts to translate names of domains, users,
  446. groups or aliases to Sids. The caller must have POLICY_LOOKUP_NAMES
  447. access to the Policy object.
  448. Names may be either isolated (e.g. JohnH) or composite names containing
  449. both the domain name and account name. Composite names must include a
  450. backslash character separating the domain name from the account name
  451. (e.g. Acctg\JohnH). An isolated name may be either an account name
  452. (user, group, or alias) or a domain name.
  453. Translation of isolated names introduces the possibility of name
  454. collisions (since the same name may be used in multiple domains). An
  455. isolated name will be translated using the following algorithm:
  456. If the name is a well-known name (e.g. Local or Interactive), then the
  457. corresponding well-known Sid is returned.
  458. If the name is the Built-in Domain's name, then that domain's Sid
  459. will be returned.
  460. If the name is the Account Domain's name, then that domain's Sid
  461. will be returned.
  462. /
  463. If the name is the Primary Domain's name, then that domain's Sid will
  464. be returned.
  465. If the name is a user, group, or alias in the Built-in Domain, then the
  466. Sid of that account is returned.
  467. If the name is a user, group, or alias in the Primary Domain, then the
  468. Sid of that account is returned.
  469. Otherwise, the name is not translated.
  470. NOTE: Proxy, Machine, and Trust user accounts are not referenced
  471. for name translation. Only normal user accounts are used for ID
  472. translation. If translation of other account types is needed, then
  473. SAM services should be used directly.
  474. Arguments:
  475. This function is the LSA server RPC worker routine for the
  476. LsaLookupNames API.
  477. PolicyHandle - Handle from an LsaOpenPolicy call.
  478. Count - Specifies the number of names to be translated.
  479. Names - Pointer to an array of Count Unicode String structures
  480. specifying the names to be looked up and mapped to Sids.
  481. The strings may be names of User, Group or Alias accounts or
  482. domains.
  483. ReferencedDomains - Receives a pointer to a structure describing the
  484. domains used for the translation. The entries in this structure
  485. are referenced by the structure returned via the Sids parameter.
  486. Unlike the Sids parameter, which contains an array entry for
  487. each translated name, this structure will only contain one
  488. component for each domain utilized in the translation.
  489. When this information is no longer needed, it must be released
  490. by passing the returned pointer to LsaFreeMemory().
  491. TranslatedSids - Pointer to a structure which will (or already) references an array of
  492. records describing each translated Sid. The nth entry in this array
  493. provides a translation for the nth element in the Names parameter.
  494. When this information is no longer needed, it must be released
  495. by passing the returned pointer to LsaFreeMemory().
  496. LookupLevel - Specifies the Level of Lookup to be performed on this
  497. machine. Values of this field are are follows:
  498. LsapLookupWksta - First Level Lookup performed on a workstation
  499. normally configured for Windows-Nt. The lookup searches the
  500. Well-Known Sids/Names, and the Built-in Domain and Account Domain
  501. in the local SAM Database. If not all Sids or Names are
  502. identified, performs a "handoff" of a Second level Lookup to the
  503. LSA running on a Controller for the workstation's Primary Domain
  504. (if any).
  505. LsapLookupPDC - Second Level Lookup performed on a Primary Domain
  506. Controller. The lookup searches the Account Domain of the
  507. SAM Database on the controller. If not all Sids or Names are
  508. found, the Trusted Domain List (TDL) is obtained from the
  509. LSA's Policy Database and Third Level lookups are performed
  510. via "handoff" to each Trusted Domain in the List.
  511. LsapLookupTDL - Third Level Lookup performed on a controller
  512. for a Trusted Domain. The lookup searches the Account Domain of
  513. the SAM Database on the controller only.
  514. MappedCount - Pointer to location that contains a count of the Names
  515. mapped so far. On exit, this will be updated.
  516. LookupOptions --
  517. LSA_LOOKUP_ISOLATED_AS_LOCAL
  518. This flags controls the lookup API's such that isolated names, including
  519. UPN's are not searched for off the machine. Composite names
  520. (domain\username) are still sent off machine if necessary.
  521. ClientRevision -- the revision, wrt to lookup code, of the client
  522. Return Values:
  523. NTSTATUS - Standard Nt Result Code
  524. STATUS_SUCCESS - The call completed successfully and all Names have
  525. been translated to Sids.
  526. STATUS_SOME_NOT_MAPPED - At least one of the names provided was
  527. trasnlated to a Sid, but not all names could be translated. This
  528. is a success status.
  529. STATUS_NONE_MAPPED - None of the names provided could be translated
  530. to Sids. This is an error status, but output is returned. Such
  531. output includes partial translations of names whose domain could
  532. be identified.
  533. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  534. to complete the operation.
  535. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  536. to complete the call.
  537. --*/
  538. {
  539. NTSTATUS Status = STATUS_SUCCESS, SecondaryStatus = STATUS_SUCCESS;
  540. NTSTATUS TempStatus;
  541. ULONG DomainIndex;
  542. LSAPR_TRUST_INFORMATION TrustInformation;
  543. LSAPR_TRUST_INFORMATION BuiltInDomainTrustInformation;
  544. LSAPR_TRUST_INFORMATION_EX AccountDomainTrustInformation;
  545. LSAPR_TRUST_INFORMATION_EX PrimaryDomainTrustInformation;
  546. ULONG NullNameCount = 0;
  547. ULONG NameIndex;
  548. PLSAPR_TRANSLATED_SID_EX2 OutputSids;
  549. PLSAPR_TRUST_INFORMATION Domains = NULL;
  550. ULONG OutputSidsLength;
  551. ULONG CompletelyUnmappedCount = Count;
  552. ULONG LocalDomainsToSearch = 0;
  553. PLSAPR_UNICODE_STRING PrefixNames = NULL;
  554. PLSAPR_UNICODE_STRING SuffixNames = NULL;
  555. LSAPR_UNICODE_STRING BackSlash;
  556. BOOLEAN fDownlevelSecureChannel = FALSE;
  557. ULONG DomainLookupScope = 0;
  558. ULONG PreviousMappedCount = 0;
  559. LsarpReturnCheckSetup();
  560. LsapTraceEvent(EVENT_TRACE_TYPE_START, LsaTraceEvent_LookupNames);
  561. BuiltInDomainTrustInformation.Name.Buffer = NULL;
  562. BuiltInDomainTrustInformation.Sid = NULL;
  563. AccountDomainTrustInformation.DomainName.Buffer = NULL;
  564. AccountDomainTrustInformation.FlatName.Buffer = NULL;
  565. AccountDomainTrustInformation.Sid = NULL;
  566. PrimaryDomainTrustInformation.DomainName.Buffer = NULL;
  567. PrimaryDomainTrustInformation.FlatName.Buffer = NULL;
  568. PrimaryDomainTrustInformation.Sid = NULL;
  569. ASSERT( Count <= LSA_MAXIMUM_LOOKUP_NAMES_COUNT );
  570. //
  571. // If there are no completely unmapped Names remaining, return.
  572. //
  573. if (CompletelyUnmappedCount == (ULONG) 0) {
  574. goto LookupNamesFinish;
  575. }
  576. if ((LookupOptions & LSA_LOOKUP_ISOLATED_AS_LOCAL) != 0
  577. && LookupLevel != LsapLookupWksta ) {
  578. //
  579. // LSA_LOOKUP_ISOLATED_AS_LOCAL is only valid on workstation lookups
  580. //
  581. Status = STATUS_INVALID_PARAMETER;
  582. goto LookupNamesFinish;
  583. }
  584. //
  585. // Validate that all of the names are valid. Unfortunately, we must do it here, since
  586. // we actually process each of the entries before we loop through them below.
  587. //
  588. for (NameIndex = 0; NameIndex < Count; NameIndex++) {
  589. if ( !LsapValidateLsaUnicodeString( &Names[ NameIndex ] ) ) {
  590. Status = STATUS_INVALID_PARAMETER;
  591. goto LookupNamesError;
  592. }
  593. }
  594. //
  595. // Perform an access check
  596. //
  597. Status = LsapDbLookupAccessCheck( PolicyHandle );
  598. if (!NT_SUCCESS(Status)) {
  599. goto LookupNamesError;
  600. }
  601. //
  602. // Determine what scope of resolution to use
  603. //
  604. DomainLookupScope = LsapGetDomainLookupScope(LookupLevel,
  605. ClientRevision);
  606. //
  607. // Names provided are either Isolated, consisting of a single
  608. // component, or composite, having the form
  609. //
  610. // <DomainName>\<SuffixName>
  611. //
  612. // Split the list of names into two separate arrays, one containing
  613. // the Domain Prefixes (or NULL strings) and the other array
  614. // containing the Terminal Names. Both arrays are the same size
  615. // as the original. First, allocate memory for the output arrays
  616. // of UNICODE_STRING structures.
  617. //
  618. Status = STATUS_INSUFFICIENT_RESOURCES;
  619. PrefixNames = MIDL_user_allocate( Count * sizeof( UNICODE_STRING ));
  620. if (PrefixNames == NULL) {
  621. goto LookupNamesError;
  622. }
  623. SuffixNames = MIDL_user_allocate( Count * sizeof( UNICODE_STRING ));
  624. if (SuffixNames == NULL) {
  625. goto LookupNamesError;
  626. }
  627. RtlInitUnicodeString( (PUNICODE_STRING) &BackSlash, L"\\" );
  628. LsapRtlSplitNames(
  629. (PUNICODE_STRING) Names,
  630. Count,
  631. (PUNICODE_STRING) &BackSlash,
  632. (PUNICODE_STRING) PrefixNames,
  633. (PUNICODE_STRING) SuffixNames
  634. );
  635. //
  636. // Note that due to the IN/OUT nature of TranslatedSids, it is
  637. // possible that a client can pass something into the Sids field.
  638. // However, NT clients do not so it is safe, and correct to free
  639. // any values at this point. Not doing so would mean a malicious
  640. // client could cause starve the server.
  641. //
  642. if ( TranslatedSids->Sids ) {
  643. MIDL_user_free( TranslatedSids->Sids );
  644. }
  645. TranslatedSids->Sids = NULL;
  646. TranslatedSids->Entries = 0;
  647. *ReferencedDomains = NULL;
  648. ASSERT( (LookupLevel == LsapLookupWksta)
  649. || (LookupLevel == LsapLookupPDC)
  650. || (LookupLevel == LsapLookupTDL)
  651. || (LookupLevel == LsapLookupGC)
  652. || (LookupLevel == LsapLookupXForestReferral)
  653. || (LookupLevel == LsapLookupXForestResolve) );
  654. //
  655. // Now that parameter checks have been done, fork off if this
  656. // is an XForest request
  657. //
  658. if (LookupLevel == LsapLookupXForestReferral) {
  659. BOOLEAN fAllocateAllNodes = FALSE;
  660. NTSTATUS Status2;
  661. //
  662. // Note that LsapDbLookupNamesInTrustedForestsWorker will allocate
  663. // the OUT parameters
  664. //
  665. *MappedCount = 0;
  666. Status = LsapDbLookupNamesInTrustedForestsWorker(Count,
  667. Names,
  668. PrefixNames,
  669. SuffixNames,
  670. ReferencedDomains,
  671. TranslatedSids,
  672. &fAllocateAllNodes,
  673. MappedCount,
  674. LookupOptions,
  675. &SecondaryStatus);
  676. if (fAllocateAllNodes) {
  677. //
  678. // Reallocate the memory in a form the server can return to RPC
  679. //
  680. Status2 = LsapLookupReallocateTranslations((PLSA_REFERENCED_DOMAIN_LIST *)ReferencedDomains,
  681. Count,
  682. NULL,
  683. (PLSA_TRANSLATED_SID_EX2 * ) &TranslatedSids->Sids);
  684. if (!NT_SUCCESS(Status2)) {
  685. //
  686. // This is a fatal resource error - free the memory that
  687. // was returned to us by the chaining call
  688. //
  689. if (*ReferencedDomains) {
  690. midl_user_free(*ReferencedDomains);
  691. *ReferencedDomains = NULL;
  692. }
  693. if (TranslatedSids->Sids) {
  694. midl_user_free(TranslatedSids->Sids);
  695. TranslatedSids->Sids = NULL;
  696. TranslatedSids->Entries = 0;
  697. }
  698. Status = Status2;
  699. }
  700. }
  701. //
  702. // There is nothing more to do
  703. //
  704. goto LookupNamesFinish;
  705. }
  706. //
  707. // Allocate Output Sids array buffer.
  708. //
  709. OutputSidsLength = Count * sizeof(LSA_TRANSLATED_SID_EX2);
  710. OutputSids = MIDL_user_allocate(OutputSidsLength);
  711. if (OutputSids == NULL) {
  712. Status = STATUS_INSUFFICIENT_RESOURCES;
  713. goto LookupNamesError;
  714. }
  715. TranslatedSids->Entries = Count;
  716. TranslatedSids->Sids = OutputSids;
  717. //
  718. // Initialize the Output Sids array. Zeroise all fields, then
  719. // Mark all of the Output Sids as being unknown initially and
  720. // set the DomainIndex fields to a negative number meaning
  721. // "no domain"
  722. //
  723. RtlZeroMemory( OutputSids, OutputSidsLength);
  724. for (NameIndex = 0; NameIndex < Count; NameIndex++) {
  725. OutputSids[NameIndex].Use = SidTypeUnknown;
  726. OutputSids[NameIndex].DomainIndex = LSA_UNKNOWN_INDEX;
  727. }
  728. //
  729. // Create an empty Referenced Domain List.
  730. //
  731. Status = LsapDbLookupCreateListReferencedDomains( ReferencedDomains, 0 );
  732. if (!NT_SUCCESS(Status)) {
  733. goto LookupNamesError;
  734. }
  735. //
  736. // Obtain the Trust Information for the
  737. // Built-in, Account and Primary Domains.
  738. //
  739. Status = LsapDbLookupLocalDomains(
  740. &BuiltInDomainTrustInformation,
  741. &AccountDomainTrustInformation,
  742. &PrimaryDomainTrustInformation
  743. );
  744. if (!NT_SUCCESS(Status)) {
  745. goto LookupNamesError;
  746. }
  747. if ( ((DomainLookupScope & LSAP_LOOKUP_DNS_SUPPORT) == 0)
  748. && (LookupLevel == LsapLookupPDC) ) {
  749. //
  750. // We don't want to expose dns names to downlevel
  751. // clients
  752. //
  753. RtlInitUnicodeString( (UNICODE_STRING*) &AccountDomainTrustInformation.DomainName, NULL );
  754. RtlInitUnicodeString( (UNICODE_STRING*) &PrimaryDomainTrustInformation.DomainName, NULL );
  755. }
  756. //
  757. // The local domains to be searched always include the Accounts
  758. // domain. For initial lookup targets only, the BUILT_IN domain is
  759. // also searched.
  760. //
  761. LocalDomainsToSearch = LSAP_DB_SEARCH_ACCOUNT_DOMAIN;
  762. if (LookupLevel == LsapLookupWksta) {
  763. LocalDomainsToSearch |= LSAP_DB_SEARCH_BUILT_IN_DOMAIN;
  764. //
  765. // This is the lowest Lookup Level, normally targeted at a
  766. // Workstation.
  767. //
  768. }
  769. ASSERT( (LookupLevel == LsapLookupWksta)
  770. || (LookupLevel == LsapLookupPDC)
  771. || (LookupLevel == LsapLookupTDL)
  772. || (LookupLevel == LsapLookupGC)
  773. || (LookupLevel == LsapLookupXForestResolve) );
  774. Status = LsapDbLookupSimpleNames(
  775. Count,
  776. LookupLevel,
  777. Names,
  778. PrefixNames,
  779. SuffixNames,
  780. &BuiltInDomainTrustInformation,
  781. &AccountDomainTrustInformation,
  782. &PrimaryDomainTrustInformation,
  783. *ReferencedDomains,
  784. TranslatedSids,
  785. MappedCount,
  786. &CompletelyUnmappedCount
  787. );
  788. if (!NT_SUCCESS(Status)) {
  789. goto LookupNamesError;
  790. }
  791. //
  792. // If all Names are now mapped or partially mapped, or only zero
  793. // length names remain, finish.
  794. //
  795. NullNameCount = 0;
  796. for( NameIndex = 0; NameIndex < Count; NameIndex++) {
  797. if (Names[NameIndex].Length == 0) {
  798. NullNameCount++;
  799. }
  800. }
  801. if (CompletelyUnmappedCount == NullNameCount) {
  802. goto LookupNamesFinish;
  803. }
  804. //
  805. // There are some remaining unmapped Names. They may belong to a
  806. // local SAM Domain. Currently, there are two such domains, the
  807. // Built-in Domain and the Accounts Domain. Search these
  808. // domains now, excluding the BUILT_IN domain from higher level
  809. // searches.
  810. //
  811. if ( LookupLevel != LsapLookupGC ) {
  812. ASSERT( (LookupLevel == LsapLookupWksta)
  813. || (LookupLevel == LsapLookupPDC)
  814. || (LookupLevel == LsapLookupTDL)
  815. || (LookupLevel == LsapLookupXForestResolve) );
  816. Status = LsapDbLookupNamesInLocalDomains(
  817. Count,
  818. Names,
  819. PrefixNames,
  820. SuffixNames,
  821. &BuiltInDomainTrustInformation,
  822. &AccountDomainTrustInformation,
  823. *ReferencedDomains,
  824. TranslatedSids,
  825. MappedCount,
  826. &CompletelyUnmappedCount,
  827. LocalDomainsToSearch
  828. );
  829. if (!NT_SUCCESS(Status)) {
  830. goto LookupNamesError;
  831. }
  832. }
  833. //
  834. // If all Names apart from NULL names are now mapped, finish.
  835. //
  836. if (CompletelyUnmappedCount == NullNameCount) {
  837. goto LookupNamesFinish;
  838. }
  839. //
  840. // Not all of the Names have been identified in the local domain(s).
  841. // The next step in the search depends on the level of this lookup
  842. // and how we are configured as follows:
  843. //
  844. // Lookup Level Configuration Lookup search next
  845. //
  846. // LsapLookupWksta Win Nt Primary Domain
  847. // LanMan Nt Trusted Domains
  848. //
  849. // LsapLookupPDC Win Nt error
  850. // LanMan Nt Trusted Domains
  851. //
  852. // LsaLookupTDL Win Nt error
  853. // LanMan Nt none
  854. //
  855. if (LookupLevel == LsapLookupWksta) {
  856. if (LsapProductType != NtProductLanManNt) {
  857. ULONG MappedByCache = *MappedCount;
  858. //
  859. // Try the cache first
  860. //
  861. Status = LsapDbMapCachedNames(
  862. LookupOptions,
  863. (PUNICODE_STRING) SuffixNames,
  864. (PUNICODE_STRING) PrefixNames,
  865. Count,
  866. FALSE, // don't use old entries
  867. *ReferencedDomains,
  868. TranslatedSids,
  869. MappedCount
  870. );
  871. if (!NT_SUCCESS(Status)) {
  872. goto LookupNamesError;
  873. }
  874. MappedByCache = *MappedCount - MappedByCache;
  875. CompletelyUnmappedCount -= MappedByCache;
  876. if (*MappedCount == Count) {
  877. goto LookupNamesFinish;
  878. }
  879. //
  880. // If there is no Primary Domain as in the case of a WORKGROUP,
  881. // just finish up. Set a default result code STATUS_SUCCESS.
  882. //
  883. Status = STATUS_SUCCESS;
  884. if (PrimaryDomainTrustInformation.Sid == NULL) {
  885. goto LookupNamesFinish;
  886. }
  887. //
  888. // There is a Primary Domain. Search it for Names. Since a
  889. // Primary Domain is also a Trusted Domain, we use the
  890. // Trusted Domain search routine. This routine will "hand off"
  891. // the search to a Domain Controller's LSA.
  892. //
  893. Status = LsapDbLookupNamesInPrimaryDomain(
  894. LookupOptions,
  895. Count,
  896. Names,
  897. PrefixNames,
  898. SuffixNames,
  899. &PrimaryDomainTrustInformation,
  900. *ReferencedDomains,
  901. TranslatedSids,
  902. LsapLookupPDC,
  903. MappedCount,
  904. &CompletelyUnmappedCount,
  905. &fDownlevelSecureChannel,
  906. &TempStatus
  907. );
  908. if (!NT_SUCCESS(Status)) {
  909. goto LookupNamesError;
  910. }
  911. if (TempStatus == STATUS_TRUSTED_RELATIONSHIP_FAILURE) {
  912. //
  913. // We could not talk to a DC -- Hit the cache again
  914. // looking for non-expired entries
  915. //
  916. MappedByCache = *MappedCount;
  917. Status = LsapDbMapCachedNames(LookupOptions,
  918. (PUNICODE_STRING) SuffixNames,
  919. (PUNICODE_STRING) PrefixNames,
  920. Count,
  921. TRUE, // Use old entries
  922. *ReferencedDomains,
  923. TranslatedSids,
  924. MappedCount);
  925. if (!NT_SUCCESS(Status)) {
  926. //
  927. // This is a fatal resource error
  928. //
  929. goto LookupNamesError;
  930. }
  931. MappedByCache = *MappedCount - MappedByCache;
  932. CompletelyUnmappedCount -= MappedByCache;
  933. }
  934. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  935. SecondaryStatus = TempStatus;
  936. }
  937. //
  938. // If we are talking to a downlevel server and we are in an
  939. // nt5 domain, then attempt to resolve the unresolved names at a GC
  940. //
  941. if ( fDownlevelSecureChannel
  942. && PrimaryDomainTrustInformation.DomainName.Length > 0 ) {
  943. Status = LsapDbLookupNamesInGlobalCatalogWks(
  944. LookupOptions,
  945. Count,
  946. Names,
  947. PrefixNames,
  948. SuffixNames,
  949. *ReferencedDomains,
  950. TranslatedSids,
  951. MappedCount,
  952. &CompletelyUnmappedCount,
  953. &TempStatus
  954. );
  955. if (!NT_SUCCESS(Status)) {
  956. goto LookupNamesError;
  957. }
  958. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  959. SecondaryStatus = TempStatus;
  960. }
  961. }
  962. goto LookupNamesFinish;
  963. }
  964. }
  965. //
  966. // We reach here in two cases:
  967. //
  968. // * Initial Level lookups targeted at DC's
  969. // * Higher Level Lookups (must be targeted at DC's)
  970. //
  971. // For the highest level lookup, that on an individual TDC, there
  972. // is no more searching to do, since we have already searched the
  973. // Accounts Domain and we do not follow trust relationships on DC's
  974. // beyond one level.
  975. //
  976. if (LookupLevel == LsapLookupTDL) {
  977. goto LookupNamesFinish;
  978. }
  979. ASSERT( (LookupLevel == LsapLookupWksta)
  980. || (LookupLevel == LsapLookupPDC)
  981. || (LookupLevel == LsapLookupGC)
  982. || (LookupLevel == LsapLookupXForestResolve) );
  983. //
  984. // We are either the initial target of the lookup but not configured
  985. // as a workstation, or we are the target of a Primary Domain
  986. // level lookup. In either case, we must be configured as a DC.
  987. //
  988. if (LsapProductType != NtProductLanManNt) {
  989. Status = STATUS_DOMAIN_CTRLR_CONFIG_ERROR;
  990. goto LookupNamesError;
  991. }
  992. if (DomainLookupScope & LSAP_LOOKUP_RESOLVE_ISOLATED_DOMAINS) {
  993. //
  994. // Check for isolated domain names
  995. //
  996. PreviousMappedCount = *MappedCount;
  997. Status = LsapDbLookupNamesAsDomainNames(DomainLookupScope,
  998. Count,
  999. Names,
  1000. PrefixNames,
  1001. SuffixNames,
  1002. *ReferencedDomains,
  1003. TranslatedSids,
  1004. MappedCount);
  1005. if (!NT_SUCCESS(Status)) {
  1006. goto LookupNamesError;
  1007. }
  1008. CompletelyUnmappedCount -= (*MappedCount - PreviousMappedCount);
  1009. //
  1010. // If all of the Names have now been mapped, finish.
  1011. //
  1012. if (*MappedCount == Count) {
  1013. goto LookupNamesFinish;
  1014. }
  1015. }
  1016. if (DomainLookupScope & LSAP_LOOKUP_TRUSTED_DOMAIN_TRANSITIVE) {
  1017. //
  1018. // Search in a global catalog for names that belong to post nt4 domains
  1019. //
  1020. Status = LsapDbLookupNamesInGlobalCatalog(
  1021. LookupOptions,
  1022. Count,
  1023. Names,
  1024. PrefixNames,
  1025. SuffixNames,
  1026. *ReferencedDomains,
  1027. TranslatedSids,
  1028. MappedCount,
  1029. &CompletelyUnmappedCount,
  1030. &TempStatus
  1031. );
  1032. if (!NT_SUCCESS(Status)) {
  1033. goto LookupNamesError;
  1034. }
  1035. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  1036. SecondaryStatus = TempStatus;
  1037. }
  1038. }
  1039. if (DomainLookupScope & LSAP_LOOKUP_TRUSTED_FOREST) {
  1040. ASSERT( (LookupLevel == LsapLookupWksta)
  1041. || (LookupLevel == LsapLookupPDC)
  1042. || (LookupLevel == LsapLookupGC));
  1043. Status = LsapDbLookupNamesInTrustedForests(
  1044. LookupOptions,
  1045. Count,
  1046. Names,
  1047. PrefixNames,
  1048. SuffixNames,
  1049. *ReferencedDomains,
  1050. TranslatedSids,
  1051. MappedCount,
  1052. &CompletelyUnmappedCount,
  1053. &TempStatus
  1054. );
  1055. if (!NT_SUCCESS(Status)) {
  1056. goto LookupNamesError;
  1057. }
  1058. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  1059. SecondaryStatus = TempStatus;
  1060. }
  1061. }
  1062. if (DomainLookupScope & LSAP_LOOKUP_TRUSTED_DOMAIN_DIRECT) {
  1063. ASSERT((LookupLevel == LsapLookupWksta)
  1064. || (LookupLevel == LsapLookupPDC));
  1065. //
  1066. // Search all of the Trusted Domains
  1067. //
  1068. Status = LsapDbLookupNamesInTrustedDomains(
  1069. LookupOptions,
  1070. Count,
  1071. !(DomainLookupScope & LSAP_LOOKUP_TRUSTED_DOMAIN_TRANSITIVE),
  1072. // if we didn't go the GC, then
  1073. // include intraforest trusts
  1074. Names,
  1075. PrefixNames,
  1076. SuffixNames,
  1077. *ReferencedDomains,
  1078. TranslatedSids,
  1079. LsapLookupTDL,
  1080. MappedCount,
  1081. &CompletelyUnmappedCount,
  1082. &TempStatus
  1083. );
  1084. if (!NT_SUCCESS(Status)) {
  1085. goto LookupNamesError;
  1086. }
  1087. if ( !NT_SUCCESS( TempStatus ) && NT_SUCCESS( SecondaryStatus ) ) {
  1088. SecondaryStatus = TempStatus;
  1089. }
  1090. }
  1091. LookupNamesFinish:
  1092. //
  1093. // If some but not all Names were mapped, return informational status
  1094. // STATUS_SOME_NOT_MAPPED. If no Names were mapped, return error
  1095. // STATUS_NONE_MAPPED. Note that we expect and STATUS_NONE_MAPPED
  1096. // errors returned by called routines to have been suppressed before
  1097. // we get here. The reason for this is that we need to calculate
  1098. // the return Status based on the whole set of Names, not some subset
  1099. //
  1100. if (NT_SUCCESS(Status)) {
  1101. if (*MappedCount < Count) {
  1102. Status = STATUS_SOME_NOT_MAPPED;
  1103. if (*MappedCount == 0) {
  1104. Status = STATUS_NONE_MAPPED;
  1105. }
  1106. }
  1107. }
  1108. //
  1109. // If no names could be mapped it is likely due to the
  1110. // secondary status
  1111. //
  1112. if ( (STATUS_NONE_MAPPED == Status)
  1113. && (STATUS_NONE_MAPPED != SecondaryStatus)
  1114. && LsapRevisionCanHandleNewErrorCodes( ClientRevision )
  1115. && !NT_SUCCESS( SecondaryStatus ) ) {
  1116. Status = SecondaryStatus;
  1117. goto LookupNamesError;
  1118. }
  1119. //
  1120. // If necessary, free the arrays of PrefixNames and SuffixNames
  1121. //
  1122. if (PrefixNames != NULL) {
  1123. MIDL_user_free(PrefixNames);
  1124. }
  1125. if (SuffixNames != NULL) {
  1126. MIDL_user_free(SuffixNames);
  1127. }
  1128. LsapTraceEvent(EVENT_TRACE_TYPE_END, LsaTraceEvent_LookupNames);
  1129. LsarpReturnPrologue();
  1130. return(Status);
  1131. LookupNamesError:
  1132. //
  1133. // If the LookupLevel is the lowest (Workstation Level) free up
  1134. // the Sids and Referenced Domains arrays.
  1135. //
  1136. if (LookupLevel == LsapLookupWksta) {
  1137. //
  1138. // If necessary, free the Sids array.
  1139. //
  1140. if (TranslatedSids->Sids != NULL) {
  1141. ULONG i;
  1142. for (i = 0; i < TranslatedSids->Entries; i++) {
  1143. if (TranslatedSids->Sids[i].Sid) {
  1144. // N.B. The SID is not an embedded field server side
  1145. MIDL_user_free(TranslatedSids->Sids[i].Sid);
  1146. TranslatedSids->Sids[i].Sid = NULL;
  1147. }
  1148. }
  1149. MIDL_user_free( TranslatedSids->Sids );
  1150. TranslatedSids->Sids = NULL;
  1151. }
  1152. //
  1153. // If necessary, free the Referenced Domain List.
  1154. //
  1155. if (*ReferencedDomains != NULL) {
  1156. Domains = (*ReferencedDomains)->Domains;
  1157. if (Domains != NULL) {
  1158. for (DomainIndex = 0;
  1159. DomainIndex < (*ReferencedDomains)->Entries;
  1160. DomainIndex++) {
  1161. if (Domains[ DomainIndex ].Name.Buffer != NULL) {
  1162. MIDL_user_free( Domains[ DomainIndex ].Name.Buffer );
  1163. Domains[ DomainIndex ].Name.Buffer = NULL;
  1164. }
  1165. if (Domains[ DomainIndex ].Sid != NULL) {
  1166. MIDL_user_free( Domains[ DomainIndex ].Sid );
  1167. Domains[ DomainIndex ].Sid = NULL;
  1168. }
  1169. }
  1170. MIDL_user_free( ( *ReferencedDomains)->Domains );
  1171. }
  1172. MIDL_user_free( *ReferencedDomains );
  1173. *ReferencedDomains = NULL;
  1174. }
  1175. }
  1176. //
  1177. // If the primary status was a success code, but the secondary
  1178. // status was an error, propagate the secondary status.
  1179. //
  1180. if ((!NT_SUCCESS(SecondaryStatus)) && NT_SUCCESS(Status)) {
  1181. Status = SecondaryStatus;
  1182. }
  1183. goto LookupNamesFinish;
  1184. }
  1185. NTSTATUS
  1186. LsapDbEnumerateNames(
  1187. IN LSAPR_HANDLE ContainerHandle,
  1188. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  1189. IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
  1190. OUT PLSAP_DB_NAME_ENUMERATION_BUFFER DbEnumerationBuffer,
  1191. IN ULONG PreferedMaximumLength
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. This function enumerates Names of objects of a given type within a container
  1196. object. Since there may be more information than can be returned in a
  1197. single call of the routine, multiple calls can be made to get all of the
  1198. information. To support this feature, the caller is provided with a
  1199. handle that can be used across calls. On the initial call,
  1200. EnumerationContext should point to a variable that has been initialized
  1201. to 0.
  1202. Arguments:
  1203. ContainerHandle - Handle to a container object.
  1204. ObjectTypeId - Type of object to be enumerated. The type must be one
  1205. for which all objects have Names.
  1206. EnumerationContext - API-specific handle to allow multiple calls
  1207. (see Routine Description above).
  1208. DbEnumerationBuffer - Receives a pointer to a structure that will receive
  1209. the count of entries returned in an enumeration information array, and
  1210. a pointer to the array. Currently, the only information returned is
  1211. the object Names. These Names may be used together with object type to
  1212. open the objects and obtain any further information available.
  1213. PreferedMaximumLength - prefered maximum length of returned data (in 8-bit
  1214. bytes). This is not a hard upper limit, but serves as a guide. Due to
  1215. data conversion between systems with different natural data sizes, the
  1216. actual amount of data returned may be greater than this value.
  1217. CountReturned - Pointer to variable which will receive a count of the
  1218. entries returned.
  1219. Return Values:
  1220. NTSTATUS - Standard Nt Result Code
  1221. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  1222. to complete the operation.
  1223. STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
  1224. is returned if there are no more objects to enumerate. Note that
  1225. zero or more objects may be enumerated on a call that returns this
  1226. reply.
  1227. --*/
  1228. {
  1229. NTSTATUS Status = STATUS_SUCCESS;
  1230. LSAP_DB_ENUMERATION_ELEMENT LastElement;
  1231. PLSAP_DB_ENUMERATION_ELEMENT FirstElement, NextElement = NULL, FreeElement;
  1232. ULONG DataLengthUsed;
  1233. ULONG ThisBufferLength;
  1234. PUNICODE_STRING Names = NULL;
  1235. BOOLEAN PreferedMaximumReached = FALSE;
  1236. ULONG EntriesRead;
  1237. ULONG Index, EnumerationIndex;
  1238. BOOLEAN TrustedClient = ((LSAP_DB_HANDLE) ContainerHandle)->Trusted;
  1239. LastElement.Next = NULL;
  1240. FirstElement = &LastElement;
  1241. //
  1242. // If no enumeration buffer provided, return an error.
  1243. //
  1244. if ( (!ARGUMENT_PRESENT(DbEnumerationBuffer)) ||
  1245. (!ARGUMENT_PRESENT(EnumerationContext )) ) {
  1246. return(STATUS_INVALID_PARAMETER);
  1247. }
  1248. //
  1249. // Enumerate objects, stopping when the length of data to be returned
  1250. // reaches or exceeds the Prefered Maximum Length, or reaches the
  1251. // absolute maximum allowed for LSA object enumerations. We allow
  1252. // the last object enumerated to bring the total amount of data to
  1253. // be returned beyond the Prefered Maximum Length, but not beyond the
  1254. // absolute maximum length.
  1255. //
  1256. EnumerationIndex = *EnumerationContext;
  1257. for(DataLengthUsed = 0, EntriesRead = 0;
  1258. DataLengthUsed < PreferedMaximumLength;
  1259. DataLengthUsed += ThisBufferLength, EntriesRead++) {
  1260. //
  1261. // If the absolute maximum length has been exceeded, back off
  1262. // the last object enumerated.
  1263. //
  1264. if ((DataLengthUsed > LSA_MAXIMUM_ENUMERATION_LENGTH) &&
  1265. (!TrustedClient)) {
  1266. //
  1267. // If PrefMaxLength is zero, NextElement may be NULL.
  1268. //
  1269. if (NextElement != NULL) {
  1270. FirstElement = NextElement->Next;
  1271. MIDL_user_free(NextElement);
  1272. }
  1273. break;
  1274. }
  1275. //
  1276. // Allocate memory for next enumeration element. Set the Name
  1277. // field to NULL for cleanup purposes.
  1278. //
  1279. NextElement = MIDL_user_allocate(sizeof (LSAP_DB_ENUMERATION_ELEMENT));
  1280. if (NextElement == NULL) {
  1281. Status = STATUS_INSUFFICIENT_RESOURCES;
  1282. break;
  1283. }
  1284. //
  1285. // Find the next object's Name, and fill in its object information.
  1286. // Note that memory will be allocated via MIDL_user_allocate
  1287. // and must be freed when no longer required.
  1288. //
  1289. Status = LsapDbFindNextName(
  1290. ContainerHandle,
  1291. &EnumerationIndex,
  1292. ObjectTypeId,
  1293. (PLSAPR_UNICODE_STRING) &NextElement->Name
  1294. );
  1295. //
  1296. // Stop the enumeration if any error or warning occurs. Note
  1297. // that the warning STATUS_NO_MORE_ENTRIES will be returned when
  1298. // we've gone beyond the last index.
  1299. //
  1300. if (Status != STATUS_SUCCESS) {
  1301. break;
  1302. }
  1303. //
  1304. // Get the length of the data allocated for the object's Name
  1305. //
  1306. ThisBufferLength = NextElement->Name.Length;
  1307. //
  1308. // Link the object just found to the front of the enumeration list
  1309. //
  1310. NextElement->Next = FirstElement;
  1311. FirstElement = NextElement;
  1312. }
  1313. //
  1314. // If an error other than STATUS_NO_MORE_ENTRIES occurred, return it.
  1315. //
  1316. if ((Status != STATUS_NO_MORE_ENTRIES) && !NT_SUCCESS(Status)) {
  1317. goto EnumerateNamesError;
  1318. }
  1319. //
  1320. // The enumeration is complete or has terminated because of return
  1321. // buffer limitations. If no entries were read, return.
  1322. //
  1323. if (EntriesRead != 0) {
  1324. //
  1325. // Some entries were read, allocate an information buffer for returning
  1326. // them.
  1327. //
  1328. Names = MIDL_user_allocate( sizeof (UNICODE_STRING) * EntriesRead );
  1329. if (Names == NULL) {
  1330. Status = STATUS_INSUFFICIENT_RESOURCES;
  1331. goto EnumerateNamesError;
  1332. }
  1333. //
  1334. // Memory was successfully allocated for the return buffer.
  1335. // Copy in the enumerated Names.
  1336. //
  1337. for (NextElement = FirstElement, Index = 0;
  1338. NextElement != &LastElement;
  1339. NextElement = NextElement->Next, Index++) {
  1340. ASSERT(Index < EntriesRead);
  1341. Names[Index] = NextElement->Name;
  1342. }
  1343. Status = STATUS_SUCCESS;
  1344. } else {
  1345. //
  1346. // No entries available this call.
  1347. //
  1348. Status = STATUS_NO_MORE_ENTRIES;
  1349. }
  1350. EnumerateNamesFinish:
  1351. //
  1352. // Free the enumeration element structures (if any).
  1353. //
  1354. for (NextElement = FirstElement; NextElement != &LastElement;) {
  1355. //
  1356. // If an error has occurred, dispose of memory allocated
  1357. // for any Names.
  1358. //
  1359. if (!(NT_SUCCESS(Status) || (Status == STATUS_NO_MORE_ENTRIES))) {
  1360. if (NextElement->Name.Buffer != NULL) {
  1361. MIDL_user_free(NextElement->Name.Buffer);
  1362. }
  1363. }
  1364. //
  1365. // Free the memory allocated for the enumeration element.
  1366. //
  1367. FreeElement = NextElement;
  1368. NextElement = NextElement->Next;
  1369. MIDL_user_free(FreeElement);
  1370. }
  1371. //
  1372. // Fill in return enumeration structure (0 and NULL in error case).
  1373. //
  1374. DbEnumerationBuffer->EntriesRead = EntriesRead;
  1375. DbEnumerationBuffer->Names = Names;
  1376. *EnumerationContext = EnumerationIndex;
  1377. return(Status);
  1378. EnumerateNamesError:
  1379. //
  1380. // If necessary, free memory allocated for returning the Names.
  1381. //
  1382. if (Names != NULL) {
  1383. MIDL_user_free( Names );
  1384. Names = NULL;
  1385. }
  1386. goto EnumerateNamesFinish;
  1387. }
  1388. VOID
  1389. LsapDbUpdateCountCompUnmappedNames(
  1390. OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  1391. IN OUT PULONG CompletelyUnmappedCount
  1392. )
  1393. /*++
  1394. Routine Description:
  1395. This function updates the count of completely unmapped names in a
  1396. name lookup operation. A name is completely unmapped if its domain
  1397. is unknown.
  1398. Arguments:
  1399. TranslatedSids - Pointer to a structure which will be initialized to
  1400. reference an array of records describing each translated Sid. The
  1401. nth entry in this array provides a translation for the nth element in
  1402. the Names parameter.
  1403. When this information is no longer needed, it must be released
  1404. by passing the returned pointer to LsaFreeMemory().
  1405. CompletelyUnmappedCount - Pointer to location that will receive
  1406. a count of completely unmapped Sids. A Name is completely unmapped
  1407. if it is isolated and unknown, or is composite and its Domain Prefix
  1408. component is not recognized as a Domain Name.
  1409. Return Values:
  1410. None
  1411. --*/
  1412. {
  1413. ULONG Count = TranslatedSids->Entries;
  1414. ULONG SidIndex;
  1415. ULONG UpdatedCompletelyUnmappedCount = 0;
  1416. for (SidIndex = 0; SidIndex < Count; SidIndex++) {
  1417. if (TranslatedSids->Sids[SidIndex].DomainIndex == LSA_UNKNOWN_INDEX) {
  1418. UpdatedCompletelyUnmappedCount++;
  1419. }
  1420. }
  1421. ASSERT(UpdatedCompletelyUnmappedCount <= *CompletelyUnmappedCount);
  1422. *CompletelyUnmappedCount = UpdatedCompletelyUnmappedCount;
  1423. }
  1424. NTSTATUS
  1425. LsapDbFindNextName(
  1426. IN LSAPR_HANDLE ContainerHandle,
  1427. IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
  1428. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  1429. OUT PLSAPR_UNICODE_STRING NextName
  1430. )
  1431. /*++
  1432. Routine Description:
  1433. This function finds the next Name of object of a given type within a
  1434. container object. The given object type must be one where objects
  1435. have Names. The Names returned can be used on subsequent open calls to
  1436. access the objects.
  1437. Arguments:
  1438. ContainerHandle - Handle to container object.
  1439. EnumerationContext - Pointer to a variable containing the index of
  1440. the object to be found. A zero value indicates that the first
  1441. object is to be found.
  1442. ObjectTypeId - Type of the objects whose Names are being enumerated.
  1443. Ccurrently, this is restricted to objects (such as Secret Objects)
  1444. that are accessed by Name only.
  1445. NextName - Pointer to Unicode String that will be initialized to
  1446. reference the next Name found.
  1447. Return Value:
  1448. NTSTATUS - Standard Nt Result Code
  1449. STATUS_INVALID_HANDLE - Invalid ContainerHandle specified
  1450. STATUS_NO_MORE_ENTRIES - Warning that no more entries exist.
  1451. --*/
  1452. {
  1453. NTSTATUS Status, SecondaryStatus;
  1454. ULONG NameKeyValueLength = 0;
  1455. LSAPR_UNICODE_STRING SubKeyNameU;
  1456. OBJECT_ATTRIBUTES ObjectAttributes;
  1457. HANDLE ContDirKeyHandle = NULL;
  1458. //
  1459. // Setup object attributes for opening the appropriate Containing
  1460. // Directory. For example, if we're looking for Account objects,
  1461. // the containing Directory is "Accounts". The Unicode strings for
  1462. // containing Directories are set up during Lsa Initialization.
  1463. //
  1464. InitializeObjectAttributes(
  1465. &ObjectAttributes,
  1466. &LsapDbContDirs[ObjectTypeId],
  1467. OBJ_CASE_INSENSITIVE,
  1468. ((LSAP_DB_HANDLE) ContainerHandle)->KeyHandle,
  1469. NULL
  1470. );
  1471. //
  1472. // If the object type is not accessed by Name only, return an error.
  1473. // Currently, only Secret objects have this property.
  1474. //
  1475. if (ObjectTypeId != SecretObject) {
  1476. return(STATUS_INVALID_PARAMETER);
  1477. }
  1478. Status = RtlpNtOpenKey(
  1479. &ContDirKeyHandle,
  1480. KEY_READ,
  1481. &ObjectAttributes,
  1482. 0
  1483. );
  1484. if (NT_SUCCESS(Status)) {
  1485. //
  1486. // Initialize the Unicode String in which the next object's Logical Name
  1487. // will be returned. The Logical Name of an object equals its Registry
  1488. // Key relative to its Containing Directory, and is also equal to
  1489. // the Relative Id of the object represented in character form as an
  1490. // 8-digit number with leading zeros.
  1491. //
  1492. // NOTE: The size of buffer allocated for the Logical Name must be
  1493. // calculated dynamically when the Registry supports long names, because
  1494. // it is possible that the Logical Name of an object will be equal to a
  1495. // character representation of the full Name, not just the Relative Id
  1496. // part.
  1497. //
  1498. SubKeyNameU.MaximumLength = (USHORT) LSAP_DB_LOGICAL_NAME_MAX_LENGTH;
  1499. SubKeyNameU.Length = 0;
  1500. SubKeyNameU.Buffer = MIDL_user_allocate(SubKeyNameU.MaximumLength);
  1501. if (SubKeyNameU.Buffer == NULL) {
  1502. Status = STATUS_INSUFFICIENT_RESOURCES;
  1503. } else {
  1504. //
  1505. // Now enumerate the next subkey.
  1506. //
  1507. Status = RtlpNtEnumerateSubKey(
  1508. ContDirKeyHandle,
  1509. (PUNICODE_STRING) &SubKeyNameU,
  1510. *EnumerationContext,
  1511. NULL
  1512. );
  1513. if (NT_SUCCESS(Status)) {
  1514. (*EnumerationContext)++;
  1515. //
  1516. // Return the Name.
  1517. //
  1518. *NextName = SubKeyNameU;
  1519. } else {
  1520. //
  1521. // Not successful - free the subkey name buffer
  1522. // Note that STATUS_NO_MORE_ENTRIES is a warning
  1523. // (not a success) code.
  1524. //
  1525. MIDL_user_free( SubKeyNameU.Buffer );
  1526. //
  1527. // Set the out parameter so RPC doesn't try
  1528. // to return anything.
  1529. //
  1530. NextName->Length = NextName->MaximumLength = 0;
  1531. NextName->Buffer = NULL;
  1532. }
  1533. }
  1534. //
  1535. // Close the containing directory handle
  1536. //
  1537. SecondaryStatus = NtClose(ContDirKeyHandle);
  1538. ASSERT(NT_SUCCESS(SecondaryStatus));
  1539. }
  1540. return(Status);
  1541. }
  1542. NTSTATUS
  1543. LsapDbLookupSimpleNames(
  1544. IN ULONG Count,
  1545. IN ULONG LookupLevel,
  1546. IN PLSAPR_UNICODE_STRING Names,
  1547. IN PLSAPR_UNICODE_STRING PrefixNames,
  1548. IN PLSAPR_UNICODE_STRING SuffixNames,
  1549. IN PLSAPR_TRUST_INFORMATION BuiltInDomainTrustInformation,
  1550. IN PLSAPR_TRUST_INFORMATION_EX AccountDomainTrustInformation,
  1551. IN PLSAPR_TRUST_INFORMATION_EX PrimaryDomainTrustInformation,
  1552. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  1553. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  1554. IN OUT PULONG MappedCount,
  1555. IN OUT PULONG CompletelyUnmappedCount
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. This function attempts to identify isolated names as the names of well known
  1560. Sids or Domains present on the Lookup Path.
  1561. Names may be either isolated (e.g. JohnH) or composite names containing
  1562. both the domain name and account name. Composite names must include a
  1563. backslash character separating the domain name from the account name
  1564. (e.g. Acctg\JohnH). An isolated name may be either an account name
  1565. (user, group, or alias) or a domain name.
  1566. Translation of isolated names introduces the possibility of name
  1567. collisions (since the same name may be used in multiple domains). An
  1568. isolated name will be translated using the following algorithm:
  1569. If the name is a well-known name (e.g. Local or Interactive), then the
  1570. corresponding well-known Sid is returned.
  1571. If the name is the Built-in Domain's name, then that domain's Sid
  1572. will be returned.
  1573. If the name is the Account Domain's name, then that domain's Sid
  1574. will be returned.
  1575. If the name is the Primary Domain's name, then that domain's Sid will
  1576. be returned.
  1577. If the name is the name of one of the Primary Domain's Trusted Domains,
  1578. then that domain's Sid will be returned.
  1579. If the name is a user, group, or alias in the Built-in Domain, then the
  1580. Sid of that account is returned.
  1581. If the name is a user, group, or alias in the Primary Domain, then the
  1582. Sid of that account is returned.
  1583. Otherwise, the name is not translated.
  1584. NOTE: Proxy, Machine, and Trust user accounts are not referenced
  1585. for name translation. Only normal user accounts are used for ID
  1586. translation. If translation of other account types is needed, then
  1587. SAM services should be used directly.
  1588. Arguments:
  1589. Count - Specifies the number of names to be translated.
  1590. Names - Pointer to an array of Count Unicode String structures
  1591. specifying the names to be looked up and mapped to Sids.
  1592. The strings may be names of User, Group or Alias accounts or
  1593. domains.
  1594. PrefixNames - Pointer to an array of Count Unicode String structures
  1595. containing the Prefix portions of the Names. Names having no
  1596. Prefix are called Isolated Names. For these, the Unicode String
  1597. structure is set to contain a zero Length.
  1598. SuffixNames - Pointer to an array of Count Unicode String structures
  1599. containing the Suffix portions of the Names.
  1600. ReferencedDomains - Pointer to a structure in which the list of domains
  1601. used in the translation is maintained. The entries in this structure
  1602. are referenced by the structure returned via the Sids parameter.
  1603. Unlike the Sids parameter, which contains an array entry for each
  1604. translated name, this structure will only contain one component for
  1605. each domain utilized in the translation.
  1606. TranslatedSids - Pointer to a structure in which the translations to Sids
  1607. corresponding to the Names specified on Names is maintained. The
  1608. nth entry in this array provides a translation (where known) for the
  1609. nth element in the Names parameter.
  1610. MappedCount - Pointer to location in which a count of the Names that
  1611. have been completely translated is maintained.
  1612. CompletelyUnmappedCount - Pointer to a location in which a count of the
  1613. Names that have not been translated (either partially, by identification
  1614. of a Domain Prefix, or completely) is maintained.
  1615. Return Values:
  1616. NTSTATUS - Standard Nt Result Code
  1617. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  1618. to complete the operation.
  1619. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  1620. to complete the call.
  1621. --*/
  1622. {
  1623. NTSTATUS Status = STATUS_SUCCESS;
  1624. //
  1625. // First, lookup any Well Known Names
  1626. //
  1627. if ( LookupLevel == LsapLookupWksta ) {
  1628. //
  1629. // This lookup should only be done once and be done at the first
  1630. // level
  1631. //
  1632. Status = LsapDbLookupWellKnownNames(
  1633. Count,
  1634. Names,
  1635. PrefixNames,
  1636. SuffixNames,
  1637. ReferencedDomains,
  1638. TranslatedSids,
  1639. MappedCount,
  1640. CompletelyUnmappedCount
  1641. );
  1642. if (!NT_SUCCESS(Status)) {
  1643. goto LookupSimpleNamesError;
  1644. }
  1645. //
  1646. // If all of the Names have now been mapped, finish.
  1647. //
  1648. if (*MappedCount == Count) {
  1649. goto LookupSimpleNamesFinish;
  1650. }
  1651. }
  1652. //
  1653. // Next, attempt to identify Isolated Names as Domain Names
  1654. //
  1655. if ( (LookupLevel == LsapLookupWksta)
  1656. || (LookupLevel == LsapLookupPDC) ) {
  1657. //
  1658. // This step should be done once at the first level to findstr
  1659. // local domain names (ie local accounts at a workstation) and
  1660. // then again at second level to find trusted domain names
  1661. //
  1662. Status = LsapDbLookupIsolatedDomainNames(
  1663. Count,
  1664. Names,
  1665. PrefixNames,
  1666. SuffixNames,
  1667. BuiltInDomainTrustInformation,
  1668. AccountDomainTrustInformation,
  1669. PrimaryDomainTrustInformation,
  1670. ReferencedDomains,
  1671. TranslatedSids,
  1672. MappedCount,
  1673. CompletelyUnmappedCount
  1674. );
  1675. if (!NT_SUCCESS(Status)) {
  1676. goto LookupSimpleNamesError;
  1677. }
  1678. }
  1679. LookupSimpleNamesFinish:
  1680. return(Status);
  1681. LookupSimpleNamesError:
  1682. goto LookupSimpleNamesFinish;
  1683. }
  1684. NTSTATUS
  1685. LsapDbLookupWellKnownNames(
  1686. IN ULONG Count,
  1687. IN PLSAPR_UNICODE_STRING Names,
  1688. IN PLSAPR_UNICODE_STRING PrefixNames,
  1689. IN PLSAPR_UNICODE_STRING SuffixNames,
  1690. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  1691. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  1692. IN OUT PULONG MappedCount,
  1693. IN OUT PULONG CompletelyUnmappedCount
  1694. )
  1695. /*++
  1696. Routine Description:
  1697. This function attempts to identify names as the names of well known Sids.
  1698. Names may be either isolated (e.g. JohnH) or composite names containing
  1699. both the domain name and account name. Composite names must include a
  1700. backslash character separating the domain name from the account name
  1701. (e.g. Acctg\JohnH). An isolated name may be either an account name
  1702. (user, group, or alias) or a domain name.
  1703. Translation of isolated names introduces the possibility of name
  1704. collisions (since the same name may be used in multiple domains). An
  1705. isolated name will be translated using the following algorithm:
  1706. If the name is a well-known name (e.g. Local or Interactive), then the
  1707. corresponding well-known Sid is returned.
  1708. If the name is the Built-in Domain's name, then that domain's Sid
  1709. will be returned.
  1710. If the name is the Account Domain's name, then that domain's Sid
  1711. will be returned.
  1712. If the name is the Primary Domain's name, then that domain's Sid will
  1713. be returned.
  1714. If the name is the name of one of the Primary Domain's Trusted Domains,
  1715. then that domain's Sid will be returned.
  1716. If the name is a user, group, or alias in the Built-in Domain, then the
  1717. Sid of that account is returned.
  1718. If the name is a user, group, or alias in the Primary Domain, then the
  1719. Sid of that account is returned.
  1720. Otherwise, the name is not translated.
  1721. NOTE: Proxy, Machine, and Trust user accounts are not referenced
  1722. for name translation. Only normal user accounts are used for ID
  1723. translation. If translation of other account types is needed, then
  1724. SAM services should be used directly.
  1725. Arguments:
  1726. Count - Specifies the number of names to be translated.
  1727. Names - Pointer to an array of Count Unicode String structures
  1728. specifying the names to be looked up and mapped to Sids.
  1729. The strings may be names of User, Group or Alias accounts or
  1730. domains.
  1731. PrefixNames - Pointer to an array of Count Unicode String structures
  1732. containing the Prefix portions of the Names. Names having no
  1733. Prefix are called Isolated Names. For these, the Unicode String
  1734. structure is set to contain a zero Length.
  1735. SuffixNames - Pointer to an array of Count Unicode String structures
  1736. containing the Suffix portions of the Names.
  1737. ReferencedDomains - Pointer to a structure in which the list of domains
  1738. used in the translation is maintained. The entries in this structure
  1739. are referenced by the structure returned via the Sids parameter.
  1740. Unlike the Sids parameter, which contains an array entry for each
  1741. translated name, this structure will only contain one component for
  1742. each domain utilized in the translation.
  1743. TranslatedSids - Pointer to a structure in which the translations to Sids
  1744. corresponding to the Names specified on Names is maintained. The
  1745. nth entry in this array provides a translation (where known) for the
  1746. nth element in the Names parameter.
  1747. MappedCount - Pointer to location in which a count of the Names that
  1748. have been completely translated is maintained.
  1749. CompletelyUnmappedCount - Pointer to a location in which a count of the
  1750. Names that have not been translated (either partially, by identification
  1751. of a Domain Prefix, or completely) is maintained.
  1752. Return Values:
  1753. NTSTATUS - Standard Nt Result Code
  1754. STATUS_SUCCESS - The call completed successfully. Note that some
  1755. or all of the Names may remain partially or completely unmapped.
  1756. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  1757. to complete the operation.
  1758. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  1759. to complete the call.
  1760. --*/
  1761. {
  1762. NTSTATUS Status = STATUS_SUCCESS;
  1763. ULONG UpdatedMappedCount;
  1764. ULONG NameNumber;
  1765. ULONG UnmappedNamesRemaining;
  1766. PLSAPR_TRANSLATED_SID_EX2 OutputSids;
  1767. LSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex;
  1768. LSAPR_TRUST_INFORMATION TrustInformation;
  1769. UCHAR SubAuthorityCount;
  1770. PLSAPR_SID Sid = NULL;
  1771. PLSAPR_SID PrefixSid = NULL;
  1772. ULONG PrefixSidLength;
  1773. ULONG RelativeId;
  1774. OutputSids = TranslatedSids->Sids;
  1775. //
  1776. // Initialize output parameters.
  1777. //
  1778. *MappedCount = UpdatedMappedCount = 0;
  1779. UnmappedNamesRemaining = Count - UpdatedMappedCount;
  1780. //
  1781. // Attempt to identify Names as Well Known Isolated Names
  1782. //
  1783. for (NameNumber = 0;
  1784. (NameNumber < Count) && (UnmappedNamesRemaining > 0);
  1785. NameNumber++) {
  1786. //
  1787. // Examine the next entry in the Names array. If the corresponding
  1788. // translated Sid entry has SidTypeUnknown for its Use field, the
  1789. // name has not been translated.
  1790. //
  1791. if (OutputSids[NameNumber].Use == SidTypeUnknown) {
  1792. //
  1793. // Attempt to identify the name as the name of a Well Known Sid
  1794. // by using the Well Known Sids table. We skip entries in the
  1795. // table for Sids that are also in the Built In domain. For
  1796. // those, we drop through to the Built in Domain search. Note
  1797. // that only one of these, the Administrators alias is currently
  1798. // present in the table.
  1799. //
  1800. DWORD dwMatchType = LOOKUP_MATCH_NONE;
  1801. UNICODE_STRING NTAuthorityName = { sizeof(NTAUTHORITY_NAME) - 2,
  1802. sizeof(NTAUTHORITY_NAME),
  1803. NTAUTHORITY_NAME };
  1804. if (PrefixNames[NameNumber].Length == 0)
  1805. {
  1806. dwMatchType = LOOKUP_MATCH_BOTH;
  1807. }
  1808. else if (RtlEqualUnicodeString( (PUNICODE_STRING) &PrefixNames[NameNumber],
  1809. &WellKnownSids[LsapLocalSystemSidIndex].DomainName,
  1810. TRUE) )
  1811. {
  1812. dwMatchType = LOOKUP_MATCH_LOCALIZED;
  1813. }
  1814. if (RtlEqualUnicodeString( (PUNICODE_STRING) &PrefixNames[NameNumber],
  1815. &NTAuthorityName,
  1816. TRUE) )
  1817. {
  1818. if (dwMatchType == LOOKUP_MATCH_NONE)
  1819. {
  1820. dwMatchType = LOOKUP_MATCH_HARDCODED;
  1821. }
  1822. else
  1823. {
  1824. ASSERT(dwMatchType == LOOKUP_MATCH_LOCALIZED);
  1825. dwMatchType = LOOKUP_MATCH_BOTH;
  1826. }
  1827. }
  1828. //
  1829. // Ignore SIDs from the BUILTIN domain since their names may
  1830. // change (i.e., we always want SAM to resolve those with the
  1831. // most up-to-date information).
  1832. //
  1833. if ((dwMatchType != LOOKUP_MATCH_NONE)
  1834. &&
  1835. LsapDbLookupIndexWellKnownName(
  1836. &SuffixNames[NameNumber],
  1837. &WellKnownSidIndex,
  1838. dwMatchType)
  1839. &&
  1840. !SID_IS_RESOLVED_BY_SAM(WellKnownSidIndex))
  1841. {
  1842. //
  1843. // Name is identified. Obtain its Sid. If the
  1844. // SubAuthorityCount for the Sid is positive, extract the
  1845. // Relative Id and place in the translated Sid entry,
  1846. // otherwise store LSA_UNKNOWN_INDEX there.
  1847. //
  1848. Sid = LsapDbWellKnownSid(WellKnownSidIndex);
  1849. SubAuthorityCount = *RtlSubAuthorityCountSid((PSID) Sid);
  1850. RelativeId = LSA_UNKNOWN_ID;
  1851. PrefixSid = NULL;
  1852. //
  1853. // Get the Sid's Use.
  1854. //
  1855. OutputSids[NameNumber].Use =
  1856. LsapDbWellKnownSidNameUse(WellKnownSidIndex);
  1857. //
  1858. // If the Sid is a Domain Sid, store pointer to
  1859. // it in the Trust Information.
  1860. //
  1861. if (OutputSids[NameNumber].Use == SidTypeDomain) {
  1862. TrustInformation.Sid = Sid;
  1863. } else {
  1864. //
  1865. // The Sid is not a domain Sid. Construct the Relative Id
  1866. // and Prefix Sid. This is equal to the original Sid
  1867. // excluding the lowest subauthority (Relative id).
  1868. //
  1869. if (SubAuthorityCount > 0) {
  1870. RelativeId = *RtlSubAuthoritySid((PSID) Sid, SubAuthorityCount - 1);
  1871. }
  1872. PrefixSidLength = RtlLengthRequiredSid(
  1873. SubAuthorityCount - 1
  1874. );
  1875. PrefixSid = MIDL_user_allocate( PrefixSidLength );
  1876. if (PrefixSid == NULL) {
  1877. Status = STATUS_INSUFFICIENT_RESOURCES;
  1878. break;
  1879. }
  1880. RtlCopyMemory( PrefixSid, Sid, PrefixSidLength );
  1881. (*RtlSubAuthorityCountSid( (PSID) PrefixSid ))--;
  1882. TrustInformation.Sid = PrefixSid;
  1883. }
  1884. //
  1885. // Set the Relative Id. For a Domain Sid this is set to the
  1886. // Unknown Value.
  1887. //
  1888. Status = LsapRpcCopySid(NULL,
  1889. &OutputSids[NameNumber].Sid,
  1890. Sid);
  1891. if (!NT_SUCCESS(Status)) {
  1892. break;
  1893. }
  1894. //
  1895. // Lookup this Domain Sid or Prefix Sid in the Referenced Domain
  1896. // List. If it is already there, return the DomainIndex for the
  1897. // existing entry and free up the memory allocated for the
  1898. // Prefix Sid (if any).
  1899. //
  1900. if (LsapDbLookupListReferencedDomains(
  1901. ReferencedDomains,
  1902. TrustInformation.Sid,
  1903. (PLONG) &OutputSids[NameNumber].DomainIndex
  1904. )) {
  1905. UnmappedNamesRemaining--;
  1906. if (PrefixSid != NULL) {
  1907. MIDL_user_free( PrefixSid );
  1908. PrefixSid = NULL;
  1909. }
  1910. continue;
  1911. }
  1912. //
  1913. // This Domain or Prefix Sid is not currently on the
  1914. // Referenced Domain List. Complete a Trust Information
  1915. // entry and add it to the List. Copy in the Domain Name
  1916. // (Domain Sids) or NULL string. Note that we use
  1917. // RtlCopyMemory to copy a UNICODE_STRING structure onto
  1918. // a LSAPR_UNICODE_STRING structure.
  1919. //
  1920. RtlCopyMemory(
  1921. &TrustInformation.Name,
  1922. &WellKnownSids[WellKnownSidIndex].DomainName,
  1923. sizeof(UNICODE_STRING)
  1924. );
  1925. //
  1926. // Make an entry in the list of Referenced Domains. Note
  1927. // that in the case of well-known Sids, the Prefix Sid
  1928. // may or may not be the Sid of a Domain. For those well
  1929. // known Sids whose Prefix Sid is not a domain Sid, the
  1930. // Name field in the Trust Information has been set to the
  1931. // NULL string.
  1932. //
  1933. Status = LsapDbLookupAddListReferencedDomains(
  1934. ReferencedDomains,
  1935. &TrustInformation,
  1936. (PLONG) &OutputSids[NameNumber].DomainIndex
  1937. );
  1938. if (!NT_SUCCESS(Status)) {
  1939. break;
  1940. }
  1941. //
  1942. // If we allocated memory for a Prefix Sid, free it.
  1943. //
  1944. if (PrefixSid != NULL) {
  1945. MIDL_user_free( PrefixSid );
  1946. PrefixSid = NULL;
  1947. }
  1948. UnmappedNamesRemaining--;
  1949. }
  1950. }
  1951. }
  1952. if (!NT_SUCCESS(Status)) {
  1953. goto LookupIsolatedWellKnownNamesError;
  1954. }
  1955. //
  1956. // Set the output parameters in the success case..
  1957. //
  1958. TranslatedSids->Sids = OutputSids;
  1959. TranslatedSids->Entries = Count;
  1960. *MappedCount = Count - UnmappedNamesRemaining;
  1961. *CompletelyUnmappedCount = UnmappedNamesRemaining;
  1962. LookupIsolatedWellKnownNamesFinish:
  1963. //
  1964. // If we still have memory allocated for the a Prefix Sid, free it.
  1965. //
  1966. if (PrefixSid != NULL) {
  1967. MIDL_user_free( PrefixSid );
  1968. PrefixSid = NULL;
  1969. }
  1970. return(Status);
  1971. LookupIsolatedWellKnownNamesError:
  1972. goto LookupIsolatedWellKnownNamesFinish;
  1973. }
  1974. BOOLEAN
  1975. LsapDbLookupIndexWellKnownName(
  1976. IN OPTIONAL PLSAPR_UNICODE_STRING Name,
  1977. OUT PLSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex,
  1978. IN DWORD dwMatchType
  1979. )
  1980. /*++
  1981. Routine Description:
  1982. This function looks up a Name to determine if it is well-known. If so,
  1983. an index into the table of well-known Sids is returned.
  1984. Arguments:
  1985. Name - Pointer to Name to be looked up. If a NULL pointer or
  1986. pointer to a zero length string is specified, FALSE will
  1987. always be returned.
  1988. WellKnownSidIndex - Pointer to variable that will receive the
  1989. index of the Name if well known.
  1990. dwMatchType - Constant indicating that the name's prefix matched
  1991. a well-known hardcoded prefix or both the hardcoded and
  1992. localized prefixes.
  1993. Return Value:
  1994. BOOLEAN - TRUE if the Name is well-known, else FALSE
  1995. --*/
  1996. {
  1997. LSAP_WELL_KNOWN_SID_INDEX Index;
  1998. PLSAPR_UNICODE_STRING MatchName = NULL;
  1999. BOOLEAN BooleanStatus = FALSE;
  2000. if ((!ARGUMENT_PRESENT(Name)) || Name->Length == 0 ) {
  2001. return(FALSE);
  2002. }
  2003. if (dwMatchType == LOOKUP_MATCH_HARDCODED
  2004. ||
  2005. dwMatchType == LOOKUP_MATCH_BOTH)
  2006. {
  2007. //
  2008. // This means the domain name was "NT AUTHORITY" -- check
  2009. // the suffix for LocalService, NetworkService, or System
  2010. //
  2011. UINT i;
  2012. for (i = 0;
  2013. i < NELEMENTS(LsapHardcodedNameLookupList);
  2014. i++)
  2015. {
  2016. if (RtlEqualUnicodeString((PUNICODE_STRING) Name,
  2017. &LsapHardcodedNameLookupList[i].KnownName,
  2018. TRUE))
  2019. {
  2020. *WellKnownSidIndex = LsapHardcodedNameLookupList[i].LookupIndex;
  2021. return TRUE;
  2022. }
  2023. }
  2024. if (dwMatchType == LOOKUP_MATCH_HARDCODED)
  2025. {
  2026. //
  2027. // No hardcoded match. Don't check the localized names since the
  2028. // prefix name itself didn't match the localized prefix.
  2029. //
  2030. *WellKnownSidIndex = LsapDummyLastSidIndex;
  2031. return FALSE;
  2032. }
  2033. }
  2034. //
  2035. // Scan the table of well-known Sids looking for a match on Name.
  2036. //
  2037. for(Index = LsapNullSidIndex; Index<LsapDummyLastSidIndex; Index++) {
  2038. //
  2039. // Allow NULL entries in the table of well-known Sids for now.
  2040. //
  2041. if (WellKnownSids[Index].Sid == NULL) {
  2042. continue;
  2043. }
  2044. //
  2045. // If the current entry in the table of Well Known Sids
  2046. // is for a Domain Sid, match the name with the DomainName
  2047. // field. Otherwise, match it with the Name field.
  2048. //
  2049. if (WellKnownSids[Index].Use == SidTypeDomain) {
  2050. MatchName = (PLSAPR_UNICODE_STRING) &WellKnownSids[Index].DomainName;
  2051. if (RtlEqualUnicodeString(
  2052. (PUNICODE_STRING) Name,
  2053. (PUNICODE_STRING) MatchName,
  2054. TRUE
  2055. )) {
  2056. //
  2057. // If a match is found, return the index to the caller.
  2058. //
  2059. BooleanStatus = TRUE;
  2060. break;
  2061. }
  2062. } else {
  2063. MatchName = (PLSAPR_UNICODE_STRING) &WellKnownSids[Index].Name;
  2064. if (RtlEqualUnicodeString(
  2065. (PUNICODE_STRING) Name,
  2066. (PUNICODE_STRING) MatchName,
  2067. TRUE
  2068. )) {
  2069. //
  2070. // If a match is found, return the index to the caller.
  2071. //
  2072. BooleanStatus = TRUE;
  2073. break;
  2074. }
  2075. }
  2076. }
  2077. *WellKnownSidIndex = Index;
  2078. return(BooleanStatus);
  2079. }
  2080. BOOLEAN
  2081. LsaILookupWellKnownName(
  2082. IN PUNICODE_STRING WellKnownName
  2083. )
  2084. /*++
  2085. RoutineDescription:
  2086. This routine returns TRUE if the supplied name is a well known name.
  2087. Arguments:
  2088. WellKnownName - The name to check against the list of well known names
  2089. Return Values:
  2090. TRUE - The supplied name is a well known name
  2091. FALSE - The supplied name is not a well known name
  2092. --*/
  2093. {
  2094. LSAP_WELL_KNOWN_SID_INDEX Index;
  2095. return(LsapDbLookupIndexWellKnownName(
  2096. (PLSAPR_UNICODE_STRING) WellKnownName,
  2097. &Index,
  2098. LOOKUP_MATCH_NONE
  2099. ));
  2100. }
  2101. PUNICODE_STRING
  2102. LsapDbWellKnownSidName(
  2103. IN LSAP_WELL_KNOWN_SID_INDEX WellKnownSidIndex
  2104. )
  2105. /*++
  2106. Routine Description:
  2107. This function returns the Unicode Name of a Well Known Sid.
  2108. Arguments:
  2109. WellKnownSidIndex - Index into the Well Known Sid information table.
  2110. It is the caller's responsibility to ensure that the given index
  2111. is valid.
  2112. Return Value:
  2113. PUNICODE_STRING Pointer to the name of the Well Known Sid.
  2114. --*/
  2115. {
  2116. //
  2117. // If the Sid is a Domain Sid, its name is contained within the
  2118. // DomainName field in the Well Known Sids table. If the Sid is not a
  2119. // Domain Sid, its name is contained within the Name field of the entry.
  2120. //
  2121. if (WellKnownSids[WellKnownSidIndex].Use == SidTypeDomain) {
  2122. return(&WellKnownSids[WellKnownSidIndex].DomainName);
  2123. } else {
  2124. return(&WellKnownSids[WellKnownSidIndex].Name);
  2125. }
  2126. }
  2127. NTSTATUS
  2128. LsapDbLookupIsolatedDomainNames(
  2129. IN ULONG Count,
  2130. IN PLSAPR_UNICODE_STRING Names,
  2131. IN PLSAPR_UNICODE_STRING PrefixNames,
  2132. IN PLSAPR_UNICODE_STRING SuffixNames,
  2133. IN PLSAPR_TRUST_INFORMATION BuiltInDomainTrustInformation,
  2134. IN PLSAPR_TRUST_INFORMATION_EX AccountDomainTrustInformation,
  2135. IN PLSAPR_TRUST_INFORMATION_EX PrimaryDomainTrustInformation,
  2136. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2137. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  2138. IN OUT PULONG MappedCount,
  2139. IN OUT PULONG CompletelyUnmappedCount
  2140. )
  2141. /*++
  2142. Routine Description:
  2143. This function attempts to identify isolated names as the names of Domains.
  2144. Names may be either isolated (e.g. JohnH) or composite names containing
  2145. both the domain name and account name. Composite names must include a
  2146. backslash character separating the domain name from the account name
  2147. (e.g. Acctg\JohnH). An isolated name may be either an account name
  2148. (user, group, or alias) or a domain name.
  2149. Translation of isolated names introduces the possibility of name
  2150. collisions (since the same name may be used in multiple domains). An
  2151. isolated name will be translated using the following algorithm:
  2152. If the name is a well-known name (e.g. Local or Interactive), then the
  2153. corresponding well-known Sid is returned.
  2154. If the name is the Built-in Domain's name, then that domain's Sid
  2155. will be returned.
  2156. If the name is the Account Domain's name, then that domain's Sid
  2157. will be returned.
  2158. If the name is the Primary Domain's name, then that domain's Sid will
  2159. be returned.
  2160. If the name is the name of one of the Primary Domain's Trusted Domains,
  2161. then that domain's Sid will be returned.
  2162. If the name is a user, group, or alias in the Built-in Domain, then the
  2163. Sid of that account is returned.
  2164. If the name is a user, group, or alias in the Primary Domain, then the
  2165. Sid of that account is returned.
  2166. Otherwise, the name is not translated.
  2167. NOTE: Proxy, Machine, and Trust user accounts are not referenced
  2168. for name translation. Only normal user accounts are used for ID
  2169. translation. If translation of other account types is needed, then
  2170. SAM services should be used directly.
  2171. Arguments:
  2172. Count - Specifies the number of names to be translated.
  2173. Names - Pointer to an array of Count Unicode String structures
  2174. specifying the names to be looked up and mapped to Sids.
  2175. The strings may be names of User, Group or Alias accounts or
  2176. domains.
  2177. PrefixNames - Pointer to an array of Count Unicode String structures
  2178. containing the Prefix portions of the Names. Names having no
  2179. Prefix are called Isolated Names. For these, the Unicode String
  2180. structure is set to contain a zero Length.
  2181. SuffixNames - Pointer to an array of Count Unicode String structures
  2182. containing the Suffix portions of the Names.
  2183. ReferencedDomains - Pointer to a structure in which the list of domains
  2184. used in the translation is maintained. The entries in this structure
  2185. are referenced by the structure returned via the Sids parameter.
  2186. Unlike the Sids parameter, which contains an array entry for each
  2187. translated name, this structure will only contain one component for
  2188. each domain utilized in the translation.
  2189. TranslatedSids - Pointer to a structure in which the translations to Sids
  2190. corresponding to the Names specified on Names is maintained. The
  2191. nth entry in this array provides a translation (where known) for the
  2192. nth element in the Names parameter.
  2193. MappedCount - Pointer to location in which a count of the Names that
  2194. have been completely translated is maintained.
  2195. CompletelyUnmappedCount - Pointer to a location in which a count of the
  2196. Names that have not been translated (either partially, by identification
  2197. of a Domain Prefix, or completely) is maintained.
  2198. Return Values:
  2199. NTSTATUS - Standard Nt Result Code
  2200. STATUS_ACCESS_DENIED - Caller does not have the appropriate access
  2201. to complete the operation.
  2202. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  2203. to complete the call.
  2204. --*/
  2205. {
  2206. NTSTATUS Status = STATUS_SUCCESS, IgnoreStatus;
  2207. LSAPR_TRUST_INFORMATION LocalTrustInfo;
  2208. ULONG NameIndex;
  2209. //
  2210. // Search for Isolated Names that match the Built-In Domain Name,
  2211. // Account Domain Name or one of the Primary Domain's Trusted Domain
  2212. // Names.
  2213. //
  2214. for (NameIndex = 0;
  2215. (NameIndex < Count);
  2216. NameIndex++) {
  2217. //
  2218. // Skip this name if already mapped or partially mapped.
  2219. //
  2220. if (!LsapDbCompletelyUnmappedSid(&TranslatedSids->Sids[NameIndex])) {
  2221. continue;
  2222. }
  2223. //
  2224. // Skip this name if composite.
  2225. //
  2226. if (PrefixNames[ NameIndex ].Length != (USHORT) 0) {
  2227. continue;
  2228. }
  2229. //
  2230. // We've found an Isolated Name. First check if it is the
  2231. // name of the Built In Domain.
  2232. //
  2233. Status = LsapDbLookupIsolatedDomainName(
  2234. NameIndex,
  2235. &SuffixNames[NameIndex],
  2236. BuiltInDomainTrustInformation,
  2237. ReferencedDomains,
  2238. TranslatedSids,
  2239. MappedCount,
  2240. CompletelyUnmappedCount
  2241. );
  2242. if (NT_SUCCESS(Status)) {
  2243. continue;
  2244. }
  2245. if (Status != STATUS_NONE_MAPPED) {
  2246. break;
  2247. }
  2248. Status = STATUS_SUCCESS;
  2249. //
  2250. // Isolated Name is not the name of the Built-in Domain. See if
  2251. // it is the name of the Accounts Domain.
  2252. //
  2253. Status = LsapDbLookupIsolatedDomainNameEx(
  2254. NameIndex,
  2255. &SuffixNames[NameIndex],
  2256. AccountDomainTrustInformation,
  2257. ReferencedDomains,
  2258. TranslatedSids,
  2259. MappedCount,
  2260. CompletelyUnmappedCount
  2261. );
  2262. if (NT_SUCCESS(Status)) {
  2263. continue;
  2264. }
  2265. Status = STATUS_SUCCESS;
  2266. //
  2267. // If we are configured as a member of a Work Group, there is
  2268. // no Primary or Trusted Domain List to search, so skip to next
  2269. // name. We are configured as a member of a Work Group if and
  2270. // only if out PolicyPrimaryDomainInformation contains a NULL Sid.
  2271. //
  2272. if (PrimaryDomainTrustInformation->Sid == NULL) {
  2273. continue;
  2274. }
  2275. //
  2276. // Isolated Name is not the name of either the Built-in or Accounts
  2277. // Domain. Try the Primary Domain if this is different from the
  2278. // Accounts Domain.
  2279. //
  2280. ASSERT(PrimaryDomainTrustInformation->FlatName.Length > 0);
  2281. if (!RtlEqualDomainName(
  2282. (PUNICODE_STRING) &PrimaryDomainTrustInformation->FlatName,
  2283. (PUNICODE_STRING) &AccountDomainTrustInformation->FlatName
  2284. )) {
  2285. Status = LsapDbLookupIsolatedDomainNameEx(
  2286. NameIndex,
  2287. &SuffixNames[NameIndex],
  2288. PrimaryDomainTrustInformation,
  2289. ReferencedDomains,
  2290. TranslatedSids,
  2291. MappedCount,
  2292. CompletelyUnmappedCount
  2293. );
  2294. if (NT_SUCCESS(Status)) {
  2295. continue;
  2296. }
  2297. if (Status != STATUS_NONE_MAPPED) {
  2298. break;
  2299. }
  2300. Status = STATUS_SUCCESS;
  2301. }
  2302. }
  2303. if (!NT_SUCCESS(Status)) {
  2304. goto LookupIsolatedDomainNamesError;
  2305. }
  2306. LookupIsolatedDomainNamesFinish:
  2307. return(Status);
  2308. LookupIsolatedDomainNamesError:
  2309. goto LookupIsolatedDomainNamesFinish;
  2310. }
  2311. NTSTATUS
  2312. LsapDbLookupNamesInLocalDomains(
  2313. IN ULONG Count,
  2314. IN PLSAPR_UNICODE_STRING Names,
  2315. IN PLSAPR_UNICODE_STRING PrefixNames,
  2316. IN PLSAPR_UNICODE_STRING SuffixNames,
  2317. IN PLSAPR_TRUST_INFORMATION BuiltInDomainTrustInformation,
  2318. IN PLSAPR_TRUST_INFORMATION_EX AccountDomainTrustInformation,
  2319. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2320. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  2321. IN OUT PULONG MappedCount,
  2322. IN OUT PULONG CompletelyUnmappedCount,
  2323. IN ULONG Options
  2324. )
  2325. /*++
  2326. Routine Description:
  2327. This function looks up Names in the local SAM domains and attempts to
  2328. translate them to Sids. Currently, there are two local SAM domains,
  2329. the Built-in domain (which has a well-known Sid and name) and the
  2330. Account Domain (which has a configurable Sid and name).
  2331. Arguments:
  2332. Count - Number of Names in the Names array, Note that some of these
  2333. may already have been mapped elsewhere, as specified by the
  2334. MappedCount parameter.
  2335. Names - Pointer to array of Unicode Names to be translated.
  2336. Zero or all of the Names may already have been translated
  2337. elsewhere. If any of the Names have been translated, the
  2338. TranslatedSids parameter will point to a location containing a non-NULL
  2339. array of Sid translation structures corresponding to the
  2340. Names. If the nth Name has been translated, the nth Sid
  2341. translation structure will contain either a non-NULL RelativeId
  2342. or a non-negative offset into the Referenced Domain List. If
  2343. the nth Name has not yet been translated, the nth Sid
  2344. translation structure will contain SidTypeUnknown in its
  2345. Use field.
  2346. PrefixNames - Pointer to an array of Count Unicode String structures
  2347. containing the Prefix portions of the Names. Names having no
  2348. Prefix are called Isolated Names. For these, the Unicode String
  2349. structure is set to contain a zero Length.
  2350. SuffixNames - Pointer to an array of Count Unicode String structures
  2351. containing the Suffix portions of the Names.
  2352. ReferencedDomains - Pointer to a location containing either NULL
  2353. or a pointer to a Referenced Domain List structure. If an
  2354. existing Referenced Domain List structure is supplied, it
  2355. will be appended/reallocated if necessary.
  2356. TranslatedSids - Pointer to structure that optionally references a list
  2357. of Sid translations for some of the Names in the Names array.
  2358. MappedCount - Pointer to location containing the number of Names
  2359. in the Names array that have already been mapped. This number
  2360. will be updated to reflect additional mapping done by this
  2361. routine.
  2362. CompletelyUnmappedCount - Pointer to location containing the
  2363. count of completely unmapped Sids. A Name is completely unmapped
  2364. if it is unknown and non-composite, or composite but with an
  2365. unrecognized Domain component. This count is updated on exit, the
  2366. number of completely unmapped Namess whose Domain Prefices are
  2367. identified by this routine being subtracted from the input value.
  2368. Options - Specifies optional actions.
  2369. LSAP_DB_SEARCH_BUILT_IN_DOMAIN - Search the Built In Domain
  2370. LSAP_DB_SEARCH_ACCOUNT_DOMAIN - Search the Account Domain
  2371. Return Values:
  2372. NTSTATUS - Standard Nt Result Code
  2373. STATUS_SUCCESS - The call completed successfully. Note that some
  2374. or all of the Names may remain partially or completely unmapped.
  2375. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  2376. such as memory, to complete the call.
  2377. STATUS_INTERNAL_DB_ERROR - A corruption has been detected in
  2378. the LSA Database.
  2379. STATUS_INVALID_PARAMETER - Invalid parameter
  2380. - No handle to the Policy object was provided on a request
  2381. to search the Account Domain.
  2382. --*/
  2383. {
  2384. NTSTATUS
  2385. Status = STATUS_SUCCESS,
  2386. SecondaryStatus = STATUS_SUCCESS;
  2387. ULONG
  2388. UpdatedMappedCount = *MappedCount;
  2389. LSAPR_HANDLE
  2390. TrustedPolicyHandle = NULL;
  2391. PLSAPR_POLICY_ACCOUNT_DOM_INFO
  2392. PolicyAccountDomainInfo = NULL;
  2393. LSAPR_TRUST_INFORMATION LookupInfo;
  2394. //
  2395. // If there are no completely unmapped Names remaining, return.
  2396. //
  2397. if (*CompletelyUnmappedCount == (ULONG) 0) {
  2398. goto LookupNamesInLocalDomainsFinish;
  2399. }
  2400. //
  2401. // If requested, lookup Names in the BUILT-IN Domain.
  2402. //
  2403. if (Options & LSAP_DB_SEARCH_BUILT_IN_DOMAIN) {
  2404. Status = LsapDbLookupNamesInLocalDomain(
  2405. LSAP_DB_SEARCH_BUILT_IN_DOMAIN,
  2406. Count,
  2407. PrefixNames,
  2408. SuffixNames,
  2409. BuiltInDomainTrustInformation,
  2410. ReferencedDomains,
  2411. TranslatedSids,
  2412. &UpdatedMappedCount,
  2413. CompletelyUnmappedCount
  2414. );
  2415. if (!NT_SUCCESS(Status)) {
  2416. goto LookupNamesInLocalDomainsError;
  2417. }
  2418. //
  2419. // If all Names are now mapped or partially mapped, finish.
  2420. //
  2421. if (*CompletelyUnmappedCount == (ULONG) 0) {
  2422. goto LookupNamesInLocalDomainsFinish;
  2423. }
  2424. }
  2425. //
  2426. // If requested, search the Account Domain.
  2427. //
  2428. if (Options & LSAP_DB_SEARCH_ACCOUNT_DOMAIN) {
  2429. Status = LsapDbLookupNamesInLocalDomainEx(
  2430. LSAP_DB_SEARCH_ACCOUNT_DOMAIN,
  2431. Count,
  2432. PrefixNames,
  2433. SuffixNames,
  2434. AccountDomainTrustInformation,
  2435. ReferencedDomains,
  2436. TranslatedSids,
  2437. &UpdatedMappedCount,
  2438. CompletelyUnmappedCount
  2439. );
  2440. if (!NT_SUCCESS(Status)) {
  2441. goto LookupNamesInLocalDomainsError;
  2442. }
  2443. }
  2444. LookupNamesInLocalDomainsFinish:
  2445. //
  2446. // Return the updated total count of Names mapped.
  2447. //
  2448. *MappedCount = UpdatedMappedCount;
  2449. return(Status);
  2450. LookupNamesInLocalDomainsError:
  2451. if (NT_SUCCESS(Status)) {
  2452. Status = SecondaryStatus;
  2453. }
  2454. goto LookupNamesInLocalDomainsFinish;
  2455. }
  2456. NTSTATUS
  2457. LsapDbLookupNamesInLocalDomain(
  2458. IN ULONG LocalDomain,
  2459. IN ULONG Count,
  2460. IN PLSAPR_UNICODE_STRING PrefixNames,
  2461. IN PLSAPR_UNICODE_STRING SuffixNames,
  2462. IN PLSAPR_TRUST_INFORMATION TrustInformation,
  2463. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2464. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  2465. IN OUT PULONG MappedCount,
  2466. IN OUT PULONG CompletelyUnmappedCount
  2467. )
  2468. {
  2469. LSAPR_TRUST_INFORMATION_EX ex;
  2470. LsapConvertTrustToEx( &ex, TrustInformation );
  2471. return LsapDbLookupNamesInLocalDomainEx( LocalDomain,
  2472. Count,
  2473. PrefixNames,
  2474. SuffixNames,
  2475. &ex,
  2476. ReferencedDomains,
  2477. TranslatedSids,
  2478. MappedCount,
  2479. CompletelyUnmappedCount );
  2480. }
  2481. NTSTATUS
  2482. LsapDbLookupNamesInLocalDomainEx(
  2483. IN ULONG LocalDomain,
  2484. IN ULONG Count,
  2485. IN PLSAPR_UNICODE_STRING PrefixNames,
  2486. IN PLSAPR_UNICODE_STRING SuffixNames,
  2487. IN PLSAPR_TRUST_INFORMATION_EX TrustInformationEx,
  2488. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2489. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  2490. IN OUT PULONG MappedCount,
  2491. IN OUT PULONG CompletelyUnmappedCount
  2492. )
  2493. /*++
  2494. Routine Description:
  2495. This function looks up Names in a SAM domain on the local system and
  2496. attempts to translate them to Sids.
  2497. Arguments:
  2498. LocalDomain - Indicates which local domain to look in. Valid values
  2499. are:
  2500. LSAP_DB_SEARCH_BUILT_IN_DOMAIN
  2501. LSAP_DB_SEARCH_ACCOUNT_DOMAIN
  2502. Count - Number of Names in the PrefixNames and SuffixNames arrays,
  2503. Note that some of these may already have been mapped elsewhere, as
  2504. specified by the MappedCount parameter.
  2505. PrefixNames - Pointer to array of Prefix Names. These are Domain
  2506. Names or NULL Unicode Strings. Only those Names whose Prefix
  2507. Names are NULL or the same as the Domain Name specified in the
  2508. TrustInformation parameter are eligible for the search.
  2509. SuffixNames - Pointer to array of Terminal Names to be translated.
  2510. Terminal Names are the last component of the name.
  2511. Zero or all of the Names may already have been translated
  2512. elsewhere. If any of the Names have been translated, the
  2513. Sids parameter will point to a location containing a non-NULL
  2514. array of Sid translation structures corresponding to the
  2515. Sids. If the nth Sid has been translated, the nth Sid
  2516. translation structure will contain either a non-NULL Sid
  2517. or a non-negative offset into the Referenced Domain List. If
  2518. the nth Sid has not yet been translated, the nth name
  2519. translation structure will contain a zero-length name string
  2520. and a negative value for the Referenced Domain List index.
  2521. TrustInformation - Pointer to Trust Information specifying a Domain Sid
  2522. and Name.
  2523. ReferencedDomains - Pointer to a Referenced Domain List. This
  2524. list references an array of zero or more Trust Information
  2525. entries describing each of the domains referenced by the names.
  2526. This array will be appended to/reallocated if necessary.
  2527. TranslatedSids - Pointer to location containing NULL or a pointer to a
  2528. array of Sid translation structures.
  2529. MappedCount - Pointer to location containing the number of Names
  2530. in the Names array that have already been mapped. This number
  2531. will be updated to reflect additional mapping done by this
  2532. routine.
  2533. CompletelyUnmappedCount - Pointer to location containing the
  2534. count of completely unmapped Sids. A Name is completely unmapped
  2535. if it is unknown and non-composite, or composite but with an
  2536. unrecognized Domain component. This count is updated on exit, the
  2537. number of completely unmapped Namess whose Domain Prefices are
  2538. identified by this routine being subtracted from the input value.
  2539. Return Values:
  2540. NTSTATUS - Standard Nt Result Code
  2541. STATUS_SUCCESS - The call completed successfully. Note that some
  2542. or all of the Names may remain partially or completely unmapped.
  2543. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  2544. such as memory, to complete the call.
  2545. --*/
  2546. {
  2547. NTSTATUS
  2548. Status = STATUS_SUCCESS,
  2549. SecondaryStatus = STATUS_SUCCESS,
  2550. IgnoreStatus;
  2551. ULONG
  2552. UnmappedNameCount = 0,
  2553. OutputSidsLength,
  2554. NameLookupCount,
  2555. NameLookupIndex,
  2556. SidIndex;
  2557. LONG
  2558. DomainIndex = LSA_UNKNOWN_INDEX;
  2559. PULONG
  2560. SidIndices = NULL;
  2561. PLSA_TRANSLATED_SID_EX2
  2562. OutputSids = NULL;
  2563. SAMPR_HANDLE
  2564. LocalSamDomainHandle = NULL,
  2565. LocalSamUserHandle = NULL;
  2566. PLSAPR_UNICODE_STRING
  2567. SamLookupSuffixNames = NULL;
  2568. PLSAPR_SID
  2569. DomainSid = TrustInformationEx->Sid;
  2570. SAMPR_ULONG_ARRAY
  2571. SamReturnedIds,
  2572. SamReturnedUses;
  2573. PLSAPR_TRUST_INFORMATION
  2574. FreeTrustInformation = NULL;
  2575. PUSER_CONTROL_INFORMATION
  2576. UserControlInfo;
  2577. LSAPR_TRUST_INFORMATION Dummy;
  2578. PLSAPR_TRUST_INFORMATION TrustInformation = &Dummy;
  2579. LsapDsDebugOut(( DEB_FTRACE, "LsapDbLookupNamesInLocalDomain\n" ));
  2580. LsapConvertExTrustToOriginal( TrustInformation, TrustInformationEx );
  2581. SamReturnedIds.Count = 0;
  2582. SamReturnedIds.Element = NULL;
  2583. SamReturnedUses.Count = 0;
  2584. SamReturnedUses.Element = NULL;
  2585. //
  2586. // Make sure the SAM handles have been established.
  2587. //
  2588. Status = LsapOpenSam();
  2589. ASSERT( NT_SUCCESS( Status ) );
  2590. if ( !NT_SUCCESS( Status ) ) {
  2591. LsapDsDebugOut(( DEB_FTRACE, "LsapDbLookupNamesInLocalDomain: 0x%lx\n", Status ));
  2592. return( Status );
  2593. }
  2594. //
  2595. // It is an internal error if the TranslatedSids or ReferencedDomains
  2596. // parameters have not been specified. Further, The TranslatedSids->Sids
  2597. // pointer must be non-NULL.
  2598. //
  2599. ASSERT(ARGUMENT_PRESENT(TranslatedSids));
  2600. ASSERT(TranslatedSids->Sids != NULL);
  2601. ASSERT(ARGUMENT_PRESENT(ReferencedDomains));
  2602. //
  2603. // Validate the Count and MappedCount parameters.
  2604. //
  2605. if (*MappedCount + *CompletelyUnmappedCount > Count) {
  2606. Status = STATUS_INVALID_PARAMETER;
  2607. goto LookupNamesInLocalDomainError;
  2608. }
  2609. if (*CompletelyUnmappedCount == (ULONG) 0) {
  2610. goto LookupNamesInLocalDomainFinish;
  2611. }
  2612. //
  2613. // Not all of the Names have yet been mapped. We'll try to map the
  2614. // remaining names by searching the designated SAM domain on this
  2615. // machine.
  2616. //
  2617. UnmappedNameCount = Count - *MappedCount;
  2618. OutputSids = (PLSA_TRANSLATED_SID_EX2) TranslatedSids->Sids;
  2619. OutputSidsLength = Count * sizeof (LSA_TRANSLATED_SID_EX2);
  2620. //
  2621. // Allocate memory for array of names to be presented to SAM. Note
  2622. // that, for simplicity, we allocate an array for the maximal case
  2623. // in which all of the reamining unmapped names are eligible
  2624. // for the search in this domain. This avoids having to scan the
  2625. // names array twice, once to compute the number of eligible names.
  2626. //
  2627. SamLookupSuffixNames = LsapAllocateLsaHeap( UnmappedNameCount * sizeof(UNICODE_STRING));
  2628. if (SamLookupSuffixNames == NULL) {
  2629. Status = STATUS_INSUFFICIENT_RESOURCES;
  2630. goto LookupNamesInLocalDomainError;
  2631. }
  2632. //
  2633. // Allocate an array to record indices of eligible names. This is
  2634. // used upon return from SAM to locate the entries in the
  2635. // OutputSids array that are to be updated. For simplicity, we
  2636. // allocate the array with sufficient entries for all of the remaining
  2637. // unmapped names.
  2638. //
  2639. SidIndices = LsapAllocateLsaHeap( UnmappedNameCount * sizeof(ULONG));
  2640. if (SidIndices == NULL) {
  2641. goto LookupNamesInLocalDomainError;
  2642. }
  2643. //
  2644. // Scan the output array of Sid translations to locate entries for names
  2645. // that have not yet been mapped. For each unmapped name, check
  2646. // eligibility of the name for the search of this domain.
  2647. //
  2648. // - All isolated names are eligible for the search
  2649. // - All composite names having this domain name as prefix are
  2650. // eligible.
  2651. //
  2652. // Copy in each eligible suffix or isolated name to the SAM buffer.
  2653. //
  2654. for (NameLookupIndex = 0, SidIndex = 0; SidIndex < Count; SidIndex++) {
  2655. if (OutputSids[SidIndex].Use == SidTypeUnknown) {
  2656. //
  2657. // Found a name that has not yet been mapped. Check for a name
  2658. // Prefix. If none has been specified, the whole name may either
  2659. // be NULL, the name of the domain itself or an isolated name.
  2660. //
  2661. if (PrefixNames[SidIndex].Length == 0) {
  2662. //
  2663. // Name is isolated. If whole name is NULL, skip.
  2664. //
  2665. if (SuffixNames[SidIndex].Length == 0) {
  2666. continue;
  2667. }
  2668. //
  2669. // If name is the name of the domain itself, use the
  2670. // Trust Information to translate it, and fill in the
  2671. // appropriate Translated Sids entry. The name will
  2672. // then be excluded from further searches.
  2673. //
  2674. if (LsapCompareDomainNames(
  2675. (PUNICODE_STRING) &(SuffixNames[SidIndex]),
  2676. (PUNICODE_STRING) &(TrustInformationEx->DomainName),
  2677. (PUNICODE_STRING) &(TrustInformationEx->FlatName))
  2678. ) {
  2679. Status = LsapDbLookupTranslateNameDomain(
  2680. TrustInformation,
  2681. &OutputSids[SidIndex],
  2682. ReferencedDomains,
  2683. &DomainIndex
  2684. );
  2685. if (!NT_SUCCESS(Status)) {
  2686. break;
  2687. }
  2688. //
  2689. // Update mapped count for this isolated domain Sid
  2690. //
  2691. (*MappedCount)++;
  2692. continue;
  2693. }
  2694. //
  2695. // Name is an isolated name not equal to the domain name and
  2696. // so is eligible for the search. Reference it from the SAM buffer,
  2697. // remember its index and increment the buffer index. The
  2698. // SAM buffer is an IN parameter to a further lookup call.
  2699. //
  2700. SamLookupSuffixNames[NameLookupIndex] = SuffixNames[SidIndex];
  2701. //
  2702. // We should never have an index that equals or exceeds the
  2703. // UnmappedNameCount.
  2704. //
  2705. ASSERT(NameLookupIndex < UnmappedNameCount);
  2706. SidIndices[NameLookupIndex] = SidIndex;
  2707. NameLookupIndex++;
  2708. continue;
  2709. }
  2710. //
  2711. // Name has a non-NULL Prefix Name. Compare the name with the
  2712. // name of the Domain being searched.
  2713. //
  2714. if (LsapCompareDomainNames(
  2715. (PUNICODE_STRING) &(PrefixNames[SidIndex]),
  2716. (PUNICODE_STRING) &(TrustInformationEx->DomainName),
  2717. (PUNICODE_STRING) &(TrustInformationEx->FlatName))
  2718. ) {
  2719. //
  2720. // Prefix name matches the name of the Domain. If the
  2721. // Suffix Name is NULL, the name of the domain itself
  2722. // has been specified (in the form <DomainName> "\").
  2723. //
  2724. if (SuffixNames[SidIndex].Length == 0) {
  2725. Status = LsapDbLookupTranslateNameDomain(
  2726. TrustInformation,
  2727. &OutputSids[SidIndex],
  2728. ReferencedDomains,
  2729. &DomainIndex
  2730. );
  2731. if (!NT_SUCCESS(Status)) {
  2732. break;
  2733. }
  2734. //
  2735. // Update mapped count for this isolated domain Sid
  2736. //
  2737. (*MappedCount)++;
  2738. continue;
  2739. }
  2740. //
  2741. // Name is composite and the Prefix name matches the name of
  2742. // this domain. We will at least be able to partially translate
  2743. // name, so add this domain to the Referenced Domain List if not
  2744. // already there. Then reference the Suffix Name from the SAM buffer,
  2745. // remember its index and increment the buffer index. The
  2746. // SAM buffer is an IN parameter to a further lookup call.
  2747. //
  2748. if (DomainIndex == LSA_UNKNOWN_INDEX) {
  2749. Status = LsapDbLookupAddListReferencedDomains(
  2750. ReferencedDomains,
  2751. TrustInformation,
  2752. &DomainIndex
  2753. );
  2754. if (!NT_SUCCESS(Status)) {
  2755. break;
  2756. }
  2757. }
  2758. SamLookupSuffixNames[NameLookupIndex] = SuffixNames[SidIndex];
  2759. SidIndices[NameLookupIndex] = SidIndex;
  2760. OutputSids[SidIndex].DomainIndex = DomainIndex;
  2761. NameLookupIndex++;
  2762. }
  2763. }
  2764. }
  2765. if (!NT_SUCCESS(Status)) {
  2766. goto LookupNamesInLocalDomainError;
  2767. }
  2768. //
  2769. // If none of the remaining Names are eligible for searching in this
  2770. // domain, finish up.
  2771. //
  2772. NameLookupCount = NameLookupIndex;
  2773. if (NameLookupCount == 0) {
  2774. goto LookupNamesInLocalDomainFinish;
  2775. }
  2776. //
  2777. //
  2778. // Lookup the Sids in the specified SAM Domain.
  2779. //
  2780. if (LocalDomain == LSAP_DB_SEARCH_BUILT_IN_DOMAIN ) {
  2781. LocalSamDomainHandle = LsapBuiltinDomainHandle;
  2782. } else {
  2783. ASSERT(LocalDomain == LSAP_DB_SEARCH_ACCOUNT_DOMAIN);
  2784. LocalSamDomainHandle = LsapAccountDomainHandle;
  2785. }
  2786. //
  2787. // Call SAM to lookup the Names in the Domain.
  2788. //
  2789. Status = SamrLookupNamesInDomain(
  2790. LocalSamDomainHandle,
  2791. NameLookupCount,
  2792. (PRPC_UNICODE_STRING) SamLookupSuffixNames,
  2793. &SamReturnedIds,
  2794. &SamReturnedUses
  2795. );
  2796. if (!NT_SUCCESS(Status)) {
  2797. if ( Status == STATUS_INVALID_SERVER_STATE ) {
  2798. Status = SamrLookupNamesInDomain(
  2799. LocalSamDomainHandle,
  2800. NameLookupCount,
  2801. (PRPC_UNICODE_STRING) SamLookupSuffixNames,
  2802. &SamReturnedIds,
  2803. &SamReturnedUses
  2804. );
  2805. }
  2806. //
  2807. // The only error allowed is STATUS_NONE_MAPPED. Filter this out.
  2808. //
  2809. if (Status != STATUS_NONE_MAPPED) {
  2810. goto LookupNamesInLocalDomainError;
  2811. }
  2812. Status = STATUS_SUCCESS;
  2813. goto LookupNamesInLocalDomainFinish;
  2814. }
  2815. #ifdef notdef
  2816. //
  2817. // Filter through the returned Ids to eliminate user accounts that are
  2818. // not marked NORMAL.
  2819. //
  2820. for (NameLookupIndex = 0;
  2821. NameLookupIndex < SamReturnedIds.Count;
  2822. NameLookupIndex++) {
  2823. //
  2824. // If this account is a User Account, check its User Control
  2825. // Information. If the account control information indicates
  2826. // that the account is not a Normal User Account, for example
  2827. // it is a machine account, do not return information about
  2828. // the account. Mark it as unknown.
  2829. //
  2830. if (SamReturnedUses.Element[ NameLookupIndex ] != SidTypeUser) {
  2831. continue;
  2832. }
  2833. Status = SamrOpenUser(
  2834. LocalSamDomainHandle,
  2835. USER_READ_ACCOUNT,
  2836. SamReturnedIds.Element[ NameLookupIndex ],
  2837. &LocalSamUserHandle
  2838. );
  2839. if (!NT_SUCCESS(Status)) {
  2840. break;
  2841. }
  2842. UserControlInfo = NULL;
  2843. Status = SamrQueryInformationUser(
  2844. LocalSamUserHandle,
  2845. UserControlInformation,
  2846. (PSAMPR_USER_INFO_BUFFER *) &UserControlInfo
  2847. );
  2848. IgnoreStatus = SamrCloseHandle(&LocalSamUserHandle);
  2849. ASSERT(NT_SUCCESS(IgnoreStatus));
  2850. LocalSamUserHandle = NULL;
  2851. if (!NT_SUCCESS(Status)) {
  2852. MIDL_user_free( UserControlInfo );
  2853. break;
  2854. }
  2855. if (!(UserControlInfo->UserAccountControl & USER_NORMAL_ACCOUNT) &&
  2856. !(UserControlInfo->UserAccountControl & USER_TEMP_DUPLICATE_ACCOUNT)) {
  2857. SamReturnedUses.Element[NameLookupIndex] = SidTypeUnknown;
  2858. }
  2859. MIDL_user_free( UserControlInfo );
  2860. }
  2861. if (!NT_SUCCESS(Status)) {
  2862. goto LookupNamesInLocalDomainError;
  2863. }
  2864. #endif
  2865. //
  2866. // SAM found at least one eligible name in the specified domain.
  2867. // Add the domain to the Referenced Domain List.
  2868. //
  2869. Status = LsapDbLookupTranslateNameDomain(
  2870. TrustInformation,
  2871. NULL,
  2872. ReferencedDomains,
  2873. &DomainIndex
  2874. );
  2875. if (!NT_SUCCESS(Status)) {
  2876. goto LookupNamesInLocalDomainError;
  2877. }
  2878. //
  2879. // Now copy the information returned from SAM into the output
  2880. // Translated Sids array.
  2881. //
  2882. for (NameLookupIndex = 0;
  2883. NameLookupIndex < SamReturnedIds.Count;
  2884. NameLookupIndex++) {
  2885. SidIndex = SidIndices[NameLookupIndex];
  2886. //
  2887. // If we have newly translated a Name, increment the mapped
  2888. // count and copy information returned by SAM.
  2889. //
  2890. if ((OutputSids[SidIndex].Use == SidTypeUnknown) &&
  2891. SamReturnedUses.Element[NameLookupIndex] != (ULONG) SidTypeUnknown) {
  2892. PSID TempSid;
  2893. (*MappedCount)++;
  2894. OutputSids[SidIndex].Use = (SID_NAME_USE) SamReturnedUses.Element[NameLookupIndex];
  2895. Status = SamrRidToSid(LocalSamDomainHandle,
  2896. SamReturnedIds.Element[NameLookupIndex],
  2897. (PRPC_SID*) &TempSid);
  2898. if (NT_SUCCESS(Status)) {
  2899. Status = LsapRpcCopySid( NULL,
  2900. &OutputSids[SidIndex].Sid,
  2901. TempSid);
  2902. SamIFreeVoid(TempSid);
  2903. }
  2904. if ( !NT_SUCCESS(Status) ) {
  2905. goto LookupNamesInLocalDomainError;
  2906. }
  2907. OutputSids[SidIndex].DomainIndex = DomainIndex;
  2908. }
  2909. }
  2910. LookupNamesInLocalDomainFinish:
  2911. //
  2912. // If successful, update count of completely unmapped names provided.
  2913. // Note that STATUS_NONE_MAPPED errors are suppressed before we get here.
  2914. //
  2915. if (NT_SUCCESS(Status)) {
  2916. LsapDbUpdateCountCompUnmappedNames(TranslatedSids, CompletelyUnmappedCount);
  2917. }
  2918. //
  2919. // If necessary, free the Lsa Heap buffer allocated for the
  2920. // SamLookupSuffixNames and SidIndices arrays.
  2921. //
  2922. if (SamLookupSuffixNames != NULL) {
  2923. LsapFreeLsaHeap( SamLookupSuffixNames );
  2924. }
  2925. if (SidIndices != NULL) {
  2926. LsapFreeLsaHeap( SidIndices );
  2927. }
  2928. //
  2929. // If necessary, free the Relative Ids array returned from SAM.
  2930. //
  2931. if ( SamReturnedIds.Count != 0 ) {
  2932. SamIFree_SAMPR_ULONG_ARRAY ( &SamReturnedIds );
  2933. }
  2934. //
  2935. // If necessary, free the Uses array returned from SAM.
  2936. //
  2937. if ( SamReturnedUses.Count != 0 ) {
  2938. SamIFree_SAMPR_ULONG_ARRAY ( &SamReturnedUses );
  2939. }
  2940. LsapDsDebugOut(( DEB_FTRACE, "LsapDbLookupNamesInLocalDomain: 0x%lx\n", Status ));
  2941. return(Status);
  2942. LookupNamesInLocalDomainError:
  2943. //
  2944. // If necessary, free memory for the OutputTrustInformation Domain
  2945. // Name Buffer and Sid Buffer.
  2946. //
  2947. if (DomainIndex >= 0) {
  2948. FreeTrustInformation = &ReferencedDomains->Domains[DomainIndex];
  2949. if (FreeTrustInformation->Sid != NULL) {
  2950. MIDL_user_free( FreeTrustInformation->Sid );
  2951. FreeTrustInformation->Sid = NULL;
  2952. }
  2953. if (FreeTrustInformation->Name.Buffer != NULL) {
  2954. MIDL_user_free( FreeTrustInformation->Name.Buffer );
  2955. FreeTrustInformation->Name.Buffer = NULL;
  2956. FreeTrustInformation->Name.Length = 0;
  2957. FreeTrustInformation->Name.MaximumLength = 0;
  2958. }
  2959. }
  2960. //
  2961. // Reset the Use field for each of the entries written to back to
  2962. // SidTypeUnknown and set the DomainIndex back to LSA_UNKNOWN_INDEX.
  2963. //
  2964. for (NameLookupIndex = 0;
  2965. NameLookupIndex < SamReturnedIds.Count;
  2966. NameLookupIndex++) {
  2967. SidIndex = SidIndices[NameLookupIndex];
  2968. OutputSids[SidIndex].Use = SidTypeUnknown;
  2969. OutputSids[SidIndex].DomainIndex = LSA_UNKNOWN_INDEX;
  2970. }
  2971. //
  2972. // If the last User Account handle is still open, close it..
  2973. //
  2974. if (LocalSamUserHandle != NULL) {
  2975. SecondaryStatus = SamrCloseHandle(&LocalSamUserHandle);
  2976. LocalSamUserHandle = NULL;
  2977. }
  2978. goto LookupNamesInLocalDomainFinish;
  2979. }
  2980. NTSTATUS
  2981. LsapDbLookupNamesInPrimaryDomain(
  2982. IN ULONG LookupOptions,
  2983. IN ULONG Count,
  2984. IN PLSAPR_UNICODE_STRING Names,
  2985. IN PLSAPR_UNICODE_STRING PrefixNames,
  2986. IN PLSAPR_UNICODE_STRING SuffixNames,
  2987. IN PLSAPR_TRUST_INFORMATION_EX TrustInformationEx,
  2988. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  2989. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  2990. IN LSAP_LOOKUP_LEVEL LookupLevel,
  2991. IN OUT PULONG MappedCount,
  2992. IN OUT PULONG CompletelyUnmappedCount,
  2993. OUT BOOLEAN *fDownlevelSecureChannel,
  2994. IN NTSTATUS *NonFatalStatus
  2995. )
  2996. /*++
  2997. Routine Description:
  2998. This function attempts to translate Names by searching the Primary
  2999. Domain.
  3000. Arguments:
  3001. LookupOptions -- LSA_LOOKUP_ISOLATED_AS_LOCAL
  3002. Count - Number of Names in the Names array, Note that some of these
  3003. may already have been mapped elsewhere, as specified by the
  3004. MappedCount parameter.
  3005. Names - Pointer to array of Names to be translated.
  3006. Zero or all of the Names may already have been translated
  3007. elsewhere. If any of the Names have been translated, the
  3008. TranslatedSids parameter will point to a location containing a non-NULL
  3009. array of Sid translation structures corresponding to the
  3010. Names. If the nth Name has been translated, the nth Sid
  3011. translation structure will contain either a non-NULL Sid
  3012. or a non-negative offset into the Referenced Domain List. If
  3013. the nth Name has not yet been translated, the nth Sid
  3014. translation structure will contain a zero-length Sid string
  3015. and a negative value for the Referenced Domain List index.
  3016. PrefixNames - Pointer to an array of Count Unicode String structures
  3017. containing the Prefix portions of the Names. Names having no
  3018. Prefix are called Isolated Names. For these, the Unicode String
  3019. structure is set to contain a zero Length.
  3020. SuffixNames - Pointer to an array of Count Unicode String structures
  3021. containing the Suffix portions of the Names.
  3022. TrustInformation - Specifies the name and Sid of the Primary Domain.
  3023. ReferencedDomains - Pointer to a Referenced Domain List. This
  3024. list references an array of zero or more Trust Information
  3025. entries describing each of the domains referenced by the names.
  3026. This array will be appended to/reallocated if necessary.
  3027. TranslatedSids - Pointer to structure that optionally references a list
  3028. of Sid translations for some of the Names in the Names array.
  3029. LookupLevel - Specifies the Level of Lookup to be performed on this
  3030. machine. Values of this field are are follows:
  3031. LsapLookupPDC - Second Level Lookup performed on a Primary Domain
  3032. Controller. The lookup searches the Account Domain of the
  3033. SAM Database on the controller. If not all Names are
  3034. found, the Trusted Domain List (TDL) is obtained from the
  3035. LSA's Policy Database and Third Level lookups are performed
  3036. via "handoff" to each Trusted Domain in the List.
  3037. NOTE: LsapLookupWksta is not valid for this parameter.
  3038. MappedCount - Pointer to location containing the number of Names
  3039. in the Names array that have already been mapped. This number
  3040. will be updated to reflect additional mapping done by this
  3041. routine.
  3042. CompletelyUnmappedCount - Pointer to location containing the
  3043. count of completely unmapped Names. A Name is completely unmapped
  3044. if it is unknown and non-composite, or composite but with an
  3045. unrecognized Domain component. This count is updated on exit, the
  3046. number of completely unmapped Namess whose Domain Prefices are
  3047. identified by this routine being subtracted from the input value.
  3048. NonFatalStatus - a status to indicate reasons why no names could have been
  3049. resolved
  3050. Return Values:
  3051. NTSTATUS - Standard Nt Result Code
  3052. STATUS_SUCCESS - The call completed successfully. Note that some
  3053. or all of the Names may remain partially or completely unmapped.
  3054. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  3055. such as memory, to complete the call.
  3056. --*/
  3057. {
  3058. NTSTATUS Status = STATUS_SUCCESS;
  3059. NTSTATUS SecondaryStatus = STATUS_SUCCESS;
  3060. ULONG NextLevelCount;
  3061. ULONG NextLevelMappedCount;
  3062. ULONG NameIndex;
  3063. ULONG NextLevelNameIndex;
  3064. PLSAPR_REFERENCED_DOMAIN_LIST NextLevelReferencedDomains = NULL;
  3065. PLSAPR_REFERENCED_DOMAIN_LIST OutputReferencedDomains = NULL;
  3066. PLSAPR_TRANSLATED_SID_EX2 NextLevelSids = NULL;
  3067. PLSAPR_UNICODE_STRING NextLevelNames = NULL;
  3068. PLSAPR_UNICODE_STRING NextLevelPrefixNames = NULL;
  3069. PLSAPR_UNICODE_STRING NextLevelSuffixNames = NULL;
  3070. LONG FirstEntryIndex;
  3071. PULONG NameIndices = NULL;
  3072. BOOLEAN PartialNameTranslationsAttempted = FALSE;
  3073. ULONG ServerRevision = 0;
  3074. LSAPR_TRUST_INFORMATION Dummy;
  3075. PLSAPR_TRUST_INFORMATION TrustInformation = &Dummy;
  3076. LsapConvertExTrustToOriginal( TrustInformation, TrustInformationEx );
  3077. *NonFatalStatus = STATUS_SUCCESS;
  3078. //
  3079. // If there are no completely unmapped Names remaining, just return.
  3080. //
  3081. if (*CompletelyUnmappedCount == (ULONG) 0) {
  3082. goto LookupNamesInPrimaryDomainFinish;
  3083. }
  3084. //
  3085. // We have successfully opened a Domain Controller's Policy
  3086. // Database. Now prepare to hand off a Name lookup for the
  3087. // remaining unmapped Names to that Controller. Here, this
  3088. // server side of the LSA is a client of the LSA on the
  3089. // target controller. We will construct an array of the
  3090. // remianing unmapped Names, look them up and then merge the
  3091. // resulting ReferencedDomains and Translated Sids into
  3092. // our existing list.
  3093. //
  3094. NextLevelCount = *CompletelyUnmappedCount;
  3095. //
  3096. // Allocate an array to hold the indices of unmapped Names
  3097. // relative to the original Names and TranslatedSids->Sids
  3098. // arrays.
  3099. //
  3100. NameIndices = MIDL_user_allocate(NextLevelCount * sizeof(ULONG));
  3101. Status = STATUS_INSUFFICIENT_RESOURCES;
  3102. if (NameIndices == NULL) {
  3103. goto LookupNamesInPrimaryDomainError;
  3104. }
  3105. //
  3106. // Allocate an array of UNICODE_STRING structures for the
  3107. // names to be looked up at the Domain Controller.
  3108. //
  3109. NextLevelNames = MIDL_user_allocate(
  3110. sizeof(UNICODE_STRING) * NextLevelCount
  3111. );
  3112. if (NextLevelNames == NULL) {
  3113. goto LookupNamesInPrimaryDomainError;
  3114. }
  3115. //
  3116. // Allocate an array of UNICODE_STRING structures for the
  3117. // prefix names to be cached.
  3118. //
  3119. NextLevelPrefixNames = MIDL_user_allocate(
  3120. sizeof(UNICODE_STRING) * NextLevelCount
  3121. );
  3122. if (NextLevelPrefixNames == NULL) {
  3123. goto LookupNamesInPrimaryDomainError;
  3124. }
  3125. //
  3126. // Allocate an array of UNICODE_STRING structures for the
  3127. // suffix names to be cached.
  3128. //
  3129. NextLevelSuffixNames = MIDL_user_allocate(
  3130. sizeof(UNICODE_STRING) * NextLevelCount
  3131. );
  3132. if (NextLevelSuffixNames == NULL) {
  3133. goto LookupNamesInPrimaryDomainError;
  3134. }
  3135. Status = STATUS_SUCCESS;
  3136. //
  3137. // Now scan the original array of Names and its parallel
  3138. // Translated Sids array. Copy over any names that are completely
  3139. // unmapped.
  3140. //
  3141. NextLevelNameIndex = (ULONG) 0;
  3142. for (NameIndex = 0;
  3143. NameIndex < Count && NextLevelNameIndex < NextLevelCount;
  3144. NameIndex++) {
  3145. if (LsapDbCompletelyUnmappedSid(&TranslatedSids->Sids[NameIndex])) {
  3146. if ( (LookupOptions & LSA_LOOKUP_ISOLATED_AS_LOCAL)
  3147. && (PrefixNames[NameIndex].Length == 0) ) {
  3148. //
  3149. // Don't lookup isolated names off machine
  3150. //
  3151. continue;
  3152. }
  3153. NextLevelNames[NextLevelNameIndex] = Names[NameIndex];
  3154. NextLevelPrefixNames[NextLevelNameIndex] = PrefixNames[NameIndex];
  3155. NextLevelSuffixNames[NextLevelNameIndex] = SuffixNames[NameIndex];
  3156. NameIndices[NextLevelNameIndex] = NameIndex;
  3157. NextLevelNameIndex++;
  3158. }
  3159. }
  3160. if (NextLevelNameIndex == 0) {
  3161. // Nothing to do
  3162. Status = STATUS_SUCCESS;
  3163. goto LookupNamesInPrimaryDomainFinish;
  3164. }
  3165. NextLevelMappedCount = (ULONG) 0;
  3166. Status = LsapDbLookupNameChainRequest(TrustInformationEx,
  3167. NextLevelCount,
  3168. (PUNICODE_STRING)NextLevelNames,
  3169. (PLSA_REFERENCED_DOMAIN_LIST *)&NextLevelReferencedDomains,
  3170. (PLSA_TRANSLATED_SID_EX2 * )&NextLevelSids,
  3171. LookupLevel,
  3172. &NextLevelMappedCount,
  3173. &ServerRevision
  3174. );
  3175. if ( 0 != ServerRevision ) {
  3176. if ( ServerRevision & LSA_CLIENT_PRE_NT5 ) {
  3177. *fDownlevelSecureChannel = TRUE;
  3178. }
  3179. }
  3180. //
  3181. // If the callout to LsaLookupNames() was unsuccessful, disregard
  3182. // the error and set the domain name for any Sids having this
  3183. // domain Sid as prefix sid.
  3184. //
  3185. if (!NT_SUCCESS(Status) && Status != STATUS_NONE_MAPPED) {
  3186. //
  3187. // Let the caller know there is a trust problem
  3188. //
  3189. if ( LsapDbIsStatusConnectionFailure(Status) ) {
  3190. *NonFatalStatus = Status;
  3191. }
  3192. Status = STATUS_SUCCESS;
  3193. goto LookupNamesInPrimaryDomainFinish;
  3194. }
  3195. //
  3196. // Cache any sids that came back
  3197. //
  3198. (void) LsapDbUpdateCacheWithNames(
  3199. (PUNICODE_STRING) NextLevelSuffixNames,
  3200. (PUNICODE_STRING) NextLevelPrefixNames,
  3201. NextLevelCount,
  3202. NextLevelReferencedDomains,
  3203. NextLevelSids
  3204. );
  3205. //
  3206. // The callout to LsaLookupNames() was successful. We now have
  3207. // an additional list of Referenced Domains containing the
  3208. // Primary Domain and/or one or more of its Trusted Domains.
  3209. // Merge the two Referenced Domain Lists together, noting that
  3210. // since they are disjoint, the second list is simply
  3211. // concatenated with the first. The index of the first entry
  3212. // of the second list will be used to adjust all of the
  3213. // Domain Index entries in the Translated Names entries.
  3214. // Note that since the memory for the graph of the first
  3215. // Referenced Domain list has been allocated as individual
  3216. // nodes, we specify that the nodes in this graph can be
  3217. // referenced by the output Referenced Domain list.
  3218. //
  3219. Status = LsapDbLookupMergeDisjointReferencedDomains(
  3220. ReferencedDomains,
  3221. NextLevelReferencedDomains,
  3222. &OutputReferencedDomains,
  3223. LSAP_DB_USE_FIRST_MERGAND_GRAPH
  3224. );
  3225. if (!NT_SUCCESS(Status)) {
  3226. goto LookupNamesInPrimaryDomainError;
  3227. }
  3228. FirstEntryIndex = ReferencedDomains->Entries;
  3229. //
  3230. // Now update the original list of Translated Names. We
  3231. // update each entry that has newly been translated by copying
  3232. // the entry from the new list and adjusting its
  3233. // Referenced Domain List Index upwards by adding the index
  3234. // of the first entry in the Next level List..
  3235. //
  3236. for( NextLevelNameIndex = 0;
  3237. NextLevelNameIndex < NextLevelCount;
  3238. NextLevelNameIndex++ ) {
  3239. if ( !LsapDbCompletelyUnmappedSid(&NextLevelSids[NextLevelNameIndex]) ) {
  3240. NameIndex = NameIndices[NextLevelNameIndex];
  3241. TranslatedSids->Sids[NameIndex]
  3242. = NextLevelSids[NextLevelNameIndex];
  3243. Status = LsapRpcCopySid(NULL,
  3244. &TranslatedSids->Sids[NameIndex].Sid,
  3245. NextLevelSids[NextLevelNameIndex].Sid);
  3246. if (!NT_SUCCESS(Status)) {
  3247. goto LookupNamesInPrimaryDomainError;
  3248. }
  3249. TranslatedSids->Sids[NameIndex].DomainIndex =
  3250. FirstEntryIndex +
  3251. NextLevelSids[NextLevelNameIndex].DomainIndex;
  3252. (*CompletelyUnmappedCount)--;
  3253. }
  3254. }
  3255. //
  3256. // Update the Referenced Domain List if a new one was produced
  3257. // from the merge. We retain the original top-level structure.
  3258. //
  3259. if (OutputReferencedDomains != NULL) {
  3260. if (ReferencedDomains->Domains != NULL) {
  3261. MIDL_user_free( ReferencedDomains->Domains );
  3262. ReferencedDomains->Domains = NULL;
  3263. }
  3264. *ReferencedDomains = *OutputReferencedDomains;
  3265. MIDL_user_free( OutputReferencedDomains );
  3266. OutputReferencedDomains = NULL;
  3267. }
  3268. //
  3269. // Update the Mapped Count and close the Controller Policy
  3270. // Handle.
  3271. //
  3272. *MappedCount += NextLevelMappedCount;
  3273. //
  3274. // Any error status that has not been suppressed must be reported
  3275. // to the caller. Errors such as connection failures to other LSA's
  3276. // are suppressed.
  3277. //
  3278. if (!NT_SUCCESS(Status)) {
  3279. goto LookupNamesInPrimaryDomainError;
  3280. }
  3281. LookupNamesInPrimaryDomainFinish:
  3282. //
  3283. // If necessary, update count of completely unmapped names.
  3284. //
  3285. if (*CompletelyUnmappedCount > (ULONG) 0) {
  3286. LsapDbUpdateCountCompUnmappedNames(TranslatedSids, CompletelyUnmappedCount);
  3287. }
  3288. //
  3289. // We can return partial translations for composite Names in which the
  3290. // domain component is known. We do this provided there has been
  3291. // no reported error. Errors resulting from callout to another
  3292. // LSA will have been suppressed.
  3293. //
  3294. if (NT_SUCCESS(Status) &&
  3295. (*MappedCount < Count) &&
  3296. !PartialNameTranslationsAttempted) {
  3297. SecondaryStatus = LsapDbLookupTranslateUnknownNamesInDomain(
  3298. Count,
  3299. Names,
  3300. PrefixNames,
  3301. SuffixNames,
  3302. TrustInformationEx,
  3303. ReferencedDomains,
  3304. TranslatedSids,
  3305. LookupLevel,
  3306. MappedCount,
  3307. CompletelyUnmappedCount
  3308. );
  3309. PartialNameTranslationsAttempted = TRUE;
  3310. if (!NT_SUCCESS(SecondaryStatus)) {
  3311. goto LookupNamesInPrimaryDomainError;
  3312. }
  3313. }
  3314. //
  3315. // If necessary, free the Next Level Referenced Domain List.
  3316. // Note that this structure is allocated(all_nodes) since it was
  3317. // allocated by the client side of the Domain Controller LSA.
  3318. //
  3319. if (NextLevelReferencedDomains != NULL) {
  3320. MIDL_user_free( NextLevelReferencedDomains );
  3321. NextLevelReferencedDomains = NULL;
  3322. }
  3323. //
  3324. // If necessary, free the Next Level Names array. We only free the
  3325. // top level, since the names therein were copied from the input
  3326. // TranslatedNames->Names array.
  3327. //
  3328. if (NextLevelNames != NULL) {
  3329. MIDL_user_free( NextLevelNames );
  3330. NextLevelNames = NULL;
  3331. }
  3332. if (NextLevelPrefixNames != NULL) {
  3333. MIDL_user_free( NextLevelPrefixNames );
  3334. NextLevelPrefixNames = NULL;
  3335. }
  3336. if (NextLevelSuffixNames != NULL) {
  3337. MIDL_user_free( NextLevelSuffixNames );
  3338. NextLevelSuffixNames = NULL;
  3339. }
  3340. //
  3341. // If necessary, free the Next Level Translated Sids array. Note
  3342. // that this array is allocated(all_nodes).
  3343. //
  3344. if (NextLevelSids != NULL) {
  3345. MIDL_user_free( NextLevelSids );
  3346. NextLevelSids = NULL;
  3347. }
  3348. //
  3349. // If necessary, free the array that maps Name Indices from the
  3350. // Next Level to the Current Level.
  3351. //
  3352. if (NameIndices != NULL) {
  3353. MIDL_user_free( NameIndices );
  3354. NameIndices = NULL;
  3355. }
  3356. return(Status);
  3357. LookupNamesInPrimaryDomainError:
  3358. //
  3359. // If the primary status was a success code, but the secondary
  3360. // status was an error, propagate the secondary status.
  3361. //
  3362. if ((!NT_SUCCESS(SecondaryStatus)) && NT_SUCCESS(Status)) {
  3363. Status = SecondaryStatus;
  3364. }
  3365. goto LookupNamesInPrimaryDomainFinish;
  3366. }
  3367. NTSTATUS
  3368. LsapDbLookupNamesInTrustedDomains(
  3369. IN ULONG LookupOptions,
  3370. IN ULONG Count,
  3371. IN BOOLEAN fIncludeIntraforest,
  3372. IN PLSAPR_UNICODE_STRING Names,
  3373. IN PLSAPR_UNICODE_STRING PrefixNames,
  3374. IN PLSAPR_UNICODE_STRING SuffixNames,
  3375. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3376. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  3377. IN LSAP_LOOKUP_LEVEL LookupLevel,
  3378. IN OUT PULONG MappedCount,
  3379. IN OUT PULONG CompletelyUnmappedCount,
  3380. IN NTSTATUS *NonFatalStatus
  3381. )
  3382. /*++
  3383. Routine Description:
  3384. This function attempts to lookup Names to see if they belong to
  3385. any of the Domains that are trusted by the Domain for which this
  3386. machine is a DC.
  3387. Arguments:
  3388. LookupOptions - LSA_LOOKUP_ISOLATED_AS_LOCAL
  3389. Count - Number of Names in the Names array, Note that some of these
  3390. may already have been mapped elsewhere, as specified by the
  3391. MappedCount parameter.
  3392. fIncludeIntraforest -- if TRUE, trusted domains in our local forest
  3393. are searched.
  3394. Names - Pointer to array of Names to be translated. Zero or all of the
  3395. Names may already have been translated elsewhere. If any of the
  3396. Names have been translated, the TranslatedSids parameter will point
  3397. to a location containing a non-NULL array of Sid translation
  3398. structures corresponding to the Names. If the nth Name has been
  3399. translated, the nth Sid translation structure will contain either a
  3400. non-NULL Sid or a non-negative offset into the Referenced Domain
  3401. List. If the nth Name has not yet been translated, the nth Sid
  3402. translation structure will contain a zero-length Sid string and a
  3403. negative value for the Referenced Domain List index.
  3404. PrefixNames - Pointer to an array of Count Unicode String structures
  3405. containing the Prefix portions of the Names. Names having no
  3406. Prefix are called Isolated Names. For these, the Unicode String
  3407. structure is set to contain a zero Length.
  3408. SuffixNames - Pointer to an array of Count Unicode String structures
  3409. containing the Suffix portions of the Names.
  3410. ReferencedDomains - Pointer to a Referenced Domain List. This
  3411. list references an array of zero or more Trust Information
  3412. entries describing each of the domains referenced by the names.
  3413. This array will be appended to/reallocated if necessary.
  3414. TranslatedSids - Pointer to structure that optionally references a list
  3415. of Sid translations for some of the Names in the Names array.
  3416. LookupLevel - Specifies the Level of Lookup to be performed on this
  3417. machine. Values of this field are are follows:
  3418. LsapLookupPDC - Second Level Lookup performed on a Primary Domain
  3419. Controller. The lookup searches the Account Domain of the
  3420. SAM Database on the controller. If not all Names are
  3421. found, the Trusted Domain List (TDL) is obtained from the
  3422. LSA's Policy Database and Third Level lookups are performed
  3423. via "handoff" to each Trusted Domain in the List.
  3424. LsapLookupTDL - Third Level Lookup performed on a controller
  3425. for a Trusted Domain. The lookup searches the Account Domain of
  3426. the SAM Database on the controller only.
  3427. NOTE: LsapLookupWksta is not valid for this parameter.
  3428. MappedCount - Pointer to location containing the number of Names
  3429. in the Names array that have already been mapped. This number
  3430. will be updated to reflect additional mapping done by this
  3431. routine.
  3432. CompletelyUnmappedCount - Pointer to location containing the
  3433. count of completely unmapped Names. A Name is completely unmapped
  3434. if it is unknown and non-composite, or composite but with an
  3435. unrecognized Domain component. This count is updated on exit, the
  3436. number of completely unmapped Namess whose Domain Prefices are
  3437. identified by this routine being subtracted from the input value.
  3438. NonFatalStatus - a status to indicate reasons why no names could have been
  3439. resolved
  3440. Return Values:
  3441. NTSTATUS - Standard Nt Result Code
  3442. STATUS_SUCCESS - The call completed successfully. Note that some
  3443. or all of the Names may remain partially or completely unmapped.
  3444. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  3445. such as memory, to complete the call.
  3446. --*/
  3447. {
  3448. NTSTATUS Status = STATUS_SUCCESS;
  3449. PLSAP_DB_LOOKUP_WORK_LIST WorkList = NULL;
  3450. *NonFatalStatus = STATUS_SUCCESS;
  3451. //
  3452. // Build a WorkList for this Lookup and put it on the Work Queue.
  3453. //
  3454. // NOTE: This routine does not need to hold the Lookup Work Queue
  3455. // lock to ensure validity of the WorkList pointer, because the
  3456. // pointer remains valid until this routine frees it via
  3457. // LsapDbLookupDeleteWorkList(). Although other threads may
  3458. // process the WorkList, do not delete it.
  3459. //
  3460. // A called routine must acquire the lock in order to access
  3461. // the WorkList after it has been added to the Work Queue.
  3462. //
  3463. Status = LsapDbLookupNamesBuildWorkList(
  3464. LookupOptions,
  3465. Count,
  3466. fIncludeIntraforest,
  3467. Names,
  3468. PrefixNames,
  3469. SuffixNames,
  3470. ReferencedDomains,
  3471. TranslatedSids,
  3472. LookupLevel,
  3473. MappedCount,
  3474. CompletelyUnmappedCount,
  3475. &WorkList
  3476. );
  3477. if (!NT_SUCCESS(Status)) {
  3478. //
  3479. // If no Work List has been built because there are no
  3480. // eligible domains to search, exit, suppressing the error.
  3481. if (Status == STATUS_NONE_MAPPED) {
  3482. Status = STATUS_SUCCESS;
  3483. goto LookupNamesInTrustedDomainsFinish;
  3484. }
  3485. goto LookupNamesInTrustedDomainsError;
  3486. }
  3487. //
  3488. // Start the work, by dispatching one or more worker threads
  3489. // if necessary.
  3490. //
  3491. Status = LsapDbLookupDispatchWorkerThreads( WorkList );
  3492. if (!NT_SUCCESS(Status)) {
  3493. goto LookupNamesInTrustedDomainsError;
  3494. }
  3495. //
  3496. // Wait for completion/termination of all items on the Work List.
  3497. //
  3498. Status = LsapDbLookupAwaitCompletionWorkList( WorkList );
  3499. if (!NT_SUCCESS(Status)) {
  3500. goto LookupNamesInTrustedDomainsError;
  3501. }
  3502. LookupNamesInTrustedDomainsFinish:
  3503. if ( WorkList &&
  3504. !NT_SUCCESS( WorkList->NonFatalStatus ) )
  3505. {
  3506. //
  3507. // Propogate the error as non fatal
  3508. //
  3509. *NonFatalStatus = WorkList->NonFatalStatus;
  3510. }
  3511. //
  3512. // If a Work List was created, delete it from the Work Queue
  3513. //
  3514. if (WorkList != NULL) {
  3515. Status = LsapDbLookupDeleteWorkList( WorkList );
  3516. WorkList = NULL;
  3517. }
  3518. return(Status);
  3519. LookupNamesInTrustedDomainsError:
  3520. goto LookupNamesInTrustedDomainsFinish;
  3521. }
  3522. NTSTATUS
  3523. LsapDbLookupTranslateNameDomain(
  3524. IN PLSAPR_TRUST_INFORMATION TrustInformation,
  3525. IN OPTIONAL PLSA_TRANSLATED_SID_EX2 TranslatedSid,
  3526. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3527. OUT PLONG DomainIndex
  3528. )
  3529. /*++
  3530. Routine Description:
  3531. This function optionally produces a Translated Sid entry for Domain
  3532. from its Name and Sid, and adds Trust Information for the Domain to
  3533. a Referenced Domain List. The index of the new (or existing) entry
  3534. in the Referenced Domain List is returned.
  3535. Arguments:
  3536. TrustInformation - Pointer to Trust Information for the Domain consisting
  3537. of its Name and Sid.
  3538. TranslatedSid - Optional pointer to Translated Sid entry which will
  3539. be filled in with the translation for this Domain. If NULL
  3540. is specified, no entry is fiiled in.
  3541. ReferencedDomains - Pointer to Referenced Domain List in which an
  3542. entry consisting of the Trust Information for the Domain will be
  3543. made if one does not already exist.
  3544. DomainIndex - Receives the index of the existing or new entry for the
  3545. Domain in the Referenced Domain List.
  3546. Return Values:
  3547. NTSTATUS - Standard Nt Result Code.
  3548. STATUS_SUCCESS - The call completed successfully.
  3549. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  3550. such as memory, to complete the call.
  3551. --*/
  3552. {
  3553. NTSTATUS Status;
  3554. Status = LsapDbLookupAddListReferencedDomains(
  3555. ReferencedDomains,
  3556. TrustInformation,
  3557. DomainIndex
  3558. );
  3559. if (!NT_SUCCESS(Status)) {
  3560. goto TranslateNameDomainError;
  3561. }
  3562. //
  3563. // If requested, fill in a Sid translation entry for the domain.
  3564. //
  3565. if (TranslatedSid != NULL) {
  3566. Status = LsapRpcCopySid(
  3567. NULL,
  3568. (PSID) &TranslatedSid->Sid,
  3569. (PSID) TrustInformation->Sid
  3570. );
  3571. if (!NT_SUCCESS(Status)) {
  3572. goto TranslateNameDomainError;
  3573. }
  3574. TranslatedSid->Use = SidTypeDomain;
  3575. TranslatedSid->DomainIndex = *DomainIndex;
  3576. }
  3577. TranslateNameDomainFinish:
  3578. return(Status);
  3579. TranslateNameDomainError:
  3580. goto TranslateNameDomainFinish;
  3581. }
  3582. NTSTATUS
  3583. LsapDbLookupTranslateUnknownNamesInDomain(
  3584. IN ULONG Count,
  3585. IN PLSAPR_UNICODE_STRING Names,
  3586. IN PLSAPR_UNICODE_STRING PrefixNames,
  3587. IN PLSAPR_UNICODE_STRING SuffixNames,
  3588. IN PLSAPR_TRUST_INFORMATION_EX TrustInformationEx,
  3589. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3590. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  3591. IN LSAP_LOOKUP_LEVEL LookupLevel,
  3592. IN OUT PULONG MappedCount,
  3593. IN OUT PULONG CompletelyUnmappedCount
  3594. )
  3595. /*++
  3596. Routine Description:
  3597. This function looks among the unknown Sids in the given list and
  3598. translates the Domain Name for any whose Domain Prefix Sid matches
  3599. the given Domain Sid.
  3600. Arguments:
  3601. Count - Number of Names in the Names array, Note that some of these
  3602. may already have been mapped elsewhere, as specified by the
  3603. MappedCount parameter.
  3604. Names - Pointer to array of Names to be translated.
  3605. Zero or all of the Names may already have been translated
  3606. elsewhere. If any of the Names have been translated, the
  3607. TranslatedSids parameter will point to a location containing a non-NULL
  3608. array of Sid translation structures corresponding to the
  3609. Names. If the nth Name has been translated, the nth Sid
  3610. translation structure will contain either a non-NULL Sid
  3611. or a non-negative offset into the Referenced Domain List. If
  3612. the nth Name has not yet been translated, the nth Sid
  3613. translation structure will contain a zero-length Sid string
  3614. and a negative value for the Referenced Domain List index.
  3615. PrefixNames - Pointer to an array of Count Unicode String structures
  3616. containing the Prefix portions of the Names. Names having no
  3617. Prefix are called Isolated Names. For these, the Unicode String
  3618. structure is set to contain a zero Length.
  3619. SuffixNames - Pointer to an array of Count Unicode String structures
  3620. containing the Suffix portions of the Names.
  3621. TrustInformation - Pointer to Trust Information specifying a Domain Sid
  3622. and Name.
  3623. ReferencedDomains - Pointer to a Referenced Domain List. This
  3624. list references an array of zero or more Trust Information
  3625. entries describing each of the domains referenced by the names.
  3626. This array will be appended to/reallocated if necessary.
  3627. TranslatedSids - Pointer to structure that optionally references a list
  3628. of Sid translations for some of the Names in the Names array.
  3629. LookupLevel - Specifies the Level of Lookup to be performed on this
  3630. machine. Values of this field are are follows:
  3631. LsapLookupPDC - Second Level Lookup performed on a Primary Domain
  3632. Controller. The lookup searches the Account Domain of the
  3633. SAM Database on the controller. If not all Names are
  3634. found, the Trusted Domain List (TDL) is obtained from the
  3635. LSA's Policy Database and Third Level lookups are performed
  3636. via "handoff" to each Trusted Domain in the List.
  3637. LsapLookupTDL - Third Level Lookup performed on a controller
  3638. for a Trusted Domain. The lookup searches the Account Domain of
  3639. the SAM Database on the controller only.
  3640. NOTE: LsapLookupWksta is not valid for this parameter.
  3641. MappedCount - Pointer to location containing the number of Names
  3642. in the Names array that have already been mapped. This number
  3643. will be updated to reflect additional mapping done by this
  3644. routine.
  3645. CompletelyUnmappedCount - Pointer to location containing the
  3646. count of completely unmapped Names. A Name is completely unmapped
  3647. if it is unknown and non-composite, or composite but with an
  3648. unrecognized Domain component. This count is updated on exit, the
  3649. number of completely unmapped Namess whose Domain Prefices are
  3650. identified by this routine being subtracted from the input value.
  3651. Return Values:
  3652. NTSTATUS - Standard Nt Result Code
  3653. STATUS_SUCCESS - The call completed successfully. Note that some
  3654. or all of the Names may remain partially or completely unmapped.
  3655. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  3656. such as memory, to complete the call.
  3657. --*/
  3658. {
  3659. NTSTATUS Status = STATUS_SUCCESS;
  3660. ULONG RemainingCompletelyUnmappedCount;
  3661. ULONG NameIndex;
  3662. PLSAPR_UNICODE_STRING DomainName = &TrustInformationEx->FlatName;
  3663. PLSAPR_UNICODE_STRING DnsDomainName = &TrustInformationEx->DomainName;
  3664. BOOLEAN DomainAlreadyAdded = FALSE;
  3665. LONG DomainIndex = 0;
  3666. LSAPR_TRUST_INFORMATION Dummy;
  3667. PLSAPR_TRUST_INFORMATION TrustInformation = &Dummy;
  3668. LsapConvertExTrustToOriginal( TrustInformation, TrustInformationEx );
  3669. //
  3670. // Scan the array of Names looking for composite ones whose domain has
  3671. // not been found.
  3672. //
  3673. for( NameIndex = 0,
  3674. RemainingCompletelyUnmappedCount = *CompletelyUnmappedCount;
  3675. (RemainingCompletelyUnmappedCount > 0) && (NameIndex < Count);
  3676. NameIndex++) {
  3677. //
  3678. // Check if this Name is completely unmapped (i.e. its domain
  3679. // has not yet been identified).
  3680. //
  3681. if (TranslatedSids->Sids[NameIndex].DomainIndex == LSA_UNKNOWN_INDEX) {
  3682. //
  3683. // Found a completely unmapped Name. If it belongs to the
  3684. // specified Domain, add the Domain to the Referenced Domain
  3685. // list if we have not already done so.
  3686. //
  3687. if (LsapRtlPrefixName(
  3688. (PUNICODE_STRING) DomainName,
  3689. (PUNICODE_STRING) &Names[NameIndex])
  3690. || LsapRtlPrefixName(
  3691. (PUNICODE_STRING) DnsDomainName,
  3692. (PUNICODE_STRING) &Names[NameIndex])
  3693. ) {
  3694. if (!DomainAlreadyAdded) {
  3695. Status = LsapDbLookupAddListReferencedDomains(
  3696. ReferencedDomains,
  3697. TrustInformation,
  3698. &DomainIndex
  3699. );
  3700. if (!NT_SUCCESS(Status)) {
  3701. break;
  3702. }
  3703. DomainAlreadyAdded = TRUE;
  3704. }
  3705. //
  3706. // Reference the domain from the TranslatedNames entry
  3707. //
  3708. TranslatedSids->Sids[NameIndex].DomainIndex = DomainIndex;
  3709. //
  3710. // This name is now partially translated, so reduce the
  3711. // count of completely unmapped names.
  3712. //
  3713. (*CompletelyUnmappedCount)--;
  3714. }
  3715. //
  3716. // Decrement count of completely unmapped Names scanned.
  3717. //
  3718. RemainingCompletelyUnmappedCount--;
  3719. }
  3720. }
  3721. return(Status);
  3722. }
  3723. NTSTATUS
  3724. LsapDbLookupIsolatedDomainName(
  3725. IN ULONG NameIndex,
  3726. IN PLSAPR_UNICODE_STRING IsolatedName,
  3727. IN PLSAPR_TRUST_INFORMATION TrustInformation,
  3728. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3729. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  3730. IN OUT PULONG MappedCount,
  3731. IN OUT PULONG CompletelyUnmappedCount
  3732. )
  3733. {
  3734. LSAPR_TRUST_INFORMATION_EX ex;
  3735. LsapConvertTrustToEx( &ex, TrustInformation );
  3736. return LsapDbLookupIsolatedDomainNameEx( NameIndex,
  3737. IsolatedName,
  3738. &ex,
  3739. ReferencedDomains,
  3740. TranslatedSids,
  3741. MappedCount,
  3742. CompletelyUnmappedCount);
  3743. }
  3744. NTSTATUS
  3745. LsapDbLookupIsolatedDomainNameEx(
  3746. IN ULONG NameIndex,
  3747. IN PLSAPR_UNICODE_STRING IsolatedName,
  3748. IN PLSAPR_TRUST_INFORMATION_EX TrustInformationEx,
  3749. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  3750. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  3751. IN OUT PULONG MappedCount,
  3752. IN OUT PULONG CompletelyUnmappedCount
  3753. )
  3754. /*++
  3755. Routine Description:
  3756. This function translates an Isolated Name if it matches a
  3757. given Domain Name.
  3758. Arguments:
  3759. NameIndex - Specifies the index of the entry for the Name within
  3760. the TranslatedSids array, which will be updated if the Name
  3761. matches the Domain Name contained in the TrusteInformation parameter.
  3762. IsolatedName - Specifies the Name to be compared with the Domain Name
  3763. contained in the TrustInformation parameter.
  3764. TrustInformation - Specifies the Name and Sid of a Domain.
  3765. Return Values:
  3766. NTSTATUS - Standard Nt Result Code
  3767. STATUS_SUCCESS - The call completed successfully.
  3768. STATUS_NONE_MAPPED - The specified name is not the same as the
  3769. name of the specified domain.
  3770. Result codes from called routines.
  3771. --*/
  3772. {
  3773. NTSTATUS Status = STATUS_NONE_MAPPED;
  3774. LSAPR_TRUST_INFORMATION Dummy;
  3775. PLSAPR_TRUST_INFORMATION TrustInformation = &Dummy;
  3776. ULONG Length;
  3777. LsapConvertExTrustToOriginal( TrustInformation, TrustInformationEx );
  3778. //
  3779. // See if the names match. If they don't, return error.
  3780. //
  3781. if (!LsapCompareDomainNames(
  3782. (PUNICODE_STRING) IsolatedName,
  3783. (PUNICODE_STRING) &(TrustInformationEx->DomainName),
  3784. (PUNICODE_STRING) &(TrustInformationEx->FlatName))
  3785. )
  3786. {
  3787. goto LookupIsolatedDomainNameError;
  3788. }
  3789. //
  3790. // Name matches the name of the given Domain. Add that
  3791. // Domain to the Referenced Domain List and translate it.
  3792. //
  3793. Status = LsapDbLookupAddListReferencedDomains(
  3794. ReferencedDomains,
  3795. TrustInformation,
  3796. (PLONG) &TranslatedSids->Sids[NameIndex].DomainIndex
  3797. );
  3798. if (!NT_SUCCESS(Status)) {
  3799. goto LookupIsolatedDomainNameError;
  3800. }
  3801. //
  3802. // Fill in the Translated Sids entry.
  3803. //
  3804. TranslatedSids->Sids[NameIndex].Use = SidTypeDomain;
  3805. Length = RtlLengthSid(TrustInformation->Sid);
  3806. TranslatedSids->Sids[NameIndex].Sid = MIDL_user_allocate(Length);
  3807. if (TranslatedSids->Sids[NameIndex].Sid == NULL) {
  3808. Status = STATUS_NO_MEMORY;
  3809. goto LookupIsolatedDomainNameError;
  3810. }
  3811. RtlCopySid(Length,
  3812. TranslatedSids->Sids[NameIndex].Sid,
  3813. TrustInformation->Sid);
  3814. Status = STATUS_SUCCESS;
  3815. (*MappedCount)++;
  3816. (*CompletelyUnmappedCount)--;
  3817. LookupIsolatedDomainNameFinish:
  3818. return(Status);
  3819. LookupIsolatedDomainNameError:
  3820. goto LookupIsolatedDomainNameFinish;
  3821. }
  3822. NTSTATUS
  3823. LsarGetUserName(
  3824. IN PLSAPR_SERVER_NAME ServerName,
  3825. IN OUT PLSAPR_UNICODE_STRING * UserName,
  3826. OUT OPTIONAL PLSAPR_UNICODE_STRING * DomainName
  3827. )
  3828. /*++
  3829. Routine Description:
  3830. This routine is the LSA Server worker routine for the LsaGetUserName
  3831. API.
  3832. WARNING: This routine allocates memory for its output. The caller is
  3833. responsible for freeing this memory after use. See description of the
  3834. Names parameter.
  3835. Arguments:
  3836. ServerName - the name of the server the client asked to execute
  3837. this API on, or NULL for the local machine.
  3838. UserName - Receives name of the current user.
  3839. DomainName - Optionally receives domain name of the current user.
  3840. Return Values:
  3841. NTSTATUS - Standard Nt Result Code
  3842. STATUS_SUCCESS - The call completed successfully and all Sids have
  3843. been translated to names.
  3844. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  3845. such as memory to complete the call.
  3846. --*/
  3847. {
  3848. LUID LogonId;
  3849. LUID SystemLogonId = SYSTEM_LUID ;
  3850. PUNICODE_STRING AccountName;
  3851. PUNICODE_STRING AuthorityName;
  3852. PSID UserSid;
  3853. PSID DomainSid = NULL;
  3854. ULONG Rid;
  3855. PLSAP_LOGON_SESSION LogonSession = NULL ;
  3856. PTOKEN_USER TokenUserInformation = NULL;
  3857. NTSTATUS Status;
  3858. LsarpReturnCheckSetup();
  3859. //
  3860. // Sanity check the input arguments
  3861. //
  3862. if ( *UserName != NULL ) {
  3863. return STATUS_INVALID_PARAMETER;
  3864. }
  3865. if (ARGUMENT_PRESENT(DomainName)) {
  3866. if ( *DomainName != NULL ) {
  3867. return STATUS_INVALID_PARAMETER;
  3868. }
  3869. }
  3870. //
  3871. // Let's see if we're trying to look up the currently logged on
  3872. // user.
  3873. //
  3874. //
  3875. // TokenUserInformation from this call must be freed by calling
  3876. // LsapFreeLsaHeap().
  3877. //
  3878. Status = LsapQueryClientInfo(
  3879. &TokenUserInformation,
  3880. &LogonId
  3881. );
  3882. if ( !NT_SUCCESS( Status )) {
  3883. goto Cleanup;
  3884. }
  3885. //
  3886. // If the user ID is Anonymous then there is no name and domain in the
  3887. // logon session
  3888. //
  3889. if (RtlEqualSid(
  3890. TokenUserInformation->User.Sid,
  3891. LsapAnonymousSid
  3892. )) {
  3893. AccountName = &WellKnownSids[LsapAnonymousSidIndex].Name;
  3894. AuthorityName = &WellKnownSids[LsapAnonymousSidIndex].DomainName;
  3895. } else if (RtlEqualLuid( &LogonId, &SystemLogonId ) ) {
  3896. AccountName = LsapDbWellKnownSidName( LsapLocalSystemSidIndex );
  3897. AuthorityName = LsapDbWellKnownSidDescription( LsapLocalSystemSidIndex );
  3898. } else {
  3899. LogonSession = LsapLocateLogonSession ( &LogonId );
  3900. //
  3901. // During setup, we may get NULL returned for the logon session.
  3902. //
  3903. if (LogonSession == NULL) {
  3904. Status = STATUS_NO_SUCH_LOGON_SESSION;
  3905. goto Cleanup;
  3906. }
  3907. //
  3908. // Got a match. Get the username and domain information
  3909. // from the LogonId
  3910. //
  3911. AccountName = &LogonSession->AccountName;
  3912. AuthorityName = &LogonSession->AuthorityName;
  3913. }
  3914. *UserName = MIDL_user_allocate(sizeof(LSAPR_UNICODE_STRING));
  3915. if (*UserName == NULL) {
  3916. Status = STATUS_INSUFFICIENT_RESOURCES;
  3917. goto Cleanup;
  3918. }
  3919. Status = LsapRpcCopyUnicodeString(
  3920. NULL,
  3921. (PUNICODE_STRING) *UserName,
  3922. AccountName
  3923. );
  3924. if (!NT_SUCCESS(Status)) {
  3925. goto Cleanup;
  3926. }
  3927. //
  3928. // Optionally copy the domain name
  3929. //
  3930. if (ARGUMENT_PRESENT(DomainName)) {
  3931. *DomainName = MIDL_user_allocate(sizeof(LSAPR_UNICODE_STRING));
  3932. if (*DomainName == NULL) {
  3933. Status = STATUS_INSUFFICIENT_RESOURCES;
  3934. goto Cleanup;
  3935. }
  3936. Status = LsapRpcCopyUnicodeString(
  3937. NULL,
  3938. (PUNICODE_STRING) *DomainName,
  3939. AuthorityName
  3940. );
  3941. if (!NT_SUCCESS(Status)) {
  3942. goto Cleanup;
  3943. }
  3944. }
  3945. Cleanup:
  3946. if ( LogonSession )
  3947. {
  3948. LsapReleaseLogonSession( LogonSession );
  3949. }
  3950. if (TokenUserInformation != NULL) {
  3951. LsapFreeLsaHeap( TokenUserInformation );
  3952. }
  3953. if (!NT_SUCCESS(Status)) {
  3954. if (*UserName != NULL) {
  3955. if ((*UserName)->Buffer != NULL) {
  3956. MIDL_user_free((*UserName)->Buffer);
  3957. }
  3958. MIDL_user_free(*UserName);
  3959. *UserName = NULL;
  3960. }
  3961. if ( ARGUMENT_PRESENT(DomainName) ){
  3962. if (*DomainName != NULL) {
  3963. if ((*DomainName)->Buffer != NULL) {
  3964. MIDL_user_free((*DomainName)->Buffer);
  3965. }
  3966. MIDL_user_free(*DomainName);
  3967. *DomainName = NULL;
  3968. }
  3969. }
  3970. }
  3971. LsarpReturnPrologue();
  3972. return(Status);
  3973. }
  3974. VOID
  3975. LsapDbFreeEnumerationBuffer(
  3976. IN PLSAP_DB_NAME_ENUMERATION_BUFFER DbEnumerationBuffer
  3977. )
  3978. /*++
  3979. Routine Description:
  3980. This routine will free the memory associated with an enumeration buffer
  3981. Arguments:
  3982. DbEnumerationBuffer - Enumeration buffer to free
  3983. Return Values:
  3984. VOID
  3985. --*/
  3986. {
  3987. ULONG i;
  3988. if ( DbEnumerationBuffer == NULL || DbEnumerationBuffer->EntriesRead == 0 ||
  3989. DbEnumerationBuffer->Names == NULL ) {
  3990. return;
  3991. }
  3992. for ( i = 0; i < DbEnumerationBuffer->EntriesRead; i++) {
  3993. MIDL_user_free( DbEnumerationBuffer->Names[ i ].Buffer );
  3994. }
  3995. MIDL_user_free( DbEnumerationBuffer->Names );
  3996. }
  3997. NTSTATUS
  3998. LsapDbLookupNamesInGlobalCatalog(
  3999. IN ULONG LookupOptions,
  4000. IN ULONG Count,
  4001. IN PLSAPR_UNICODE_STRING Names,
  4002. IN PLSAPR_UNICODE_STRING PrefixNames,
  4003. IN PLSAPR_UNICODE_STRING SuffixNames,
  4004. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  4005. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  4006. IN OUT PULONG MappedCount,
  4007. IN OUT PULONG CompletelyUnmappedCount,
  4008. OUT NTSTATUS *NonFatalStatus
  4009. )
  4010. /*++
  4011. Routine Description:
  4012. This routine looks at the list of name that have yet to be resolved.
  4013. If the any of the names belong to domain that are stored in the DS,
  4014. then these sids are packaged up and sent to a GC for translation.
  4015. Note: this will resolve names from domains that we trust directly and
  4016. indirectly
  4017. Note: names with no domain name are also sent to the GC
  4018. Arguments:
  4019. LookupOptions - LSA_LOOKUP_ISOLATED_AS_LOCAL
  4020. Count - Number of Names in the Names array, Note that some of these
  4021. may already have been mapped elsewhere, as specified by the
  4022. MappedCount parameter.
  4023. Names - Pointer to array of Names to be translated. Zero or all of the
  4024. Names may already have been translated elsewhere. If any of the
  4025. Names have been translated, the TranslatedSids parameter will point
  4026. to a location containing a non-NULL array of Sid translation
  4027. structures corresponding to the Names. If the nth Name has been
  4028. translated, the nth Sid translation structure will contain either a
  4029. non-NULL Sid or a non-negative offset into the Referenced Domain
  4030. List. If the nth Name has not yet been translated, the nth Sid
  4031. translation structure will contain a zero-length Sid string and a
  4032. negative value for the Referenced Domain List index.
  4033. PrefixNames - Pointer to an array of Count Unicode String structures
  4034. containing the Prefix portions of the Names. Names having no
  4035. Prefix are called Isolated Names. For these, the Unicode String
  4036. structure is set to contain a zero Length.
  4037. SuffixNames - Pointer to an array of Count Unicode String structures
  4038. containing the Suffix portions of the Names.
  4039. ReferencedDomains - Pointer to a Referenced Domain List. This
  4040. list references an array of zero or more Trust Information
  4041. entries describing each of the domains referenced by the names.
  4042. This array will be appended to/reallocated if necessary.
  4043. TranslatedSids - Pointer to structure that optionally references a list
  4044. of Sid translations for some of the Names in the Names array.
  4045. MappedCount - Pointer to location containing the number of Names
  4046. in the Names array that have already been mapped. This number
  4047. will be updated to reflect additional mapping done by this
  4048. routine.
  4049. CompletelyUnmappedCount - Pointer to location containing the
  4050. count of completely unmapped Names. A Name is completely unmapped
  4051. if it is unknown and non-composite, or composite but with an
  4052. unrecognized Domain component. This count is updated on exit, the
  4053. number of completely unmapped Namess whose Domain Prefices are
  4054. identified by this routine being subtracted from the input value.
  4055. NonFatalStatus - a status to indicate reasons why no names could have been
  4056. resolved
  4057. Return Values:
  4058. NTSTATUS - Standard Nt Result Code
  4059. STATUS_SUCCESS - The call completed successfully. Note that some
  4060. or all of the Names may remain partially or completely unmapped.
  4061. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  4062. such as memory, to complete the call.
  4063. --*/
  4064. {
  4065. NTSTATUS Status = STATUS_SUCCESS;
  4066. ULONG cGcNames = 0;
  4067. BOOLEAN *PossibleGcNames = NULL;
  4068. SID_NAME_USE *GcSidNameUse = NULL;
  4069. UNICODE_STRING *GcNames = NULL;
  4070. ULONG *GcNameOriginalIndex = NULL;
  4071. PSAMPR_PSID_ARRAY SidArray = NULL;
  4072. ULONG *GcNamesFlags = NULL;
  4073. ULONG Length;
  4074. ULONG i;
  4075. *NonFatalStatus = STATUS_SUCCESS;
  4076. //
  4077. // Determine what sids are part of known nt5 domains
  4078. // and package into an array
  4079. //
  4080. ASSERT( Count == TranslatedSids->Entries );
  4081. if ( !SampUsingDsData() ) {
  4082. //
  4083. // Only useful if the ds is running
  4084. //
  4085. return STATUS_SUCCESS;
  4086. }
  4087. PossibleGcNames = MIDL_user_allocate( Count * sizeof(BOOLEAN) );
  4088. if ( !PossibleGcNames ) {
  4089. Status = STATUS_INSUFFICIENT_RESOURCES;
  4090. goto Finish;
  4091. }
  4092. RtlZeroMemory( PossibleGcNames, Count * sizeof(BOOLEAN) );
  4093. for ( i = 0; i < Count; i++ ) {
  4094. if ( LsapDbCompletelyUnmappedSid(&TranslatedSids->Sids[i]) ) {
  4095. //
  4096. // If the name
  4097. //
  4098. // 1. has a domain portion and
  4099. // 2. the domain is not in the forest and
  4100. // 3. the domain is a directly trusted domain
  4101. //
  4102. // then don't look up at the GC -- use the direct
  4103. // trust link instead
  4104. //
  4105. if ( PrefixNames[i].Length != 0 ) {
  4106. NTSTATUS Status2;
  4107. Status2 = LsapDomainHasDirectExternalTrust((PUNICODE_STRING)&PrefixNames[i],
  4108. NULL,
  4109. NULL,
  4110. NULL);
  4111. if (NT_SUCCESS(Status2)) {
  4112. continue;
  4113. }
  4114. }
  4115. //
  4116. // If the name is isolated are we are asked not to lookup isolated
  4117. // names, then don't send to the GC
  4118. //
  4119. if ((LookupOptions & LSA_LOOKUP_ISOLATED_AS_LOCAL)
  4120. && PrefixNames[i].Length == 0 ) {
  4121. continue;
  4122. }
  4123. //
  4124. // Can no longer filter since some names might belog to trusted
  4125. // forest. Note this also fixes 196280.
  4126. //
  4127. cGcNames++;
  4128. PossibleGcNames[i] = TRUE;
  4129. }
  4130. }
  4131. // We should no more than the number of unmapped sids!
  4132. ASSERT( cGcNames <= *CompletelyUnmappedCount );
  4133. if ( 0 == cGcNames ) {
  4134. // nothing to do
  4135. goto Finish;
  4136. }
  4137. //
  4138. // Allocate lots of space to hold the resolved names; this space will
  4139. // be freed at the end of the routine
  4140. //
  4141. GcNames = MIDL_user_allocate( cGcNames * sizeof(UNICODE_STRING) );
  4142. if ( !GcNames ) {
  4143. Status = STATUS_INSUFFICIENT_RESOURCES;
  4144. goto Finish;
  4145. }
  4146. RtlZeroMemory( GcNames, cGcNames * sizeof(UNICODE_STRING) );
  4147. GcNameOriginalIndex = MIDL_user_allocate( cGcNames * sizeof(ULONG) );
  4148. if ( !GcNameOriginalIndex ) {
  4149. Status = STATUS_INSUFFICIENT_RESOURCES;
  4150. goto Finish;
  4151. }
  4152. RtlZeroMemory( GcNameOriginalIndex, cGcNames * sizeof(ULONG) );
  4153. cGcNames = 0;
  4154. for ( i = 0; i < Count; i++ ) {
  4155. if ( PossibleGcNames[i] ) {
  4156. ASSERT( sizeof(GcNames[cGcNames]) == sizeof(Names[i]) );
  4157. memcpy( &GcNames[cGcNames], &Names[i], sizeof(UNICODE_STRING) );
  4158. GcNameOriginalIndex[cGcNames] = i;
  4159. cGcNames++;
  4160. }
  4161. }
  4162. // we are done with this
  4163. MIDL_user_free( PossibleGcNames );
  4164. PossibleGcNames = NULL;
  4165. GcSidNameUse = MIDL_user_allocate( cGcNames * sizeof(SID_NAME_USE) );
  4166. if ( !GcSidNameUse ) {
  4167. Status = STATUS_INSUFFICIENT_RESOURCES;
  4168. goto Finish;
  4169. }
  4170. RtlZeroMemory( GcSidNameUse, cGcNames * sizeof(SID_NAME_USE) );
  4171. GcNamesFlags = MIDL_user_allocate( cGcNames * sizeof(ULONG) );
  4172. if ( !GcNamesFlags ) {
  4173. Status = STATUS_INSUFFICIENT_RESOURCES;
  4174. goto Finish;
  4175. }
  4176. RtlZeroMemory( GcNamesFlags, cGcNames * sizeof(ULONG) );
  4177. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: Chaining a name request to a GC\n"));
  4178. //
  4179. // Call into SAM to resolve the sids at a GC
  4180. //
  4181. Status = SamIGCLookupNames( cGcNames,
  4182. GcNames,
  4183. SAMP_LOOKUP_BY_UPN,
  4184. GcNamesFlags,
  4185. GcSidNameUse,
  4186. &SidArray );
  4187. if (!NT_SUCCESS(Status)) {
  4188. LsapDiagPrint( DB_LOOKUP_WORK_LIST, ("LSA: Chain to GC request failed (0x%x)\n", Status));
  4189. }
  4190. if ( STATUS_DS_GC_NOT_AVAILABLE == Status ) {
  4191. //
  4192. // Ok, don't update the mapped count since no names were
  4193. // resolved
  4194. //
  4195. LsapDbLookupReportEvent0( 1,
  4196. EVENTLOG_WARNING_TYPE,
  4197. LSAEVENT_LOOKUP_GC_FAILED,
  4198. sizeof( ULONG ),
  4199. &Status);
  4200. *NonFatalStatus = Status;
  4201. Status = STATUS_SUCCESS;
  4202. goto Finish;
  4203. }
  4204. // Any other error is fatal
  4205. if ( !NT_SUCCESS( Status ) ) {
  4206. goto Finish;
  4207. }
  4208. //
  4209. // For each name resolved, put back in the original array and update
  4210. // the referenced domain's list
  4211. //
  4212. for ( i = 0; i < cGcNames; i++ ) {
  4213. BOOLEAN fStatus;
  4214. ULONG OriginalIndex;
  4215. LSAPR_TRUST_INFORMATION TrustInformation;
  4216. PSID DomainSid = NULL;
  4217. ULONG Rid = 0;
  4218. ULONG DomainIndex = LSA_UNKNOWN_INDEX;
  4219. RtlZeroMemory( &TrustInformation, sizeof(TrustInformation) );
  4220. if (GcNamesFlags[i] & SAMP_FOUND_XFOREST_REF) {
  4221. //
  4222. // Flag this entry to be resolved in a trusted forest
  4223. //
  4224. OriginalIndex = GcNameOriginalIndex[i];
  4225. TranslatedSids->Sids[OriginalIndex].Flags |= LSA_LOOKUP_NAME_XFOREST_REF;
  4226. }
  4227. if ( SidTypeUnknown == GcSidNameUse[i] ) {
  4228. // go on to the next one right away
  4229. goto IterationCleanup;
  4230. }
  4231. //
  4232. // This name was resolved!
  4233. //
  4234. if ( GcSidNameUse[i] != SidTypeDomain ) {
  4235. // This is not a domain object, so make sure there
  4236. // is a domain reference for this object
  4237. Status = LsapSplitSid( SidArray->Sids[i].SidPointer,
  4238. &DomainSid,
  4239. &Rid );
  4240. if ( !NT_SUCCESS( Status ) ) {
  4241. goto IterationCleanup;
  4242. }
  4243. } else {
  4244. DomainSid = SidArray->Sids[i].SidPointer;
  4245. }
  4246. if ( LsapIsBuiltinDomain( DomainSid ) ) {
  4247. // don't map this since all searches are implicitly
  4248. // over the account domain, not the builtin domain
  4249. Status = STATUS_SUCCESS;
  4250. goto IterationCleanup;
  4251. }
  4252. fStatus = LsapDbLookupListReferencedDomains( ReferencedDomains,
  4253. DomainSid,
  4254. &DomainIndex );
  4255. if ( FALSE == fStatus ) {
  4256. //
  4257. // No entry for this domain -- add it
  4258. //
  4259. // Set the sid
  4260. TrustInformation.Sid = DomainSid;
  4261. DomainSid = NULL;
  4262. // Allocate and set the name
  4263. Status = LsapGetDomainNameBySid( TrustInformation.Sid,
  4264. (PUNICODE_STRING) &TrustInformation.Name );
  4265. if ( STATUS_NO_SUCH_DOMAIN == Status ) {
  4266. //
  4267. // We longer know about this domain, though we did
  4268. // before we sent the name off to the GC.
  4269. // Don't resolve this name, but do continue on with
  4270. // the next name
  4271. //
  4272. Status = STATUS_SUCCESS;
  4273. goto IterationCleanup;
  4274. }
  4275. // Any other error is a resource error
  4276. if ( !NT_SUCCESS( Status ) ) {
  4277. goto IterationCleanup;
  4278. }
  4279. //
  4280. // Add the entry
  4281. //
  4282. Status = LsapDbLookupAddListReferencedDomains( ReferencedDomains,
  4283. &TrustInformation,
  4284. &DomainIndex );
  4285. if ( !NT_SUCCESS( Status ) ) {
  4286. goto IterationCleanup;
  4287. }
  4288. }
  4289. // We should now have a domain index
  4290. ASSERT( LSA_UNKNOWN_INDEX != DomainIndex );
  4291. // Set the information
  4292. OriginalIndex = GcNameOriginalIndex[i];
  4293. TranslatedSids->Sids[OriginalIndex].Use = GcSidNameUse[i];
  4294. Length = RtlLengthSid(SidArray->Sids[i].SidPointer);
  4295. TranslatedSids->Sids[OriginalIndex].Sid = MIDL_user_allocate(Length);
  4296. if (TranslatedSids->Sids[OriginalIndex].Sid == NULL) {
  4297. Status = STATUS_NO_MEMORY;
  4298. goto IterationCleanup;
  4299. }
  4300. RtlCopySid(Length,
  4301. TranslatedSids->Sids[OriginalIndex].Sid,
  4302. SidArray->Sids[i].SidPointer);
  4303. TranslatedSids->Sids[OriginalIndex].DomainIndex = DomainIndex;
  4304. if ( !(GcNamesFlags[i] & SAMP_FOUND_BY_SAM_ACCOUNT_NAME) ) {
  4305. TranslatedSids->Sids[OriginalIndex].Flags |= LSA_LOOKUP_NAME_NOT_SAM_ACCOUNT_NAME;
  4306. }
  4307. (*MappedCount) += 1;
  4308. (*CompletelyUnmappedCount) -= 1;
  4309. IterationCleanup:
  4310. if ( TrustInformation.Sid
  4311. && (VOID*)TrustInformation.Sid != (VOID*)SidArray->Sids[i].SidPointer ) {
  4312. MIDL_user_free( TrustInformation.Sid );
  4313. }
  4314. if ( TrustInformation.Name.Buffer ) {
  4315. MIDL_user_free( TrustInformation.Name.Buffer );
  4316. }
  4317. if ( DomainSid && DomainSid != SidArray->Sids[i].SidPointer ) {
  4318. MIDL_user_free( DomainSid );
  4319. }
  4320. if ( !NT_SUCCESS( Status ) ) {
  4321. break;
  4322. }
  4323. } // iterate over names returned from the GC search
  4324. Finish:
  4325. SamIFreeSidArray( SidArray );
  4326. if ( PossibleGcNames ) {
  4327. MIDL_user_free( PossibleGcNames );
  4328. }
  4329. if ( GcSidNameUse ) {
  4330. MIDL_user_free( GcSidNameUse );
  4331. }
  4332. if ( GcNames ) {
  4333. MIDL_user_free( GcNames );
  4334. }
  4335. if ( GcNameOriginalIndex ) {
  4336. MIDL_user_free( GcNameOriginalIndex );
  4337. }
  4338. if ( GcNamesFlags ) {
  4339. MIDL_user_free( GcNamesFlags );
  4340. }
  4341. //
  4342. // Note: on error, higher level should will free the memory
  4343. // in the returned arrays
  4344. //
  4345. return Status;
  4346. }
  4347. NTSTATUS
  4348. LsapDbLookupNamesInGlobalCatalogWks(
  4349. IN ULONG LookupOptions,
  4350. IN ULONG Count,
  4351. IN PLSAPR_UNICODE_STRING Names,
  4352. IN PLSAPR_UNICODE_STRING PrefixNames,
  4353. IN PLSAPR_UNICODE_STRING SuffixNames,
  4354. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  4355. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  4356. IN OUT PULONG MappedCount,
  4357. IN OUT PULONG CompletelyUnmappedCount,
  4358. OUT NTSTATUS *NonFatalStatus
  4359. )
  4360. /*++
  4361. Routine Description:
  4362. This routine is called from a non-DC when the secure channel DC is a pre
  4363. windows 2000 DC and thus can't talk to a GC. This routine finds a GC
  4364. and lookups up the remaining unresolved names at that GC.
  4365. Arguments:
  4366. Count - Number of Names in the Names array, Note that some of these
  4367. may already have been mapped elsewhere, as specified by the
  4368. MappedCount parameter.
  4369. LookupOptions - LSA_LOOKUP_ISOLATED_AS_LOCAL
  4370. Names - Pointer to array of Names to be translated. Zero or all of the
  4371. Names may already have been translated elsewhere. If any of the
  4372. Names have been translated, the TranslatedSids parameter will point
  4373. to a location containing a non-NULL array of Sid translation
  4374. structures corresponding to the Names. If the nth Name has been
  4375. translated, the nth Sid translation structure will contain either a
  4376. non-NULL Sid or a non-negative offset into the Referenced Domain
  4377. List. If the nth Name has not yet been translated, the nth Sid
  4378. translation structure will contain a zero-length Sid string and a
  4379. negative value for the Referenced Domain List index.
  4380. PrefixNames - Pointer to an array of Count Unicode String structures
  4381. containing the Prefix portions of the Names. Names having no
  4382. Prefix are called Isolated Names. For these, the Unicode String
  4383. structure is set to contain a zero Length.
  4384. SuffixNames - Pointer to an array of Count Unicode String structures
  4385. containing the Suffix portions of the Names.
  4386. ReferencedDomains - Pointer to a Referenced Domain List. This
  4387. list references an array of zero or more Trust Information
  4388. entries describing each of the domains referenced by the names.
  4389. This array will be appended to/reallocated if necessary.
  4390. TranslatedSids - Pointer to structure that optionally references a list
  4391. of Sid translations for some of the Names in the Names array.
  4392. MappedCount - Pointer to location containing the number of Names
  4393. in the Names array that have already been mapped. This number
  4394. will be updated to reflect additional mapping done by this
  4395. routine.
  4396. CompletelyUnmappedCount - Pointer to location containing the
  4397. count of completely unmapped Names. A Name is completely unmapped
  4398. if it is unknown and non-composite, or composite but with an
  4399. unrecognized Domain component. This count is updated on exit, the
  4400. number of completely unmapped Namess whose Domain Prefices are
  4401. identified by this routine being subtracted from the input value.
  4402. NonFatalStatus - a status to indicate reasons why no names could have been
  4403. resolved
  4404. Return Values:
  4405. NTSTATUS - Standard Nt Result Code
  4406. STATUS_SUCCESS - The call completed successfully. Note that some
  4407. or all of the Names may remain partially or completely unmapped.
  4408. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  4409. such as memory, to complete the call.
  4410. --*/
  4411. {
  4412. NTSTATUS Status = STATUS_SUCCESS;
  4413. NTSTATUS SecondaryStatus = STATUS_SUCCESS;
  4414. LSA_HANDLE ControllerPolicyHandle = NULL;
  4415. ULONG NextLevelCount;
  4416. ULONG NextLevelMappedCount;
  4417. ULONG NameIndex;
  4418. ULONG NextLevelNameIndex;
  4419. PLSAPR_REFERENCED_DOMAIN_LIST NextLevelReferencedDomains = NULL;
  4420. PLSAPR_REFERENCED_DOMAIN_LIST OutputReferencedDomains = NULL;
  4421. PLSAPR_TRANSLATED_SID_EX2 NextLevelSids = NULL;
  4422. PLSAPR_UNICODE_STRING NextLevelNames = NULL;
  4423. PLSAPR_UNICODE_STRING NextLevelPrefixNames = NULL;
  4424. PLSAPR_UNICODE_STRING NextLevelSuffixNames = NULL;
  4425. LONG FirstEntryIndex;
  4426. PULONG NameIndices = NULL;
  4427. BOOLEAN PartialNameTranslationsAttempted = FALSE;
  4428. LPWSTR ServerName = NULL;
  4429. LPWSTR ServerPrincipalName = NULL;
  4430. PVOID ClientContext = NULL;
  4431. ULONG ServerRevision;
  4432. *NonFatalStatus = STATUS_SUCCESS;
  4433. //
  4434. // If there are no completely unmapped Names remaining, just return.
  4435. //
  4436. if (*CompletelyUnmappedCount == (ULONG) 0) {
  4437. goto LookupNamesInPrimaryDomainFinish;
  4438. }
  4439. //
  4440. // Open the Policy object on some GC in the forest.
  4441. //
  4442. Status = LsapDbOpenPolicyGc( &ControllerPolicyHandle );
  4443. if (!NT_SUCCESS(Status)) {
  4444. //
  4445. // We cannot access the Global Catalog. Suppress the error
  4446. // and translate Domain Prefix Sids for Sids belonging to
  4447. // the Primary Domain.
  4448. //
  4449. //
  4450. // If we can't open a open a secure channel if a DC call
  4451. // this a trust relationship problem
  4452. //
  4453. *NonFatalStatus = STATUS_DS_GC_NOT_AVAILABLE;
  4454. Status = STATUS_SUCCESS;
  4455. goto LookupNamesInPrimaryDomainFinish;
  4456. }
  4457. //
  4458. // We have successfully opened a Domain Controller's Policy
  4459. // Database. Now prepare to hand off a Name lookup for the
  4460. // remaining unmapped Names to that Controller. Here, this
  4461. // server side of the LSA is a client of the LSA on the
  4462. // target controller. We will construct an array of the
  4463. // remianing unmapped Names, look them up and then merge the
  4464. // resulting ReferencedDomains and Translated Sids into
  4465. // our existing list.
  4466. //
  4467. NextLevelCount = *CompletelyUnmappedCount;
  4468. //
  4469. // Allocate an array to hold the indices of unmapped Names
  4470. // relative to the original Names and TranslatedSids->Sids
  4471. // arrays.
  4472. //
  4473. NameIndices = MIDL_user_allocate(NextLevelCount * sizeof(ULONG));
  4474. Status = STATUS_INSUFFICIENT_RESOURCES;
  4475. if (NameIndices == NULL) {
  4476. goto LookupNamesInPrimaryDomainError;
  4477. }
  4478. //
  4479. // Allocate an array of UNICODE_STRING structures for the
  4480. // names to be looked up at the Domain Controller.
  4481. //
  4482. NextLevelNames = MIDL_user_allocate(
  4483. sizeof(UNICODE_STRING) * NextLevelCount
  4484. );
  4485. if (NextLevelNames == NULL) {
  4486. goto LookupNamesInPrimaryDomainError;
  4487. }
  4488. //
  4489. // Allocate an array of UNICODE_STRING structures for the
  4490. // prefix names to be cached.
  4491. //
  4492. NextLevelPrefixNames = MIDL_user_allocate(
  4493. sizeof(UNICODE_STRING) * NextLevelCount
  4494. );
  4495. if (NextLevelPrefixNames == NULL) {
  4496. goto LookupNamesInPrimaryDomainError;
  4497. }
  4498. //
  4499. // Allocate an array of UNICODE_STRING structures for the
  4500. // suffix names to be cached.
  4501. //
  4502. NextLevelSuffixNames = MIDL_user_allocate(
  4503. sizeof(UNICODE_STRING) * NextLevelCount
  4504. );
  4505. if (NextLevelSuffixNames == NULL) {
  4506. goto LookupNamesInPrimaryDomainError;
  4507. }
  4508. Status = STATUS_SUCCESS;
  4509. //
  4510. // Now scan the original array of Names and its parallel
  4511. // Translated Sids array. Copy over any names that are completely
  4512. // unmapped.
  4513. //
  4514. NextLevelNameIndex = (ULONG) 0;
  4515. for (NameIndex = 0;
  4516. NameIndex < Count && NextLevelNameIndex < NextLevelCount;
  4517. NameIndex++) {
  4518. if ( (LookupOptions & LSA_LOOKUP_ISOLATED_AS_LOCAL)
  4519. && (PrefixNames[NameIndex].Length == 0) ) {
  4520. //
  4521. // Don't lookup isolated names off machine
  4522. //
  4523. continue;
  4524. }
  4525. if (LsapDbCompletelyUnmappedSid(&TranslatedSids->Sids[NameIndex])) {
  4526. NextLevelNames[NextLevelNameIndex] = Names[NameIndex];
  4527. NextLevelPrefixNames[NextLevelNameIndex] = PrefixNames[NameIndex];
  4528. NextLevelSuffixNames[NextLevelNameIndex] = SuffixNames[NameIndex];
  4529. NameIndices[NextLevelNameIndex] = NameIndex;
  4530. NextLevelNameIndex++;
  4531. }
  4532. }
  4533. if (NameIndex == 0) {
  4534. // Nothing to do
  4535. Status = STATUS_SUCCESS;
  4536. goto LookupNamesInPrimaryDomainFinish;
  4537. }
  4538. NextLevelMappedCount = (ULONG) 0;
  4539. Status = LsaICLookupNames(
  4540. ControllerPolicyHandle,
  4541. 0, // no flags necessary
  4542. NextLevelCount,
  4543. (PUNICODE_STRING) NextLevelNames,
  4544. (PLSA_REFERENCED_DOMAIN_LIST *) &NextLevelReferencedDomains,
  4545. (PLSA_TRANSLATED_SID_EX2 *) &NextLevelSids,
  4546. LsapLookupGC,
  4547. 0,
  4548. &NextLevelMappedCount,
  4549. &ServerRevision
  4550. );
  4551. //
  4552. // If the callout to LsaLookupNames() was unsuccessful, disregard
  4553. // the error and set the domain name for any Sids having this
  4554. // domain Sid as prefix sid.
  4555. //
  4556. if (!NT_SUCCESS(Status)) {
  4557. //
  4558. // Let the caller know there is a trust problem
  4559. //
  4560. if ( (STATUS_TRUSTED_DOMAIN_FAILURE == Status)
  4561. || (STATUS_DS_GC_NOT_AVAILABLE == Status) ) {
  4562. *NonFatalStatus = Status;
  4563. }
  4564. Status = STATUS_SUCCESS;
  4565. goto LookupNamesInPrimaryDomainFinish;
  4566. }
  4567. //
  4568. // Cache any sids that came back
  4569. //
  4570. (void) LsapDbUpdateCacheWithNames(
  4571. (PUNICODE_STRING) NextLevelSuffixNames,
  4572. (PUNICODE_STRING) NextLevelPrefixNames,
  4573. NextLevelCount,
  4574. NextLevelReferencedDomains,
  4575. NextLevelSids
  4576. );
  4577. //
  4578. // The callout to LsaLookupNames() was successful. We now have
  4579. // an additional list of Referenced Domains containing the
  4580. // Primary Domain and/or one or more of its Trusted Domains.
  4581. // Merge the two Referenced Domain Lists together, noting that
  4582. // since they are disjoint, the second list is simply
  4583. // concatenated with the first. The index of the first entry
  4584. // of the second list will be used to adjust all of the
  4585. // Domain Index entries in the Translated Names entries.
  4586. // Note that since the memory for the graph of the first
  4587. // Referenced Domain list has been allocated as individual
  4588. // nodes, we specify that the nodes in this graph can be
  4589. // referenced by the output Referenced Domain list.
  4590. //
  4591. Status = LsapDbLookupMergeDisjointReferencedDomains(
  4592. ReferencedDomains,
  4593. NextLevelReferencedDomains,
  4594. &OutputReferencedDomains,
  4595. LSAP_DB_USE_FIRST_MERGAND_GRAPH
  4596. );
  4597. if (!NT_SUCCESS(Status)) {
  4598. goto LookupNamesInPrimaryDomainError;
  4599. }
  4600. FirstEntryIndex = ReferencedDomains->Entries;
  4601. //
  4602. // Now update the original list of Translated Names. We
  4603. // update each entry that has newly been translated by copying
  4604. // the entry from the new list and adjusting its
  4605. // Referenced Domain List Index upwards by adding the index
  4606. // of the first entry in the Next level List..
  4607. //
  4608. for( NextLevelNameIndex = 0;
  4609. NextLevelNameIndex < NextLevelCount;
  4610. NextLevelNameIndex++ ) {
  4611. if ( !LsapDbCompletelyUnmappedSid(&NextLevelSids[NextLevelNameIndex]) ) {
  4612. NameIndex = NameIndices[NextLevelNameIndex];
  4613. TranslatedSids->Sids[NameIndex]
  4614. = NextLevelSids[NextLevelNameIndex];
  4615. Status = LsapRpcCopySid(NULL,
  4616. &TranslatedSids->Sids[NameIndex].Sid,
  4617. NextLevelSids[NextLevelNameIndex].Sid);
  4618. if (!NT_SUCCESS(Status)) {
  4619. goto LookupNamesInPrimaryDomainError;
  4620. }
  4621. TranslatedSids->Sids[NameIndex].DomainIndex =
  4622. FirstEntryIndex +
  4623. NextLevelSids[NextLevelNameIndex].DomainIndex;
  4624. (*CompletelyUnmappedCount)--;
  4625. }
  4626. }
  4627. //
  4628. // Update the Referenced Domain List if a new one was produced
  4629. // from the merge. We retain the original top-level structure.
  4630. //
  4631. if (OutputReferencedDomains != NULL) {
  4632. if (ReferencedDomains->Domains != NULL) {
  4633. MIDL_user_free( ReferencedDomains->Domains );
  4634. ReferencedDomains->Domains = NULL;
  4635. }
  4636. *ReferencedDomains = *OutputReferencedDomains;
  4637. MIDL_user_free( OutputReferencedDomains );
  4638. OutputReferencedDomains = NULL;
  4639. }
  4640. //
  4641. // Update the Mapped Count and close the Controller Policy
  4642. // Handle.
  4643. //
  4644. *MappedCount += NextLevelMappedCount;
  4645. SecondaryStatus = LsaClose( ControllerPolicyHandle );
  4646. ControllerPolicyHandle = NULL;
  4647. //
  4648. // Any error status that has not been suppressed must be reported
  4649. // to the caller. Errors such as connection failures to other LSA's
  4650. // are suppressed.
  4651. //
  4652. if (!NT_SUCCESS(Status)) {
  4653. goto LookupNamesInPrimaryDomainError;
  4654. }
  4655. LookupNamesInPrimaryDomainFinish:
  4656. //
  4657. // If necessary, update count of completely unmapped names.
  4658. //
  4659. if (*CompletelyUnmappedCount > (ULONG) 0) {
  4660. LsapDbUpdateCountCompUnmappedNames(TranslatedSids, CompletelyUnmappedCount);
  4661. }
  4662. //
  4663. // If necessary, free the Next Level Referenced Domain List.
  4664. // Note that this structure is allocated(all_nodes) since it was
  4665. // allocated by the client side of the Domain Controller LSA.
  4666. //
  4667. if (NextLevelReferencedDomains != NULL) {
  4668. MIDL_user_free( NextLevelReferencedDomains );
  4669. NextLevelReferencedDomains = NULL;
  4670. }
  4671. //
  4672. // If necessary, free the Next Level Names array. We only free the
  4673. // top level, since the names therein were copied from the input
  4674. // TranslatedNames->Names array.
  4675. //
  4676. if (NextLevelNames != NULL) {
  4677. MIDL_user_free( NextLevelNames );
  4678. NextLevelNames = NULL;
  4679. }
  4680. if (NextLevelPrefixNames != NULL) {
  4681. MIDL_user_free( NextLevelPrefixNames );
  4682. NextLevelPrefixNames = NULL;
  4683. }
  4684. if (NextLevelSuffixNames != NULL) {
  4685. MIDL_user_free( NextLevelSuffixNames );
  4686. NextLevelSuffixNames = NULL;
  4687. }
  4688. //
  4689. // If necessary, free the Next Level Translated Sids array. Note
  4690. // that this array is allocated(all_nodes).
  4691. //
  4692. if (NextLevelSids != NULL) {
  4693. MIDL_user_free( NextLevelSids );
  4694. NextLevelSids = NULL;
  4695. }
  4696. //
  4697. // If necessary, free the array that maps Name Indices from the
  4698. // Next Level to the Current Level.
  4699. //
  4700. if (NameIndices != NULL) {
  4701. MIDL_user_free( NameIndices );
  4702. NameIndices = NULL;
  4703. }
  4704. //
  4705. // If necessary, close the Controller Policy Handle.
  4706. //
  4707. if ( ControllerPolicyHandle != NULL) {
  4708. SecondaryStatus = LsaClose( ControllerPolicyHandle );
  4709. ControllerPolicyHandle = NULL;
  4710. if (!NT_SUCCESS(SecondaryStatus)) {
  4711. goto LookupNamesInPrimaryDomainError;
  4712. }
  4713. }
  4714. return(Status);
  4715. LookupNamesInPrimaryDomainError:
  4716. //
  4717. // If the primary status was a success code, but the secondary
  4718. // status was an error, propagate the secondary status.
  4719. //
  4720. if ((!NT_SUCCESS(SecondaryStatus)) && NT_SUCCESS(Status)) {
  4721. Status = SecondaryStatus;
  4722. }
  4723. goto LookupNamesInPrimaryDomainFinish;
  4724. }
  4725. NTSTATUS
  4726. LsapDbLookupNamesInTrustedForests(
  4727. IN ULONG LookupOptions,
  4728. IN ULONG Count,
  4729. IN PLSAPR_UNICODE_STRING Names,
  4730. IN PLSAPR_UNICODE_STRING PrefixNames,
  4731. IN PLSAPR_UNICODE_STRING SuffixNames,
  4732. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  4733. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  4734. IN OUT PULONG MappedCount,
  4735. IN OUT PULONG CompletelyUnmappedCount,
  4736. OUT NTSTATUS *NonFatalStatus
  4737. )
  4738. /*++
  4739. Routine Description:
  4740. This routine looks at the list of name that have yet to be resolved.
  4741. If the any of the names are marked as belowing to outside of the
  4742. current forest, package up these entries and sent off to the root via
  4743. the trust chain.
  4744. N.B. Isolated names not are resolved at this point.
  4745. N.B. This routine must be called after the names have been resolved
  4746. at a GC, since it is this call to the GC that marks the names as
  4747. exisiting outside of the local forest.
  4748. Arguments:
  4749. LookupOptions - LSA_LOOKUP_ISOLATED_AS_LOCAL
  4750. Count - Number of Names in the Names array, Note that some of these
  4751. may already have been mapped elsewhere, as specified by the
  4752. MappedCount parameter.
  4753. Names - Pointer to array of Names to be translated. Zero or all of the
  4754. Names may already have been translated elsewhere. If any of the
  4755. Names have been translated, the TranslatedSids parameter will point
  4756. to a location containing a non-NULL array of Sid translation
  4757. structures corresponding to the Names. If the nth Name has been
  4758. translated, the nth Sid translation structure will contain either a
  4759. non-NULL Sid or a non-negative offset into the Referenced Domain
  4760. List. If the nth Name has not yet been translated, the nth Sid
  4761. translation structure will contain a zero-length Sid string and a
  4762. negative value for the Referenced Domain List index.
  4763. PrefixNames - Pointer to an array of Count Unicode String structures
  4764. containing the Prefix portions of the Names. Names having no
  4765. Prefix are called Isolated Names. For these, the Unicode String
  4766. structure is set to contain a zero Length.
  4767. SuffixNames - Pointer to an array of Count Unicode String structures
  4768. containing the Suffix portions of the Names.
  4769. ReferencedDomains - Pointer to a Referenced Domain List. This
  4770. list references an array of zero or more Trust Information
  4771. entries describing each of the domains referenced by the names.
  4772. This array will be appended to/reallocated if necessary.
  4773. TranslatedSids - Pointer to structure that optionally references a list
  4774. of Sid translations for some of the Names in the Names array.
  4775. MappedCount - Pointer to location containing the number of Names
  4776. in the Names array that have already been mapped. This number
  4777. will be updated to reflect additional mapping done by this
  4778. routine.
  4779. CompletelyUnmappedCount - Pointer to location containing the
  4780. count of completely unmapped Names. A Name is completely unmapped
  4781. if it is unknown and non-composite, or composite but with an
  4782. unrecognized Domain component. This count is updated on exit, the
  4783. number of completely unmapped Namess whose Domain Prefices are
  4784. identified by this routine being subtracted from the input value.
  4785. NonFatalStatus - a status to indicate reasons why no names could have been
  4786. resolved
  4787. Return Values:
  4788. NTSTATUS - Standard Nt Result Code
  4789. STATUS_SUCCESS - The call completed successfully. Note that some
  4790. or all of the Names may remain partially or completely unmapped.
  4791. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  4792. such as memory, to complete the call.
  4793. --*/
  4794. {
  4795. NTSTATUS Status = STATUS_SUCCESS;
  4796. NTSTATUS NextLevelSecondaryStatus = STATUS_SUCCESS;
  4797. ULONG NextLevelCount;
  4798. ULONG NextLevelMappedCount;
  4799. ULONG NameIndex;
  4800. ULONG NextLevelNameIndex;
  4801. PLSAPR_REFERENCED_DOMAIN_LIST NextLevelReferencedDomains = NULL;
  4802. PLSAPR_REFERENCED_DOMAIN_LIST OutputReferencedDomains = NULL;
  4803. PLSAPR_TRANSLATED_SID_EX2 NextLevelSids = NULL;
  4804. LSAPR_TRANSLATED_SIDS_EX2 NextLevelSidsStruct;
  4805. PLSAPR_UNICODE_STRING NextLevelNames = NULL;
  4806. LONG FirstEntryIndex;
  4807. PULONG NameIndices = NULL;
  4808. PLSAPR_UNICODE_STRING NextLevelPrefixNames = NULL;
  4809. PLSAPR_UNICODE_STRING NextLevelSuffixNames = NULL;
  4810. BOOLEAN fAllocateAllNodes = FALSE;
  4811. *NonFatalStatus = STATUS_SUCCESS;
  4812. //
  4813. // Get a count of how many names need to be passed on
  4814. //
  4815. NextLevelCount = 0;
  4816. ASSERT(Count == TranslatedSids->Entries);
  4817. for (NameIndex = 0; NameIndex < Count; NameIndex++) {
  4818. if ( (LookupOptions & LSA_LOOKUP_ISOLATED_AS_LOCAL)
  4819. && (PrefixNames[NameIndex].Length == 0) ) {
  4820. //
  4821. // Don't lookup isolated names off machine
  4822. //
  4823. continue;
  4824. }
  4825. if (TranslatedSids->Sids[NameIndex].Flags & LSA_LOOKUP_NAME_XFOREST_REF) {
  4826. NextLevelCount++;
  4827. }
  4828. }
  4829. if (0 == NextLevelCount) {
  4830. //
  4831. // There is nothing to resolve
  4832. //
  4833. goto LookupNamesInTrustedForestsFinish;
  4834. }
  4835. //
  4836. // Allocate an array to hold the indices of unmapped Names
  4837. // relative to the original Names and TranslatedSids->Sids
  4838. // arrays.
  4839. //
  4840. NameIndices = MIDL_user_allocate(NextLevelCount * sizeof(ULONG));
  4841. if (NameIndices == NULL) {
  4842. Status = STATUS_INSUFFICIENT_RESOURCES;
  4843. goto LookupNamesInTrustedForestsError;
  4844. }
  4845. //
  4846. // Allocate an array of UNICODE_STRING structures for the
  4847. // names to be looked up at the Domain Controller.
  4848. //
  4849. NextLevelNames = MIDL_user_allocate(
  4850. sizeof(UNICODE_STRING) * NextLevelCount
  4851. );
  4852. if (NextLevelNames == NULL) {
  4853. Status = STATUS_INSUFFICIENT_RESOURCES;
  4854. goto LookupNamesInTrustedForestsError;
  4855. }
  4856. NextLevelPrefixNames = MIDL_user_allocate( NextLevelCount * sizeof( UNICODE_STRING ));
  4857. if (NextLevelPrefixNames == NULL) {
  4858. Status = STATUS_INSUFFICIENT_RESOURCES;
  4859. goto LookupNamesInTrustedForestsError;
  4860. }
  4861. NextLevelSuffixNames = MIDL_user_allocate( NextLevelCount * sizeof( UNICODE_STRING ));
  4862. if (NextLevelSuffixNames == NULL) {
  4863. Status = STATUS_INSUFFICIENT_RESOURCES;
  4864. goto LookupNamesInTrustedForestsError;
  4865. }
  4866. //
  4867. // Now scan the original array of Names and its parallel
  4868. // Translated Sids array. Copy over any names that need to be resolved
  4869. // in an ex-forest.
  4870. //
  4871. NextLevelNameIndex = (ULONG) 0;
  4872. for (NameIndex = 0;
  4873. NameIndex < Count && NextLevelNameIndex < NextLevelCount;
  4874. NameIndex++) {
  4875. if ( (LookupOptions & LSA_LOOKUP_ISOLATED_AS_LOCAL)
  4876. && (PrefixNames[NameIndex].Length == 0) ) {
  4877. //
  4878. // Don't lookup isolated names off machine
  4879. //
  4880. continue;
  4881. }
  4882. if (TranslatedSids->Sids[NameIndex].Flags & LSA_LOOKUP_NAME_XFOREST_REF) {
  4883. NextLevelNames[NextLevelNameIndex] = Names[NameIndex];
  4884. NextLevelPrefixNames[NextLevelNameIndex] = PrefixNames[NameIndex];
  4885. NextLevelSuffixNames[NextLevelNameIndex] = SuffixNames[NameIndex];
  4886. NameIndices[NextLevelNameIndex] = NameIndex;
  4887. NextLevelNameIndex++;
  4888. }
  4889. }
  4890. NextLevelMappedCount = (ULONG) 0;
  4891. NextLevelSidsStruct.Entries = 0;
  4892. NextLevelSidsStruct.Sids = NULL;
  4893. Status = LsapDbLookupNamesInTrustedForestsWorker(NextLevelCount,
  4894. NextLevelNames,
  4895. NextLevelPrefixNames,
  4896. NextLevelSuffixNames,
  4897. &NextLevelReferencedDomains,
  4898. &NextLevelSidsStruct,
  4899. &fAllocateAllNodes,
  4900. &NextLevelMappedCount,
  4901. 0, // no options,
  4902. &NextLevelSecondaryStatus);
  4903. if (NextLevelSidsStruct.Sids) {
  4904. NextLevelSids = NextLevelSidsStruct.Sids;
  4905. NextLevelSidsStruct.Sids = NULL;
  4906. NextLevelSidsStruct.Entries = 0;
  4907. }
  4908. if (!NT_SUCCESS(Status)
  4909. && LsapDbIsStatusConnectionFailure(Status)) {
  4910. *NonFatalStatus = Status;
  4911. Status = STATUS_SUCCESS;
  4912. goto LookupNamesInTrustedForestsFinish;
  4913. } else if (NT_SUCCESS(Status)
  4914. && !NT_SUCCESS(NextLevelSecondaryStatus)) {
  4915. *NonFatalStatus = NextLevelSecondaryStatus;
  4916. goto LookupNamesInTrustedForestsFinish;
  4917. } else if (!NT_SUCCESS(Status)
  4918. && Status != STATUS_NONE_MAPPED) {
  4919. //
  4920. // Unhandled error; STATUS_NONE_MAPPED is handled to get
  4921. // partially resolved names.
  4922. //
  4923. goto LookupNamesInTrustedForestsError;
  4924. }
  4925. ASSERT(NT_SUCCESS(Status) || Status == STATUS_NONE_MAPPED);
  4926. Status = STATUS_SUCCESS;
  4927. //
  4928. // Merge the results back in
  4929. //
  4930. Status = LsapDbLookupMergeDisjointReferencedDomains(
  4931. ReferencedDomains,
  4932. NextLevelReferencedDomains,
  4933. &OutputReferencedDomains,
  4934. LSAP_DB_USE_FIRST_MERGAND_GRAPH
  4935. );
  4936. if (!NT_SUCCESS(Status)) {
  4937. goto LookupNamesInTrustedForestsError;
  4938. }
  4939. FirstEntryIndex = ReferencedDomains->Entries;
  4940. //
  4941. // Now update the original list of Translated Names. We
  4942. // update each entry that has newly been translated by copying
  4943. // the entry from the new list and adjusting its
  4944. // Referenced Domain List Index upwards by adding the index
  4945. // of the first entry in the Next level List.
  4946. //
  4947. for( NextLevelNameIndex = 0;
  4948. NextLevelNameIndex < NextLevelCount;
  4949. NextLevelNameIndex++ ) {
  4950. if ( !LsapDbCompletelyUnmappedSid(&NextLevelSids[NextLevelNameIndex]) ) {
  4951. NameIndex = NameIndices[NextLevelNameIndex];
  4952. TranslatedSids->Sids[NameIndex]
  4953. = NextLevelSids[NextLevelNameIndex];
  4954. Status = LsapRpcCopySid(NULL,
  4955. &TranslatedSids->Sids[NameIndex].Sid,
  4956. NextLevelSids[NextLevelNameIndex].Sid);
  4957. if (!NT_SUCCESS(Status)) {
  4958. goto LookupNamesInTrustedForestsError;
  4959. }
  4960. TranslatedSids->Sids[NameIndex].DomainIndex =
  4961. FirstEntryIndex +
  4962. NextLevelSids[NextLevelNameIndex].DomainIndex;
  4963. (*CompletelyUnmappedCount)--;
  4964. }
  4965. }
  4966. //
  4967. // Update the Referenced Domain List if a new one was produced
  4968. // from the merge. We retain the original top-level structure.
  4969. //
  4970. if (OutputReferencedDomains != NULL) {
  4971. if (ReferencedDomains->Domains != NULL) {
  4972. MIDL_user_free( ReferencedDomains->Domains );
  4973. ReferencedDomains->Domains = NULL;
  4974. }
  4975. *ReferencedDomains = *OutputReferencedDomains;
  4976. MIDL_user_free( OutputReferencedDomains );
  4977. OutputReferencedDomains = NULL;
  4978. }
  4979. //
  4980. // Update the Mapped Count
  4981. //
  4982. *MappedCount += NextLevelMappedCount;
  4983. //
  4984. // Any error status that has not been suppressed must be reported
  4985. // to the caller. Errors such as connection failures to other LSA's
  4986. // are suppressed.
  4987. //
  4988. if (!NT_SUCCESS(Status)) {
  4989. goto LookupNamesInTrustedForestsError;
  4990. }
  4991. LookupNamesInTrustedForestsFinish:
  4992. //
  4993. // If necessary, update count of completely unmapped names.
  4994. //
  4995. if (*CompletelyUnmappedCount > (ULONG) 0) {
  4996. LsapDbUpdateCountCompUnmappedNames(TranslatedSids, CompletelyUnmappedCount);
  4997. }
  4998. //
  4999. // If necessary, free the Next Level Referenced Domain List.
  5000. // Note the structure is not allocate_all_nodes
  5001. //
  5002. if (NextLevelReferencedDomains != NULL) {
  5003. if (!fAllocateAllNodes) {
  5004. if (NextLevelReferencedDomains->Domains) {
  5005. for (NextLevelNameIndex = 0;
  5006. NextLevelNameIndex < NextLevelReferencedDomains->Entries;
  5007. NextLevelNameIndex++) {
  5008. if (NextLevelReferencedDomains->Domains[NextLevelNameIndex].Name.Buffer) {
  5009. MIDL_user_free(NextLevelReferencedDomains->Domains[NextLevelNameIndex].Name.Buffer);
  5010. }
  5011. if (NextLevelReferencedDomains->Domains[NextLevelNameIndex].Sid) {
  5012. MIDL_user_free(NextLevelReferencedDomains->Domains[NextLevelNameIndex].Sid);
  5013. }
  5014. }
  5015. MIDL_user_free(NextLevelReferencedDomains->Domains);
  5016. }
  5017. }
  5018. MIDL_user_free( NextLevelReferencedDomains );
  5019. NextLevelReferencedDomains = NULL;
  5020. }
  5021. //
  5022. // If necessary, free the Next Level Names array. We only free the
  5023. // top level, since the names therein were copied from the input
  5024. // TranslatedNames->Names array.
  5025. //
  5026. if (NextLevelNames != NULL) {
  5027. MIDL_user_free( NextLevelNames );
  5028. NextLevelNames = NULL;
  5029. }
  5030. //
  5031. // If necessary, free the Next Level Translated Sids array. Note
  5032. // the structure is not allocate_all_nodes
  5033. //
  5034. if (NextLevelSids != NULL) {
  5035. if (!fAllocateAllNodes) {
  5036. for (NextLevelNameIndex = 0;
  5037. NextLevelNameIndex < NextLevelCount;
  5038. NextLevelNameIndex++) {
  5039. if (NextLevelSids[NextLevelNameIndex].Sid) {
  5040. MIDL_user_free(NextLevelSids[NextLevelNameIndex].Sid);
  5041. }
  5042. }
  5043. }
  5044. MIDL_user_free( NextLevelSids );
  5045. NextLevelSids = NULL;
  5046. }
  5047. if (NextLevelPrefixNames != NULL) {
  5048. MIDL_user_free( NextLevelPrefixNames );
  5049. NextLevelSids = NULL;
  5050. }
  5051. if (NextLevelSuffixNames != NULL) {
  5052. MIDL_user_free( NextLevelSuffixNames );
  5053. NextLevelSids = NULL;
  5054. }
  5055. //
  5056. // If necessary, free the array that maps Name Indices from the
  5057. // Next Level to the Current Level.
  5058. //
  5059. if (NameIndices != NULL) {
  5060. MIDL_user_free( NameIndices );
  5061. NameIndices = NULL;
  5062. }
  5063. return(Status);
  5064. LookupNamesInTrustedForestsError:
  5065. goto LookupNamesInTrustedForestsFinish;
  5066. }
  5067. NTSTATUS
  5068. LsapDbLookupNamesInTrustedForestsWorker(
  5069. IN ULONG Count,
  5070. IN PLSAPR_UNICODE_STRING Names,
  5071. IN PLSAPR_UNICODE_STRING PrefixNames,
  5072. IN PLSAPR_UNICODE_STRING SuffixNames,
  5073. OUT PLSAPR_REFERENCED_DOMAIN_LIST *ReferencedDomains,
  5074. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  5075. OUT BOOLEAN * fAllocateAllNodes,
  5076. IN OUT PULONG MappedCount,
  5077. IN ULONG LookupOptions,
  5078. OUT NTSTATUS *NonFatalStatus
  5079. )
  5080. /*++
  5081. Routine Description:
  5082. This routine takes a set of names that are to be resolved at an
  5083. external forest and either 1) sends of to the external forest if
  5084. this is the root of a domain or 2) sends to request of to a DC
  5085. in the root of domain (via the trust path).
  5086. N.B. This routine is called from the LsarLookupName request of levels
  5087. LsapLookupXForestReferral and LsaLookupPDC.
  5088. N.B. Both ReferencedDomains and TranslatedSids.Sids are allocated
  5089. on output.
  5090. Arguments:
  5091. Count - Number of Names in the Names array, Note that some of these
  5092. may already have been mapped elsewhere, as specified by the
  5093. MappedCount parameter.
  5094. Names - Pointer to array of Names to be translated. Zero or all of the
  5095. Names may already have been translated elsewhere. If any of the
  5096. Names have been translated, the TranslatedSids parameter will point
  5097. to a location containing a non-NULL array of Sid translation
  5098. structures corresponding to the Names. If the nth Name has been
  5099. translated, the nth Sid translation structure will contain either a
  5100. non-NULL Sid or a non-negative offset into the Referenced Domain
  5101. List. If the nth Name has not yet been translated, the nth Sid
  5102. translation structure will contain a zero-length Sid string and a
  5103. negative value for the Referenced Domain List index.
  5104. ReferencedDomains - Pointer to a Referenced Domain List. This
  5105. list references an array of zero or more Trust Information
  5106. entries describing each of the domains referenced by the names.
  5107. This array will be appended to/reallocated if necessary.
  5108. TranslatedSids - Pointer to structure that optionally references a list
  5109. of Sid translations for some of the Names in the Names array.
  5110. fAllocateAllNodes -- describes how ReferencedDomains and TranslatesSids are
  5111. allocated.
  5112. MappedCount - Pointer to location containing the number of Names
  5113. in the Names array that have already been mapped. This number
  5114. will be updated to reflect additional mapping done by this
  5115. routine.
  5116. CompletelyUnmappedCount - Pointer to location containing the
  5117. count of completely unmapped Names. A Name is completely unmapped
  5118. if it is unknown and non-composite, or composite but with an
  5119. unrecognized Domain component. This count is updated on exit, the
  5120. number of completely unmapped Namess whose Domain Prefices are
  5121. identified by this routine being subtracted from the input value.
  5122. NonFatalStatus - a status to indicate reasons why no names could have been
  5123. resolved
  5124. Return Values:
  5125. NTSTATUS - Standard Nt Result Code
  5126. STATUS_SUCCESS - The call completed successfully. Note that some
  5127. or all of the Names may remain partially or completely unmapped.
  5128. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
  5129. such as memory, to complete the call.
  5130. --*/
  5131. {
  5132. NTSTATUS Status = STATUS_SUCCESS;
  5133. LSAP_LOOKUP_LEVEL LookupLevel;
  5134. ULONG i;
  5135. PLSAP_DB_LOOKUP_WORK_LIST WorkList = NULL;
  5136. *NonFatalStatus = STATUS_SUCCESS;
  5137. *fAllocateAllNodes = FALSE;
  5138. if (!LsapDbDcInRootDomain()) {
  5139. //
  5140. // We are not at the root domain -- forward request
  5141. //
  5142. PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
  5143. LSAPR_TRUST_INFORMATION_EX TrustInfoEx;
  5144. //
  5145. // Get our forest name
  5146. //
  5147. Status = LsapDbLookupGetDomainInfo(NULL,
  5148. &DnsDomainInfo);
  5149. if (!NT_SUCCESS(Status)) {
  5150. goto LookupNamesInTrustedForestFinish;
  5151. }
  5152. RtlZeroMemory(&TrustInfoEx, sizeof(TrustInfoEx));
  5153. TrustInfoEx.DomainName = *((LSAPR_UNICODE_STRING*)&DnsDomainInfo->DnsForestName);
  5154. Status = LsapDbLookupNameChainRequest(&TrustInfoEx,
  5155. Count,
  5156. (PUNICODE_STRING)Names,
  5157. (PLSA_REFERENCED_DOMAIN_LIST *)ReferencedDomains,
  5158. (PLSA_TRANSLATED_SID_EX2 * )&TranslatedSids->Sids,
  5159. LsapLookupXForestReferral,
  5160. MappedCount,
  5161. NULL);
  5162. if (TranslatedSids->Sids) {
  5163. TranslatedSids->Entries = Count;
  5164. *fAllocateAllNodes = TRUE;
  5165. }
  5166. if (!NT_SUCCESS(Status)) {
  5167. //
  5168. // The attempt to chain failed; record the error
  5169. // if it is interesting
  5170. //
  5171. if (LsapDbIsStatusConnectionFailure(Status)) {
  5172. *NonFatalStatus = Status;
  5173. }
  5174. //
  5175. // This should not fail the overall request
  5176. //
  5177. Status = STATUS_SUCCESS;
  5178. }
  5179. } else {
  5180. //
  5181. // Split the names up into different forests and issue a work
  5182. // request for each one
  5183. //
  5184. ULONG i;
  5185. ULONG CompletelyUnmappedCount = Count;
  5186. TranslatedSids->Sids = MIDL_user_allocate(Count * sizeof(LSA_TRANSLATED_SID_EX2));
  5187. if (TranslatedSids->Sids == NULL) {
  5188. Status = STATUS_INSUFFICIENT_RESOURCES;
  5189. goto LookupNamesInTrustedForestFinish;
  5190. }
  5191. TranslatedSids->Entries = Count;
  5192. //
  5193. // Initialize the Output Sids array. Zeroise all fields, then
  5194. // Mark all of the Output Sids as being unknown initially and
  5195. // set the DomainIndex fields to a negative number meaning
  5196. // "no domain"
  5197. //
  5198. RtlZeroMemory( TranslatedSids->Sids, Count * sizeof(LSA_TRANSLATED_SID_EX2));
  5199. for (i = 0; i < Count; i++) {
  5200. TranslatedSids->Sids[i].Use = SidTypeUnknown;
  5201. TranslatedSids->Sids[i].DomainIndex = LSA_UNKNOWN_INDEX;
  5202. }
  5203. //
  5204. // Create an empty Referenced Domain List.
  5205. //
  5206. Status = LsapDbLookupCreateListReferencedDomains( ReferencedDomains, 0 );
  5207. if (!NT_SUCCESS(Status)) {
  5208. goto LookupNamesInTrustedForestFinish;
  5209. }
  5210. //
  5211. // Build a WorkList for this Lookup and put it on the Work Queue.
  5212. //
  5213. // NOTE: This routine does not need to hold the Lookup Work Queue
  5214. // lock to ensure validity of the WorkList pointer, because the
  5215. // pointer remains valid until this routine frees it via
  5216. // LsapDbLookupDeleteWorkList(). Although other threads may
  5217. // process the WorkList, do not delete it.
  5218. //
  5219. // A called routine must acquire the lock in order to access
  5220. // the WorkList after it has been added to the Work Queue.
  5221. //
  5222. Status = LsapDbLookupXForestNamesBuildWorkList(
  5223. Count,
  5224. Names,
  5225. PrefixNames,
  5226. SuffixNames,
  5227. *ReferencedDomains,
  5228. TranslatedSids,
  5229. LsapLookupXForestResolve,
  5230. MappedCount,
  5231. &CompletelyUnmappedCount,
  5232. &WorkList
  5233. );
  5234. if (!NT_SUCCESS(Status)) {
  5235. //
  5236. // If no Work List has been built because there are no
  5237. // eligible domains to search, exit, suppressing the error.
  5238. if (Status == STATUS_NONE_MAPPED) {
  5239. Status = STATUS_SUCCESS;
  5240. goto LookupNamesInTrustedForestFinish;
  5241. }
  5242. goto LookupNamesInTrustedForestFinish;
  5243. }
  5244. //
  5245. // Start the work, by dispatching one or more worker threads
  5246. // if necessary.
  5247. //
  5248. Status = LsapDbLookupDispatchWorkerThreads( WorkList );
  5249. if (!NT_SUCCESS(Status)) {
  5250. goto LookupNamesInTrustedForestFinish;
  5251. }
  5252. //
  5253. // Wait for completion/termination of all items on the Work List.
  5254. //
  5255. Status = LsapDbLookupAwaitCompletionWorkList( WorkList );
  5256. if (!NT_SUCCESS(Status)) {
  5257. goto LookupNamesInTrustedForestFinish;
  5258. }
  5259. if ( !NT_SUCCESS(WorkList->NonFatalStatus) ) {
  5260. //
  5261. // Propogate the error as non fatal
  5262. //
  5263. *NonFatalStatus = WorkList->NonFatalStatus;
  5264. }
  5265. }
  5266. LookupNamesInTrustedForestFinish:
  5267. //
  5268. // If a Work List was created, delete it from the Work Queue
  5269. //
  5270. if (WorkList != NULL) {
  5271. Status = LsapDbLookupDeleteWorkList( WorkList );
  5272. WorkList = NULL;
  5273. }
  5274. return Status;
  5275. }
  5276. NTSTATUS
  5277. LsapDbLookupNamesAsDomainNames(
  5278. IN ULONG Flags,
  5279. IN ULONG Count,
  5280. IN PLSAPR_UNICODE_STRING Names,
  5281. IN PLSAPR_UNICODE_STRING PrefixNames,
  5282. IN PLSAPR_UNICODE_STRING SuffixNames,
  5283. IN OUT PLSAPR_REFERENCED_DOMAIN_LIST ReferencedDomains,
  5284. IN OUT PLSAPR_TRANSLATED_SIDS_EX2 TranslatedSids,
  5285. IN OUT PULONG MappedCount
  5286. )
  5287. /*++
  5288. Routine Description:
  5289. This routine tries to match entries in Names to domain names of
  5290. trusted domains.
  5291. There are three kinds of trusted domains:
  5292. 1) domains we directly trusts (both in and out of forest). The LSA TDL
  5293. is used for this.
  5294. 2) domains we trust transitively. The DS cross-ref is used for this.
  5295. 3) domains we trust via a forest trust. The LSA TDL is used
  5296. for this.
  5297. Arguments:
  5298. Flags -- LSAP_LOOKUP_TRUSTED_DOMAIN_DIRECT
  5299. LSAP_LOOKUP_TRUSTED_DOMAIN_TRANSITIVE
  5300. LSAP_LOOKUP_TRUSTED_DOMAIN_FOREST_NAMES
  5301. Count -- the number of entries in Names
  5302. Names/PrefixNames/SuffixName -- the requested Names
  5303. ReferencedDomains -- the domains of Names
  5304. TranslatedSids -- the SIDs and characteristics of Names
  5305. MappedCount -- the number of names that have been fully mapped
  5306. Return Values:
  5307. STATUS_SUCCESS, or resource error otherwise
  5308. --*/
  5309. {
  5310. NTSTATUS Status = STATUS_SUCCESS;
  5311. ULONG NameIndex;
  5312. BOOLEAN fTDLLock = FALSE;
  5313. LSA_TRUST_INFORMATION TrustInfo;
  5314. RtlZeroMemory(&TrustInfo, sizeof(TrustInfo));
  5315. for (NameIndex = 0; NameIndex < Count; NameIndex++) {
  5316. PLSAPR_TRUST_INFORMATION_EX TrustInfoEx = NULL;
  5317. LSAPR_TRUST_INFORMATION_EX TrustInfoBuffer;
  5318. PLSAP_DB_TRUSTED_DOMAIN_LIST_ENTRY TrustEntry = NULL;
  5319. RtlZeroMemory(&TrustInfo, sizeof(TrustInfo));
  5320. RtlZeroMemory(&TrustInfoBuffer, sizeof(TrustInfoBuffer));
  5321. if (!LsapDbCompletelyUnmappedSid(&TranslatedSids->Sids[NameIndex])) {
  5322. // Already resolved
  5323. continue;
  5324. }
  5325. if (PrefixNames[NameIndex].Length != 0) {
  5326. // Not in isolated name, so can't be just a domain name
  5327. continue;
  5328. }
  5329. if (Flags & LSAP_LOOKUP_TRUSTED_DOMAIN_TRANSITIVE) {
  5330. Status = LsapDomainHasTransitiveTrust((PUNICODE_STRING)&SuffixNames[NameIndex],
  5331. NULL,
  5332. &TrustInfo);
  5333. if (NT_SUCCESS(Status)) {
  5334. TrustInfoEx = &TrustInfoBuffer;
  5335. TrustInfoEx->FlatName = *(LSAPR_UNICODE_STRING*)&TrustInfo.Name;
  5336. TrustInfoEx->Sid = TrustInfo.Sid;
  5337. } else if (Status == STATUS_NO_SUCH_DOMAIN) {
  5338. Status = STATUS_SUCCESS;
  5339. } else {
  5340. // This is fatal
  5341. goto Exit;
  5342. }
  5343. }
  5344. if ((NULL == TrustInfoEx)
  5345. && (Flags & LSAP_LOOKUP_TRUSTED_DOMAIN_DIRECT)) {
  5346. Status = LsapDomainHasDirectTrust((PUNICODE_STRING)&SuffixNames[NameIndex],
  5347. NULL,
  5348. &fTDLLock,
  5349. &TrustEntry);
  5350. if (NT_SUCCESS(Status)) {
  5351. TrustInfoEx = &TrustInfoBuffer;
  5352. TrustInfoEx->FlatName = TrustEntry->TrustInfoEx.FlatName;
  5353. TrustInfoEx->Sid = TrustEntry->TrustInfoEx.Sid;
  5354. } else if (Status == STATUS_NO_SUCH_DOMAIN) {
  5355. Status = STATUS_SUCCESS;
  5356. } else {
  5357. // This is fatal
  5358. goto Exit;
  5359. }
  5360. }
  5361. if ((NULL == TrustInfoEx)
  5362. && (Flags & LSAP_LOOKUP_TRUSTED_FOREST_ROOT) ) {
  5363. Status = LsapDomainHasForestTrust((PUNICODE_STRING)&SuffixNames[NameIndex],
  5364. NULL,
  5365. &fTDLLock,
  5366. &TrustEntry);
  5367. if (NT_SUCCESS(Status)) {
  5368. TrustInfoEx = &TrustInfoBuffer;
  5369. TrustInfoEx->FlatName = TrustEntry->TrustInfoEx.FlatName;
  5370. TrustInfoEx->Sid = TrustEntry->TrustInfoEx.Sid;
  5371. } else if (Status == STATUS_NO_SUCH_DOMAIN) {
  5372. Status = STATUS_SUCCESS;
  5373. } else {
  5374. // This is fatal
  5375. goto Exit;
  5376. }
  5377. }
  5378. if (TrustInfoEx) {
  5379. BOOLEAN fStatus;
  5380. ULONG DomainIndex;
  5381. fStatus = LsapDbLookupListReferencedDomains( ReferencedDomains,
  5382. TrustInfoEx->Sid,
  5383. &DomainIndex );
  5384. if ( FALSE == fStatus ) {
  5385. LSA_TRUST_INFORMATION TempTrustInfo;
  5386. //
  5387. // No entry for this domain -- add it
  5388. //
  5389. RtlZeroMemory(&TempTrustInfo, sizeof(TempTrustInfo));
  5390. // Set the sid
  5391. TempTrustInfo.Sid = TrustInfoEx->Sid;
  5392. TempTrustInfo.Name = *(PUNICODE_STRING)&TrustInfoEx->FlatName;
  5393. //
  5394. // Add the entry
  5395. //
  5396. Status = LsapDbLookupAddListReferencedDomains( ReferencedDomains,
  5397. (PLSAPR_TRUST_INFORMATION) &TempTrustInfo,
  5398. &DomainIndex );
  5399. if ( !NT_SUCCESS( Status ) ) {
  5400. goto Exit;
  5401. }
  5402. }
  5403. // We should now have a domain index
  5404. ASSERT( LSA_UNKNOWN_INDEX != DomainIndex );
  5405. // Set the information in the returned array
  5406. TranslatedSids->Sids[NameIndex].Use = SidTypeDomain;
  5407. TranslatedSids->Sids[NameIndex].DomainIndex = DomainIndex;
  5408. Status = LsapRpcCopySid(NULL,
  5409. &TranslatedSids->Sids[NameIndex].Sid,
  5410. TrustInfoEx->Sid);
  5411. if ( !NT_SUCCESS( Status ) ) {
  5412. goto Exit;
  5413. }
  5414. //
  5415. // Increment the number of items mapped
  5416. //
  5417. (*MappedCount) += 1;
  5418. }
  5419. if (fTDLLock) {
  5420. LsapDbReleaseLockTrustedDomainList();
  5421. fTDLLock = FALSE;
  5422. }
  5423. if (TrustInfo.Name.Buffer) {
  5424. midl_user_free(TrustInfo.Name.Buffer);
  5425. TrustInfo.Name.Buffer = NULL;
  5426. }
  5427. if (TrustInfo.Sid) {
  5428. midl_user_free(TrustInfo.Sid);
  5429. TrustInfo.Sid = NULL;
  5430. }
  5431. if (!NT_SUCCESS(Status)) {
  5432. goto Exit;
  5433. }
  5434. }
  5435. Exit:
  5436. if (fTDLLock) {
  5437. LsapDbReleaseLockTrustedDomainList();
  5438. fTDLLock = FALSE;
  5439. }
  5440. if (TrustInfo.Name.Buffer) {
  5441. midl_user_free(TrustInfo.Name.Buffer);
  5442. TrustInfo.Name.Buffer = NULL;
  5443. }
  5444. if (TrustInfo.Sid) {
  5445. midl_user_free(TrustInfo.Sid);
  5446. TrustInfo.Sid = NULL;
  5447. }
  5448. return Status;
  5449. }