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.

2251 lines
63 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. netlogon.c
  5. Abstract:
  6. Netlogon routines to access the DS.
  7. Rightfully these routines belong in netlogon. However, the current
  8. interface to the DS is complex enough that the support routines
  9. are substantial. Those routines are already duplicated in SAM and LSA.
  10. Rather than introduce a new set, this module exports exactly what is
  11. needed by Netlogon.
  12. Author:
  13. Cliff Van Dyke (CliffV) May 7, 1997
  14. Environment:
  15. User Mode
  16. Revision History:
  17. --*/
  18. #include <lsapch2.h>
  19. #include <dbp.h>
  20. // #include <ntdsa.h>
  21. #include <windns.h>
  22. BOOLEAN
  23. DsIsBeingBackSynced();
  24. NTSTATUS
  25. LsapDsReadSubnetObj(
  26. IN PDSNAME SubnetObjName,
  27. OUT PBOOL SubnetValid,
  28. OUT PLSAP_SUBNET_INFO_ENTRY SubnetInfoEntry
  29. )
  30. /*++
  31. Routine Description:
  32. This function will read the specified subnet object and fill in the entry.
  33. Arguments:
  34. SubnetObjName - DsName of the subnet object
  35. SubnetValid - On success, returns TRUE if the subnet object has been
  36. read successfully and has been determined to be valid. Otherwise,
  37. returns FALSE. A subnet object may be invalid if it was created
  38. as a result of a subnet name collision in the DS or if the
  39. associated site name object was created as a result of a site
  40. name collision in the DS.
  41. SubnetInfoEntry - On success, if the subnet has been determined
  42. to be valid as indicated by the SubnetValid parameter, returns
  43. the Subnet Information.
  44. Returns:
  45. STATUS_SUCCESS - Success
  46. STATUS_INVALID_PARAMETER - A bad InformationClass level was encountered
  47. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  48. --*/
  49. {
  50. NTSTATUS Status = STATUS_SUCCESS;
  51. ULONG i;
  52. PDSNAME DsName;
  53. UNICODE_STRING SubnetName = {0};
  54. UNICODE_STRING SiteName = {0};
  55. LPWSTR SiteNameString = NULL;
  56. BOOL LocalSubnetValid = TRUE; // used only on success
  57. //
  58. // Build the list of attribute IDs we need based on the information
  59. // class
  60. //
  61. ATTR SubnetAttrVals[] = {
  62. {ATT_SITE_OBJECT, {0, NULL} },
  63. };
  64. ATTRBLOCK ReadBlock, ReturnedBlock = { 0 };
  65. WCHAR RdnBuffer[MAX_RDN_SIZE + 1];
  66. ULONG RdnLen;
  67. ATTRTYP RdnType;
  68. LsapEnterFunc( "LsapDsReadSubnetObj" );
  69. //
  70. // The subnet name is the RDN of the subnet object itself.
  71. //
  72. // Return it to the caller.
  73. //
  74. Status = LsapDsMapDsReturnToStatus( GetRDNInfoExternal(
  75. SubnetObjName,
  76. RdnBuffer,
  77. &RdnLen,
  78. &RdnType ) );
  79. if ( !NT_SUCCESS(Status) ) {
  80. goto Cleanup;
  81. }
  82. //
  83. // If the subnet object DN is mangled as a result
  84. // of a subnet name collision in the DS, ignore this
  85. // subnet object
  86. //
  87. if ( IsMangledRDNExternal(RdnBuffer, RdnLen, NULL) ) {
  88. LocalSubnetValid = FALSE;
  89. Status = STATUS_SUCCESS;
  90. goto Cleanup;
  91. }
  92. LSAPDS_ALLOC_AND_COPY_STRING_TO_UNICODE_ON_SUCCESS(
  93. Status,
  94. &SubnetName,
  95. RdnBuffer,
  96. RdnLen*sizeof(WCHAR) );
  97. if ( !NT_SUCCESS(Status) ) {
  98. goto Cleanup;
  99. }
  100. //
  101. // Read the required attributes from the subnet object
  102. //
  103. ReadBlock.attrCount = sizeof(SubnetAttrVals) / sizeof(ATTR);
  104. ReadBlock.pAttr = SubnetAttrVals;
  105. Status = LsapDsReadByDsName( SubnetObjName,
  106. 0,
  107. &ReadBlock,
  108. &ReturnedBlock );
  109. //
  110. // Allow for the case where the SiteObject attribute doesn't exist.
  111. //
  112. if ( Status == STATUS_NOT_FOUND ) {
  113. LocalSubnetValid = TRUE;
  114. Status = STATUS_SUCCESS;
  115. goto Cleanup;
  116. }
  117. if ( !NT_SUCCESS(Status) ) {
  118. goto Cleanup;
  119. }
  120. //
  121. // Now, marshal the attribute. There should be
  122. // only one site object associated with a subnet.
  123. //
  124. if ( ReturnedBlock.attrCount > 0 ) {
  125. NET_API_STATUS NetStatus;
  126. //
  127. // Validate the data
  128. //
  129. if ( ReturnedBlock.pAttr[0].attrTyp != ATT_SITE_OBJECT ||
  130. ReturnedBlock.pAttr[0].AttrVal.valCount == 0 ) {
  131. Status = STATUS_INVALID_PARAMETER;
  132. goto Cleanup;
  133. }
  134. //
  135. // Get the first value (should be only one)
  136. //
  137. DsName = LSAP_DS_GET_DS_ATTRIBUTE_AS_DSNAME( &ReturnedBlock.pAttr[0] );
  138. //
  139. // Get the site name RDN from the site DN
  140. //
  141. Status = LsapDsMapDsReturnToStatus( GetRDNInfoExternal(
  142. DsName,
  143. RdnBuffer,
  144. &RdnLen,
  145. &RdnType ) );
  146. if ( !NT_SUCCESS(Status) ) {
  147. goto Cleanup;
  148. }
  149. //
  150. // If the site name is mangled as the result of a name
  151. // colision in the DS, ignore this site attribute.
  152. //
  153. if ( IsMangledRDNExternal(RdnBuffer, RdnLen, NULL) ) {
  154. LocalSubnetValid = FALSE;
  155. Status = STATUS_SUCCESS;
  156. goto Cleanup;
  157. }
  158. //
  159. // Verify that the site name can be
  160. // used as a label in a DNS name
  161. //
  162. SiteNameString = LsapAllocateLsaHeap( (RdnLen + 1) * sizeof(WCHAR) );
  163. if ( SiteNameString == NULL ) {
  164. Status = STATUS_INSUFFICIENT_RESOURCES;
  165. goto Cleanup;
  166. }
  167. RtlCopyMemory( SiteNameString, RdnBuffer, RdnLen*sizeof(WCHAR) );
  168. SiteNameString[RdnLen] = UNICODE_NULL;
  169. NetStatus = DnsValidateName_W( SiteNameString, DnsNameDomainLabel );
  170. //
  171. // If the name can't be used as a DNS label,
  172. // the subnet is invalid
  173. //
  174. if ( NetStatus != NO_ERROR && NetStatus != DNS_ERROR_NON_RFC_NAME ) {
  175. LocalSubnetValid = FALSE;
  176. Status = STATUS_SUCCESS;
  177. goto Cleanup;
  178. }
  179. //
  180. // OK, the site name is valid
  181. //
  182. LocalSubnetValid = TRUE;
  183. //
  184. // Get the site name
  185. //
  186. LSAPDS_ALLOC_AND_COPY_STRING_TO_UNICODE_ON_SUCCESS(
  187. Status,
  188. &SiteName,
  189. RdnBuffer,
  190. RdnLen*sizeof(WCHAR) );
  191. }
  192. Cleanup:
  193. //
  194. // On success, return the data
  195. //
  196. if ( NT_SUCCESS(Status) ) {
  197. *SubnetValid = LocalSubnetValid;
  198. }
  199. if ( NT_SUCCESS(Status) && LocalSubnetValid ) {
  200. SubnetInfoEntry->SubnetName = SubnetName;
  201. SubnetInfoEntry->SiteName = SiteName;
  202. } else {
  203. if ( SubnetName.Buffer != NULL ) {
  204. LsapFreeLsaHeap( SubnetName.Buffer );
  205. }
  206. if ( SiteName.Buffer != NULL ) {
  207. LsapFreeLsaHeap( SiteName.Buffer );
  208. }
  209. }
  210. if ( SiteNameString != NULL ) {
  211. LsapFreeLsaHeap( SiteNameString );
  212. }
  213. LsapExitFunc( "LsapDsReadSubnetObj", Status );
  214. return( Status );
  215. }
  216. NTSTATUS
  217. LsapDsReadSiteObj(
  218. IN PDSNAME SiteObjName,
  219. OUT PBOOL SiteValid,
  220. OUT PLSAP_SITE_INFO_ENTRY SiteInfoEntry
  221. )
  222. /*++
  223. Routine Description:
  224. This function will read the specified site object and fill in the entry.
  225. It will check that the site name is not mangled as a result of site
  226. name collision in the DS. It will also check that the site name can be
  227. used as a DNS label in a DNS name.
  228. Arguments:
  229. SiteObjName - DsName of the site object
  230. SiteValid - On success, returns TRUE if the site object has been
  231. read successfully and has been determined to be valid. Otherwise,
  232. returns FALSE. A site object may be invalid if it was created
  233. as a result of a site name collision in the DS.
  234. SitesInfoEntry - On success, if the site has been determined
  235. to be valid as indicated by the SiteValid parameter, returns
  236. the Site Information.
  237. Returns:
  238. STATUS_SUCCESS - Success
  239. STATUS_INVALID_PARAMETER - A bad InformationClass level was encountered
  240. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  241. --*/
  242. {
  243. NTSTATUS Status;
  244. WCHAR RdnBuffer[MAX_RDN_SIZE + 1];
  245. ULONG RdnLen;
  246. ATTRTYP RdnType;
  247. LsapEnterFunc( "LsapDsReadSiteObj" );
  248. //
  249. // The site name is the RDN of the site object itself.
  250. //
  251. // Return it to the caller.
  252. //
  253. Status = LsapDsMapDsReturnToStatus( GetRDNInfoExternal(
  254. SiteObjName,
  255. RdnBuffer,
  256. &RdnLen,
  257. &RdnType ) );
  258. if ( NT_SUCCESS( Status ) ) {
  259. //
  260. // Return this site only if it's not mangled
  261. // as the result of a name colision in the DS
  262. //
  263. if ( IsMangledRDNExternal(RdnBuffer, RdnLen, NULL) ) {
  264. *SiteValid = FALSE;
  265. } else {
  266. LPWSTR SiteNameString = NULL;
  267. //
  268. // Verify that the site name can be
  269. // used as a label in a DNS name
  270. //
  271. SiteNameString = LsapAllocateLsaHeap( (RdnLen + 1) * sizeof(WCHAR) );
  272. if ( SiteNameString == NULL ) {
  273. Status = STATUS_INSUFFICIENT_RESOURCES;
  274. } else {
  275. NET_API_STATUS NetStatus;
  276. RtlCopyMemory( SiteNameString, RdnBuffer, RdnLen*sizeof(WCHAR) );
  277. SiteNameString[RdnLen] = UNICODE_NULL;
  278. NetStatus = DnsValidateName_W( SiteNameString, DnsNameDomainLabel );
  279. LsapFreeLsaHeap( SiteNameString );
  280. //
  281. // Return the site name only if it can be used as a DNS label
  282. //
  283. if ( NetStatus == NO_ERROR || NetStatus == DNS_ERROR_NON_RFC_NAME ) {
  284. LSAPDS_ALLOC_AND_COPY_STRING_TO_UNICODE_ON_SUCCESS(
  285. Status,
  286. &SiteInfoEntry->SiteName,
  287. RdnBuffer,
  288. RdnLen*sizeof(WCHAR) );
  289. //
  290. // On success, indicate that the site is valid
  291. //
  292. if ( NT_SUCCESS(Status) ) {
  293. *SiteValid = TRUE;
  294. }
  295. } else {
  296. *SiteValid = FALSE;
  297. }
  298. }
  299. }
  300. }
  301. LsapExitFunc( "LsapDsReadSiteObj", Status );
  302. return( Status );
  303. }
  304. NTSTATUS
  305. LsaIGetSiteName(
  306. OUT PLSAP_SITENAME_INFO *SiteNameInformation
  307. )
  308. /*++
  309. Routine Description:
  310. This routine returns the GUID of this DSA and the SiteName of the
  311. site this DSA is in.
  312. Arguments:
  313. SiteNameInformation - Returns a pointer to the site name information.
  314. Buffer should be freed using LsaIFree_LSAP_SITENAME_INFO;
  315. Returns:
  316. STATUS_SUCCESS - Success
  317. STATUS_INVALID_DOMAIN_STATE - The Ds is not installed or running at the time of the call
  318. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  319. --*/
  320. {
  321. NTSTATUS Status;
  322. BINDARG BindArg;
  323. BINDRES *BindRes;
  324. PLSAP_SITENAME_INFO SiteNameInfo = NULL;
  325. PDSNAME SiteDsName = NULL;
  326. BOOLEAN CloseTransaction = FALSE;
  327. ULONG DsaOptions = 0;
  328. //
  329. // The list of attributes we need from the DSA object
  330. //
  331. ATTR DsaAttrVals[] = {
  332. {ATT_OPTIONS, {0, NULL} },
  333. };
  334. ATTRBLOCK ReadBlock, ReturnedBlock;
  335. WCHAR RdnBuffer[MAX_RDN_SIZE + 1];
  336. ULONG RdnLen;
  337. ATTRTYP RdnType;
  338. ULONG i;
  339. LsarpReturnCheckSetup();
  340. LsapEnterFunc( "LsaIGetSiteName" );
  341. //
  342. // Make sure the DS is installed
  343. //
  344. if ( !LsaDsStateInfo.UseDs ) {
  345. LsapExitFunc( "LsaIGetSiteName", STATUS_INVALID_DOMAIN_STATE );
  346. return STATUS_INVALID_DOMAIN_STATE;
  347. }
  348. //
  349. // See if we already have a transaction going
  350. //
  351. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  352. LSAP_DB_DS_OP_TRANSACTION,
  353. NullObject,
  354. &CloseTransaction );
  355. if ( !NT_SUCCESS( Status ) ) {
  356. return Status;
  357. }
  358. //
  359. // Get the DSA object's DSNAME.
  360. //
  361. RtlZeroMemory( &BindArg, sizeof(BindArg) );
  362. Status = LsapDsMapDsReturnToStatus( DirBind( &BindArg,
  363. &BindRes ));
  364. LsapDsContinueTransaction();
  365. if ( !NT_SUCCESS( Status ) ) {
  366. goto Cleanup;
  367. }
  368. //
  369. // Read the required attributes from the DSA object
  370. //
  371. ReadBlock.attrCount = sizeof(DsaAttrVals) / sizeof(ATTR);
  372. ReadBlock.pAttr = DsaAttrVals;
  373. Status = LsapDsReadByDsName( BindRes->pCredents,
  374. LSAPDS_READ_NO_LOCK,
  375. &ReadBlock,
  376. &ReturnedBlock );
  377. if ( Status == STATUS_UNSUCCESSFUL ) {
  378. Status = STATUS_NOT_FOUND;
  379. }
  380. //
  381. // If the options attribute exists,
  382. // get its value.
  383. //
  384. if ( Status != STATUS_NOT_FOUND ) {
  385. if ( !NT_SUCCESS( Status ) ) {
  386. goto Cleanup;
  387. }
  388. //
  389. // Get the attributes from the DSA object
  390. //
  391. for ( i = 0;
  392. i < ReturnedBlock.attrCount && NT_SUCCESS( Status );
  393. i++) {
  394. //
  395. // Handle the DSA Options attributes.
  396. //
  397. switch ( ReturnedBlock.pAttr[i].attrTyp ) {
  398. case ATT_OPTIONS:
  399. // Attribute is single valued, but ...
  400. if ( ReturnedBlock.pAttr[i].AttrVal.valCount >= 1 ) {
  401. DsaOptions = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( &ReturnedBlock.pAttr[ i ] );
  402. }
  403. break;
  404. default:
  405. Status = STATUS_INVALID_PARAMETER;
  406. break;
  407. }
  408. }
  409. }
  410. //
  411. // Compute the name of the site this DSA is in.
  412. // (Simply trim three names off the DSA's DSNAME )
  413. //
  414. SiteDsName = LsapAllocateLsaHeap( BindRes->pCredents->structLen );
  415. if ( SiteDsName == NULL ) {
  416. Status = STATUS_INSUFFICIENT_RESOURCES;
  417. goto Cleanup;
  418. }
  419. if ( TrimDSNameBy( BindRes->pCredents, 3, SiteDsName ) != 0 ) {
  420. Status = STATUS_INTERNAL_ERROR;
  421. goto Cleanup;
  422. }
  423. //
  424. // The site name is the RDN of the site object.
  425. //
  426. Status = LsapDsMapDsReturnToStatus( GetRDNInfoExternal(
  427. SiteDsName,
  428. RdnBuffer,
  429. &RdnLen,
  430. &RdnType ) );
  431. if ( !NT_SUCCESS( Status ) ) {
  432. goto Cleanup;
  433. }
  434. //
  435. // Allocate a buffer to return to the caller.
  436. //
  437. SiteNameInfo = LsapAllocateLsaHeap( sizeof(LSAP_SITENAME_INFO) );
  438. if ( SiteNameInfo == NULL ) {
  439. Status = STATUS_INSUFFICIENT_RESOURCES;
  440. goto Cleanup;
  441. }
  442. //
  443. // Fill it in.
  444. //
  445. LSAPDS_ALLOC_AND_COPY_STRING_TO_UNICODE_ON_SUCCESS(
  446. Status,
  447. &SiteNameInfo->SiteName,
  448. RdnBuffer,
  449. RdnLen*sizeof(WCHAR) );
  450. if ( !NT_SUCCESS( Status ) ) {
  451. goto Cleanup;
  452. }
  453. SiteNameInfo->DsaGuid = BindRes->pCredents->Guid;
  454. SiteNameInfo->DsaOptions = DsaOptions;
  455. Status = STATUS_SUCCESS;
  456. //
  457. // Free locally used resources
  458. //
  459. Cleanup:
  460. //
  461. // Destruction of the thread state will delete the memory alloced by the SearchNonUnique call
  462. //
  463. LsapDsDeleteAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  464. LSAP_DB_DS_OP_TRANSACTION,
  465. NullObject,
  466. CloseTransaction );
  467. if ( SiteDsName != NULL ) {
  468. LsapFreeLsaHeap( SiteDsName );
  469. }
  470. if ( !NT_SUCCESS( Status ) ) {
  471. LsaIFree_LSAP_SITENAME_INFO( SiteNameInfo );
  472. } else {
  473. *SiteNameInformation = SiteNameInfo;
  474. }
  475. LsarpReturnPrologue();
  476. LsapExitFunc( "LsaIGetSiteName", Status );
  477. return( Status );
  478. }
  479. NTSTATUS
  480. LsaIQuerySiteInfo(
  481. OUT PLSAP_SITE_INFO *SiteInformation
  482. )
  483. /*++
  484. Routine Description:
  485. This routine enumerates all of the sites objects and returns their names.
  486. Returned site names are validated to be non-mangled. (A name can become
  487. mangled as a result of a name collision in the DS where an object with a
  488. mangled name is created in addition to the object with the intended name).
  489. The sites are also verified to be valid for use as DNS labels in a DNS name.
  490. This is done to ensure that netlogon will succeed to register DNS records
  491. containing the site names returned.
  492. Arguments:
  493. SiteInformation - Returns a pointer to the site information.
  494. Buffer should be freed using LsaIFree_LSAP_SITE_INFO;
  495. Returns:
  496. STATUS_SUCCESS - Success
  497. STATUS_INVALID_DOMAIN_STATE - The Ds is not installed or running at the time of the call
  498. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  499. --*/
  500. {
  501. NTSTATUS Status;
  502. ULONG DsNameLen;
  503. ULONG DsNameSize;
  504. PDSNAME DsSiteContainer = NULL;
  505. PDSNAME *DsNames = NULL;
  506. ULONG Items;
  507. ULONG i;
  508. ATTRBLOCK *ReadAttrs;
  509. BOOLEAN CloseTransaction = FALSE;
  510. PLSAP_SITE_INFO SiteInfo = NULL;
  511. BOOLEAN TsActive = FALSE;
  512. ULONG Size;
  513. ULONG ClassId;
  514. //
  515. // Attributes we want to look for
  516. //
  517. ATTRVAL SiteAttVals[] = {
  518. { sizeof(ULONG), (PUCHAR)&ClassId},
  519. };
  520. ATTR SiteAttrs[] = {
  521. { ATT_OBJECT_CLASS, {1, &SiteAttVals[0] } },
  522. };
  523. LsarpReturnCheckSetup();
  524. ClassId = CLASS_SITE;
  525. //
  526. // Make sure the DS is installed
  527. //
  528. if ( !LsaDsStateInfo.UseDs ) {
  529. return STATUS_INVALID_DOMAIN_STATE;
  530. }
  531. LsapEnterFunc( "LsaIQuerySiteInfo" );
  532. //
  533. // Build the name of the Site container.
  534. //
  535. // DSNameSizeFromLen doesn't want the trailing NULL that we'll give it by using
  536. // the sizeof operators. It evens out, though, since we don't bother adding in the
  537. // comma seperator that should be there as well.
  538. //
  539. DsNameLen = wcslen( LsaDsStateInfo.DsConfigurationContainer->StringName ) +
  540. wcslen( LSAP_DS_SITES_CONTAINER ) + 1;
  541. DsNameSize = DSNameSizeFromLen( DsNameLen );
  542. DsSiteContainer = LsapAllocateLsaHeap( DsNameSize );
  543. if ( DsSiteContainer == NULL ) {
  544. Status = STATUS_INSUFFICIENT_RESOURCES;
  545. goto Cleanup;
  546. } else {
  547. DsSiteContainer->structLen = DsNameSize;
  548. DsSiteContainer->NameLen = DsNameLen;
  549. swprintf( DsSiteContainer->StringName,
  550. L"%ws,%ws",
  551. LSAP_DS_SITES_CONTAINER,
  552. LsaDsStateInfo.DsConfigurationContainer->StringName );
  553. }
  554. //
  555. // See if we already have a transaction going
  556. //
  557. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  558. LSAP_DB_DS_OP_TRANSACTION,
  559. NullObject,
  560. &CloseTransaction );
  561. if ( !NT_SUCCESS( Status ) ) {
  562. goto Cleanup;
  563. }
  564. TsActive = TRUE;;
  565. //
  566. // Search for the site objects
  567. //
  568. // Site objects must be directly in the sites container.
  569. //
  570. Status = LsapDsSearchNonUnique( LSAPDS_SEARCH_LEVEL | LSAPDS_OP_NO_TRANS,
  571. DsSiteContainer,
  572. SiteAttrs,
  573. sizeof(SiteAttrs)/sizeof(SiteAttrs[0]),
  574. &DsNames,
  575. &Items );
  576. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  577. Items = 0;
  578. Status = STATUS_SUCCESS;
  579. DsNames = NULL;
  580. }
  581. if ( !NT_SUCCESS( Status ) ) {
  582. goto Cleanup;
  583. }
  584. //
  585. // Allocate a list of attribute blocks big enough to hold them all
  586. //
  587. Size = sizeof( LSAP_SITE_INFO ) +
  588. Items * sizeof( LSAP_SITE_INFO_ENTRY );
  589. SiteInfo = LsapAllocateLsaHeap( Size );
  590. if ( SiteInfo == NULL ) {
  591. Status = STATUS_INSUFFICIENT_RESOURCES;
  592. goto Cleanup;
  593. }
  594. RtlZeroMemory( SiteInfo, Size );
  595. SiteInfo->SiteCount = 0;
  596. //
  597. // Read each of the enumerated site objects
  598. //
  599. for ( i = 0; i < Items; i++ ) {
  600. BOOL SiteValid = FALSE;
  601. Status = LsapDsReadSiteObj( DsNames[ i ] ,
  602. &SiteValid,
  603. &SiteInfo->Sites[SiteInfo->SiteCount] );
  604. if ( !NT_SUCCESS(Status) ) {
  605. goto Cleanup;
  606. }
  607. //
  608. // If site is valid, count this entry
  609. //
  610. if ( SiteValid ) {
  611. SiteInfo->SiteCount ++;
  612. }
  613. }
  614. Status = STATUS_SUCCESS;
  615. //
  616. // Free locally used resources
  617. //
  618. Cleanup:
  619. //
  620. // Destruction of the thread state will delete the memory alloced by the SearchNonUnique call
  621. //
  622. if ( TsActive ) {
  623. LsapDsDeleteAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  624. LSAP_DB_DS_OP_TRANSACTION,
  625. NullObject,
  626. CloseTransaction );
  627. }
  628. if ( DsSiteContainer != NULL ) {
  629. LsapFreeLsaHeap( DsSiteContainer );
  630. }
  631. if ( DsNames != NULL ) {
  632. LsapFreeLsaHeap( DsNames );
  633. }
  634. if ( !NT_SUCCESS( Status ) ) {
  635. LsaIFree_LSAP_SITE_INFO( SiteInfo );
  636. } else {
  637. *SiteInformation = SiteInfo;
  638. }
  639. LsarpReturnPrologue();
  640. LsapExitFunc( "LsaIQuerySiteInfo", Status );
  641. return( Status );
  642. }
  643. VOID
  644. LsaIFree_LSAP_SITE_INFO(
  645. IN PLSAP_SITE_INFO SiteInfo
  646. )
  647. /*++
  648. Routine Description:
  649. This routine free the LSAP_SITE_INFO strcture returned from
  650. LsaIQuerySiteInfo.
  651. Arguments:
  652. SiteInformation - Specifies a pointer to the site information.
  653. Returns:
  654. None.
  655. --*/
  656. {
  657. ULONG i;
  658. if ( SiteInfo != NULL ) {
  659. for ( i=0; i<SiteInfo->SiteCount; i++) {
  660. if ( SiteInfo->Sites[i].SiteName.Buffer != NULL ) {
  661. LsapFreeLsaHeap( SiteInfo->Sites[i].SiteName.Buffer );
  662. }
  663. }
  664. LsapFreeLsaHeap( SiteInfo );
  665. }
  666. }
  667. NTSTATUS
  668. LsaIQuerySubnetInfo(
  669. OUT PLSAP_SUBNET_INFO *SubnetInformation
  670. )
  671. /*++
  672. Routine Description:
  673. This routine enumerates all of the subnet objects returns their names
  674. and the names of the sites they are in. Returned subnet and site names
  675. are validated to be non-mangled. (A name can become mangled as a result
  676. of a name collision in the DS where an object with a mangled name is
  677. created in addition to the object with the intended name). The sites
  678. are verified to be valid for use as DNS labels in a DNS name. This
  679. is done to ensure that netlogon will succeed to register DNS records
  680. containing the site names returned.
  681. Arguments:
  682. SubnetInformation - Returns a pointer to the subnet information.
  683. Buffer should be freed using LsaIFree_LSAP_SUBNET_INFO;
  684. Returns:
  685. STATUS_SUCCESS - Success
  686. STATUS_INVALID_DOMAIN_STATE - The Ds is not installed or running at the time of the call
  687. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  688. --*/
  689. {
  690. NTSTATUS Status;
  691. ULONG DsNameLen;
  692. ULONG DsNameSize;
  693. PDSNAME DsSubnetContainer = NULL;
  694. PDSNAME DsSiteContainer = NULL;
  695. PDSNAME *DsNames = NULL;
  696. ULONG Items;
  697. ULONG i;
  698. ATTRBLOCK *ReadAttrs;
  699. BOOLEAN CloseTransaction = FALSE;
  700. BOOLEAN TsActive = FALSE;
  701. PLSAP_SUBNET_INFO SubnetInfo = NULL;
  702. ULONG Size;
  703. ULONG ClassId;
  704. //
  705. // Attributes we want to look for
  706. //
  707. ATTRVAL SubnetAttVals[] = {
  708. { sizeof(ULONG), (PUCHAR)&ClassId},
  709. };
  710. ATTR SubnetAttrs[] = {
  711. { ATT_OBJECT_CLASS, {1, &SubnetAttVals[0] } },
  712. };
  713. LsarpReturnCheckSetup();
  714. ClassId = CLASS_SUBNET;
  715. //
  716. // Make sure the DS is installed
  717. //
  718. if ( !LsaDsStateInfo.UseDs ) {
  719. return STATUS_INVALID_DOMAIN_STATE;
  720. }
  721. LsapEnterFunc( "LsaIQuerySubnetInfo" );
  722. //
  723. // Build the name of the Subnet container.
  724. //
  725. // DSNameSizeFromLen doesn't want the trailing NULL that we'll give it by using
  726. // the sizeof operators. It evens out, though, since we don't bother adding in the
  727. // comma seperator that should be there as well.
  728. //
  729. DsNameLen = wcslen( LsaDsStateInfo.DsConfigurationContainer->StringName ) +
  730. wcslen( LSAP_DS_SUBNET_CONTAINER ) + 1;
  731. DsNameSize = DSNameSizeFromLen( DsNameLen );
  732. DsSubnetContainer = LsapAllocateLsaHeap( DsNameSize );
  733. if ( DsSubnetContainer == NULL ) {
  734. Status = STATUS_INSUFFICIENT_RESOURCES;
  735. goto Cleanup;
  736. } else {
  737. DsSubnetContainer->structLen = DsNameSize;
  738. DsSubnetContainer->NameLen = DsNameLen;
  739. swprintf( DsSubnetContainer->StringName,
  740. L"%ws,%ws",
  741. LSAP_DS_SUBNET_CONTAINER,
  742. LsaDsStateInfo.DsConfigurationContainer->StringName );
  743. }
  744. //
  745. // See if we already have a transaction going
  746. //
  747. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  748. LSAP_DB_DS_OP_TRANSACTION,
  749. NullObject,
  750. &CloseTransaction );
  751. if ( !NT_SUCCESS( Status ) ) {
  752. goto Cleanup;
  753. }
  754. TsActive = TRUE;
  755. //
  756. // Search for the subnet objects
  757. //
  758. // Subnet objects must be directly in the subnet container.
  759. //
  760. Status = LsapDsSearchNonUnique( LSAPDS_SEARCH_LEVEL | LSAPDS_OP_NO_TRANS,
  761. DsSubnetContainer,
  762. SubnetAttrs,
  763. sizeof(SubnetAttrs)/sizeof(SubnetAttrs[0]),
  764. &DsNames,
  765. &Items
  766. );
  767. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  768. Items = 0;
  769. Status = STATUS_SUCCESS;
  770. DsNames = NULL;
  771. }
  772. if ( !NT_SUCCESS( Status ) ) {
  773. goto Cleanup;
  774. }
  775. //
  776. // Allocate a list of attribute blocks big enough to hold them all
  777. //
  778. Size = sizeof( LSAP_SUBNET_INFO ) +
  779. Items * sizeof( LSAP_SUBNET_INFO_ENTRY );
  780. SubnetInfo = LsapAllocateLsaHeap( Size );
  781. if ( SubnetInfo == NULL ) {
  782. Status = STATUS_INSUFFICIENT_RESOURCES;
  783. goto Cleanup;
  784. }
  785. RtlZeroMemory( SubnetInfo, Size );
  786. SubnetInfo->SubnetCount = 0;
  787. //
  788. // Read each of the enumerated subnet objects
  789. //
  790. for ( i = 0; i < Items; i++ ) {
  791. BOOL SubnetValid = FALSE;
  792. Status = LsapDsReadSubnetObj( DsNames[ i ] ,
  793. &SubnetValid,
  794. &SubnetInfo->Subnets[SubnetInfo->SubnetCount] );
  795. if ( !NT_SUCCESS(Status) ) {
  796. goto Cleanup;
  797. }
  798. //
  799. // If subnet/site valid, count this entry
  800. //
  801. if ( SubnetValid ) {
  802. SubnetInfo->SubnetCount ++;
  803. }
  804. }
  805. if ( DsNames != NULL ) {
  806. LsapFreeLsaHeap( DsNames );
  807. DsNames = NULL;
  808. }
  809. //
  810. // Determine the number of site objects.
  811. //
  812. // The caller wants to be able to special case the single site case in
  813. // for enterprises that's aren't interested in subnet objects.
  814. //
  815. {
  816. //
  817. // Build the name of the Site container.
  818. //
  819. // DSNameSizeFromLen doesn't want the trailing NULL that we'll give it by using
  820. // the sizeof operators. It evens out, though, since we don't bother adding in the
  821. // comma seperator that should be there as well.
  822. //
  823. DsNameLen = wcslen( LsaDsStateInfo.DsConfigurationContainer->StringName ) +
  824. wcslen( LSAP_DS_SITES_CONTAINER ) + 1;
  825. DsNameSize = DSNameSizeFromLen( DsNameLen );
  826. DsSiteContainer = LsapAllocateLsaHeap( DsNameSize );
  827. if ( DsSiteContainer == NULL ) {
  828. Status = STATUS_INSUFFICIENT_RESOURCES;
  829. goto Cleanup;
  830. } else {
  831. DsSiteContainer->structLen = DsNameSize;
  832. DsSiteContainer->NameLen = DsNameLen;
  833. swprintf( DsSiteContainer->StringName,
  834. L"%ws,%ws",
  835. LSAP_DS_SITES_CONTAINER,
  836. LsaDsStateInfo.DsConfigurationContainer->StringName );
  837. }
  838. //
  839. // Search for the site objects
  840. //
  841. // Site objects must be directly in the sites container.
  842. //
  843. ClassId = CLASS_SITE;
  844. Status = LsapDsSearchNonUnique( LSAPDS_SEARCH_LEVEL | LSAPDS_OP_NO_TRANS,
  845. DsSiteContainer,
  846. SubnetAttrs,
  847. sizeof(SubnetAttrs)/sizeof(SubnetAttrs[0]),
  848. &DsNames,
  849. &Items );
  850. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  851. Items = 0;
  852. Status = STATUS_SUCCESS;
  853. DsNames = NULL;
  854. }
  855. if ( !NT_SUCCESS( Status ) ) {
  856. goto Cleanup;
  857. }
  858. //
  859. // Simply tell the caller the number of valid sites
  860. //
  861. SubnetInfo->SiteCount = 0;
  862. for ( i = 0; i < Items; i++ ) {
  863. WCHAR RdnBuffer[MAX_RDN_SIZE + 1];
  864. ULONG RdnLen;
  865. ATTRTYP RdnType;
  866. //
  867. // Get the RDN of the site object
  868. //
  869. Status = LsapDsMapDsReturnToStatus( GetRDNInfoExternal(
  870. DsNames[i],
  871. RdnBuffer,
  872. &RdnLen,
  873. &RdnType ) );
  874. if ( !NT_SUCCESS(Status) ) {
  875. goto Cleanup;
  876. }
  877. //
  878. // If the site object RDN is mangled as a result
  879. // of a site name collision in the DS, ignore this
  880. // site object
  881. //
  882. if ( IsMangledRDNExternal(RdnBuffer, RdnLen, NULL) ) {
  883. continue;
  884. //
  885. // OK, the site name is not mangled. Verify that
  886. // it can be used as a DNS label
  887. //
  888. } else {
  889. NET_API_STATUS NetStatus;
  890. LPWSTR SiteNameString = NULL;
  891. SiteNameString = LsapAllocateLsaHeap( (RdnLen + 1) * sizeof(WCHAR) );
  892. if ( SiteNameString == NULL ) {
  893. Status = STATUS_INSUFFICIENT_RESOURCES;
  894. goto Cleanup;
  895. }
  896. RtlCopyMemory( SiteNameString, RdnBuffer, RdnLen*sizeof(WCHAR) );
  897. SiteNameString[RdnLen] = UNICODE_NULL;
  898. NetStatus = DnsValidateName_W( SiteNameString, DnsNameDomainLabel );
  899. LsapFreeLsaHeap( SiteNameString );
  900. //
  901. // If the name can't be used as a DNS label,
  902. // ignore this site
  903. //
  904. if ( NetStatus != NO_ERROR && NetStatus != DNS_ERROR_NON_RFC_NAME ) {
  905. continue;
  906. }
  907. }
  908. //
  909. // All checks succeeded. Count this site.
  910. //
  911. SubnetInfo->SiteCount ++;
  912. }
  913. }
  914. Status = STATUS_SUCCESS;
  915. //
  916. // Free locally used resources
  917. //
  918. Cleanup:
  919. //
  920. // Destruction of the thread state will delete the memory alloced by the SearchNonUnique call
  921. //
  922. if ( TsActive ) {
  923. LsapDsDeleteAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  924. LSAP_DB_DS_OP_TRANSACTION,
  925. NullObject,
  926. CloseTransaction );
  927. }
  928. if ( DsSubnetContainer != NULL ) {
  929. LsapFreeLsaHeap( DsSubnetContainer );
  930. }
  931. if ( DsSiteContainer != NULL ) {
  932. LsapFreeLsaHeap( DsSiteContainer );
  933. }
  934. if ( DsNames != NULL ) {
  935. LsapFreeLsaHeap( DsNames );
  936. }
  937. if ( !NT_SUCCESS( Status ) ) {
  938. LsaIFree_LSAP_SUBNET_INFO( SubnetInfo );
  939. } else {
  940. *SubnetInformation = SubnetInfo;
  941. }
  942. LsarpReturnPrologue();
  943. LsapExitFunc( "LsaIQuerySubnetInfo", Status );
  944. return( Status );
  945. }
  946. VOID
  947. LsaIFree_LSAP_SUBNET_INFO(
  948. IN PLSAP_SUBNET_INFO SubnetInfo
  949. )
  950. /*++
  951. Routine Description:
  952. This routine free the LSAP_SUBNET_INFO strcture returned from
  953. LsaIQuerySubnetInfo.
  954. Arguments:
  955. SubnetInformation - Specifies a pointer to the subnet information.
  956. Returns:
  957. None.
  958. --*/
  959. {
  960. ULONG i;
  961. if ( SubnetInfo != NULL ) {
  962. for ( i=0; i<SubnetInfo->SubnetCount; i++) {
  963. if ( SubnetInfo->Subnets[i].SubnetName.Buffer != NULL ) {
  964. LsapFreeLsaHeap( SubnetInfo->Subnets[i].SubnetName.Buffer );
  965. }
  966. if ( SubnetInfo->Subnets[i].SiteName.Buffer != NULL ) {
  967. LsapFreeLsaHeap( SubnetInfo->Subnets[i].SiteName.Buffer );
  968. }
  969. }
  970. LsapFreeLsaHeap( SubnetInfo );
  971. }
  972. }
  973. VOID
  974. LsaIFree_LSAP_SITENAME_INFO(
  975. IN PLSAP_SITENAME_INFO SiteNameInfo
  976. )
  977. /*++
  978. Routine Description:
  979. This routine frees the LSAP_SITENAME_INFO strcture returned from
  980. LsaIGetSiteName.
  981. Arguments:
  982. SitenameInfo - Specifies a pointer to the sitename information.
  983. Returns:
  984. None.
  985. --*/
  986. {
  987. ULONG i;
  988. if ( SiteNameInfo != NULL ) {
  989. if ( SiteNameInfo->SiteName.Buffer != NULL ) {
  990. LsapFreeLsaHeap( SiteNameInfo->SiteName.Buffer );
  991. }
  992. LsapFreeLsaHeap( SiteNameInfo );
  993. }
  994. }
  995. BOOLEAN
  996. LsaIIsDsPaused(
  997. VOID
  998. )
  999. /*++
  1000. Routine Description:
  1001. This routine determines DS wants us to avoid advertising it.
  1002. The only current reason is if the DS is backsyncing after a restore.
  1003. Arguments:
  1004. None
  1005. Returns:
  1006. TRUE: The DS is paused.
  1007. FALSE: The DS is not paused
  1008. --*/
  1009. {
  1010. //
  1011. // Simply return TRUE if the DS is backsyncing.
  1012. //
  1013. if ( SampUsingDsData() ) {
  1014. return DsIsBeingBackSynced();
  1015. }
  1016. return FALSE;
  1017. }
  1018. NTSTATUS
  1019. LsaISetClientDnsHostName(
  1020. IN PWSTR ClientName,
  1021. IN PWSTR ClientDnsHostName OPTIONAL,
  1022. IN POSVERSIONINFOEXW OsVersionInfo OPTIONAL,
  1023. IN PWSTR OsName OPTIONAL,
  1024. OUT PWSTR *OldDnsHostName OPTIONAL
  1025. )
  1026. /*++
  1027. Routine Description:
  1028. This routine will update the DnsHostName on the specified client object if it is
  1029. different from the one alread on the object
  1030. Arguments:
  1031. ClientName - Name of the client
  1032. DnsHostName - Dns host name that should be on the client
  1033. If not specified, the Dns Host name attribute will be removed from the object.
  1034. However, if OldDnsHostName is specified, this parameter will be completely
  1035. ignored.
  1036. OsVersionInfo - Version Info of the client
  1037. If not specified, the version attributes will be removed from the object.
  1038. OsName - Operation System name of the client
  1039. If not specified, the operating system name will be removed from the object.
  1040. OldDnsHostName - If specified, this parameter will returns a pointer to the
  1041. current DNS Host Name on the computer object.
  1042. A NULL pointer is returned if there is no current DNS Host Name.
  1043. This buffer should be freed using MIDL_user_free.
  1044. Returns:
  1045. STATUS_SUCCESS - Success
  1046. STATUS_OBJECT_NAME_NOT_FOUND - No such client was found
  1047. --*/
  1048. {
  1049. NTSTATUS Status;
  1050. NTSTATUS SavedStatus = STATUS_SUCCESS;
  1051. PDSNAME ServerPath;
  1052. PDSNAME *MachinePaths = NULL;
  1053. ULONG MachinePathCount;
  1054. ULONG MachinePathIndex;
  1055. ATTRBLOCK AttrBlock, Results, Results2, Results3;
  1056. PBYTE AllocatedBuffer = NULL;
  1057. PWSTR SamName;
  1058. ULONG SamNameSize;
  1059. PWSTR OsVersion;
  1060. ULONG OsVersionSize;
  1061. ATTRVAL ReplaceVals[ LsapDsMachineClientSetAttrsCount ];
  1062. ATTR ReplaceAttributes[ LsapDsMachineClientSetAttrsCount ];
  1063. ATTRBLOCK ReplaceAttrBlock;
  1064. ATTR LocalSamAccountAttr;
  1065. ATTRVAL RemoveVals[ LsapDsMachineClientSetAttrsCount ];
  1066. ATTR RemoveAttributes[ LsapDsMachineClientSetAttrsCount ];
  1067. ATTRBLOCK RemoveAttrBlock;
  1068. BOOLEAN CloseTransaction = FALSE;
  1069. BOOLEAN TsActive = FALSE;
  1070. PWSTR CurrentServerDnsHostName;
  1071. ULONG CurrentServerDnsHostNameLength;
  1072. PWSTR CurrentComputerDnsHostName = NULL;
  1073. ULONG CurrentComputerDnsHostNameLength = 0;
  1074. ULONG i;
  1075. struct _AttributesToUpdate {
  1076. PWSTR CurrentValue;
  1077. ULONG CurrentValueLength;
  1078. PWSTR NewValue;
  1079. } AttributesToUpdate[LsapDsMachineClientSetAttrsCount];
  1080. //
  1081. // The indices below must match the order of the element of LsapDsMachineClientSetAttrs
  1082. //
  1083. #define ATU_HOST_INDEX 0
  1084. #define ATU_OS_INDEX 1
  1085. #define ATU_OS_VERSION_INDEX 2
  1086. #define ATU_OS_SERVICE_PACK_INDEX 3
  1087. #define ATU_SERVICE_PRINCIPAL_NAME_INDEX 4
  1088. LsapEnterFunc( "LsaISetClientDnsHostName" );
  1089. //
  1090. // Initialization
  1091. //
  1092. if ( ARGUMENT_PRESENT( OldDnsHostName )) {
  1093. *OldDnsHostName = NULL;
  1094. }
  1095. RtlZeroMemory( &AttributesToUpdate, sizeof(AttributesToUpdate) );
  1096. //
  1097. // If we haven't initalized the Ds names, we might as well bail
  1098. //
  1099. if ( !LsaDsStateInfo.DsRoot ) {
  1100. return( STATUS_UNSUCCESSFUL );
  1101. }
  1102. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  1103. LSAP_DB_DS_OP_TRANSACTION,
  1104. NullObject,
  1105. &CloseTransaction );
  1106. if ( !NT_SUCCESS( Status ) ) {
  1107. goto SetDnsHostNameEnd;
  1108. }
  1109. TsActive = TRUE;
  1110. //
  1111. // Allocate a buffer for all of the temporary storage for this routine
  1112. //
  1113. SamNameSize = (wcslen( ClientName ) + 2) * sizeof(WCHAR);
  1114. OsVersionSize = (32+1+32+2+32+2) * sizeof(WCHAR);
  1115. AllocatedBuffer = LsapAllocateLsaHeap( SamNameSize +
  1116. OsVersionSize );
  1117. if ( AllocatedBuffer == NULL ) {
  1118. Status = STATUS_INSUFFICIENT_RESOURCES;
  1119. goto SetDnsHostNameEnd;
  1120. }
  1121. SamName = (PWSTR)(AllocatedBuffer);
  1122. OsVersion = (PWSTR)(SamName + SamNameSize);
  1123. //
  1124. // Compute the new value of all of the attributes to set.
  1125. //
  1126. AttributesToUpdate[ATU_OS_INDEX].NewValue = OsName;
  1127. if ( OsVersionInfo != NULL ) {
  1128. AttributesToUpdate[ATU_OS_VERSION_INDEX].NewValue = OsVersion;
  1129. if ( OsVersionInfo->dwBuildNumber == 0 ) {
  1130. swprintf( AttributesToUpdate[ATU_OS_VERSION_INDEX].NewValue,
  1131. L"%ld.%ld",
  1132. OsVersionInfo->dwMajorVersion,
  1133. OsVersionInfo->dwMinorVersion );
  1134. } else {
  1135. swprintf( AttributesToUpdate[ATU_OS_VERSION_INDEX].NewValue,
  1136. L"%ld.%ld (%ld)",
  1137. OsVersionInfo->dwMajorVersion,
  1138. OsVersionInfo->dwMinorVersion,
  1139. OsVersionInfo->dwBuildNumber );
  1140. }
  1141. if ( OsVersionInfo->szCSDVersion[0] != L'\0' ) {
  1142. AttributesToUpdate[ATU_OS_SERVICE_PACK_INDEX].NewValue = OsVersionInfo->szCSDVersion;
  1143. }
  1144. }
  1145. //
  1146. // Only update the DnsHostName if the client isn't going to
  1147. //
  1148. if ( !ARGUMENT_PRESENT( OldDnsHostName )) {
  1149. AttributesToUpdate[ATU_HOST_INDEX].NewValue = ClientDnsHostName;
  1150. }
  1151. //
  1152. // Find the objects whose computer name is the one we were given...
  1153. //
  1154. swprintf( SamName, L"%ws$", ClientName );
  1155. RtlCopyMemory( &LocalSamAccountAttr, &LsapDsAttrs[LsapDsAttrSamAccountName], sizeof( ATTR ) );
  1156. LSAP_DS_SET_DS_ATTRIBUTE_STRING( &LocalSamAccountAttr, SamName );
  1157. Status = LsapDsSearchNonUnique( LSAPDS_OP_NO_TRANS,
  1158. LsaDsStateInfo.DsRoot,
  1159. &LocalSamAccountAttr,
  1160. 1,
  1161. &MachinePaths,
  1162. &MachinePathCount );
  1163. if ( !NT_SUCCESS( Status ) ) {
  1164. goto SetDnsHostNameEnd;
  1165. }
  1166. //
  1167. // Process each of the objects by that name
  1168. //
  1169. for ( MachinePathIndex=0; MachinePathIndex<MachinePathCount; MachinePathIndex++ ) {
  1170. PDSNAME MachinePath;
  1171. MachinePath = MachinePaths[MachinePathIndex];
  1172. //
  1173. // Read the current "Client Set" attributes name from the machine object
  1174. //
  1175. AttrBlock.attrCount = LsapDsMachineClientSetAttrsCount;
  1176. AttrBlock.pAttr = LsapDsMachineClientSetAttrs;
  1177. Status = LsapDsReadByDsName( MachinePath,
  1178. 0,
  1179. &AttrBlock,
  1180. &Results );
  1181. if ( Status == STATUS_NOT_FOUND ) {
  1182. Results.attrCount = 0;
  1183. Status = STATUS_SUCCESS;
  1184. }
  1185. if ( !NT_SUCCESS( Status ) ) {
  1186. if ( SavedStatus == STATUS_SUCCESS ) {
  1187. SavedStatus = Status;
  1188. }
  1189. continue;
  1190. }
  1191. //
  1192. // Loop through the each attribute returned from the DS
  1193. //
  1194. for ( i = 0; i < Results.attrCount; i++ ) {
  1195. ULONG j;
  1196. //
  1197. // Loop through the list of attributes we understand
  1198. //
  1199. for ( j=0; j<LsapDsMachineClientSetAttrsCount; j++ ) {
  1200. if ( Results.pAttr[i].attrTyp == LsapDsMachineClientSetAttrs[j].attrTyp ) {
  1201. // Attribute is single valued, but ...
  1202. if ( Results.pAttr[i].AttrVal.valCount >= 1 ) {
  1203. //
  1204. //
  1205. AttributesToUpdate[j].CurrentValue =
  1206. LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR(&Results.pAttr[ i ] );
  1207. // length in count of characters.
  1208. AttributesToUpdate[j].CurrentValueLength =
  1209. LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results.pAttr[ i ] ) / sizeof( WCHAR );
  1210. //
  1211. // If this is the DnsHostName attribute,
  1212. // and the caller doesn't want us to set it,
  1213. // simply remember the current value.
  1214. //
  1215. if ( Results.pAttr[i].attrTyp == ATT_DNS_HOST_NAME &&
  1216. ARGUMENT_PRESENT( OldDnsHostName )) {
  1217. if ( CurrentComputerDnsHostName == NULL &&
  1218. AttributesToUpdate[j].CurrentValueLength != 0 ) {
  1219. CurrentComputerDnsHostName = MIDL_user_allocate( AttributesToUpdate[j].CurrentValueLength * sizeof(WCHAR) + sizeof(WCHAR) );
  1220. if ( CurrentComputerDnsHostName == NULL ) {
  1221. if ( SavedStatus == STATUS_SUCCESS ) {
  1222. SavedStatus = STATUS_INSUFFICIENT_RESOURCES;
  1223. }
  1224. } else {
  1225. CurrentComputerDnsHostNameLength = AttributesToUpdate[j].CurrentValueLength;
  1226. RtlCopyMemory( CurrentComputerDnsHostName,
  1227. AttributesToUpdate[j].CurrentValue,
  1228. AttributesToUpdate[j].CurrentValueLength * sizeof(WCHAR) );
  1229. CurrentComputerDnsHostName[CurrentComputerDnsHostNameLength] = L'\0';
  1230. }
  1231. }
  1232. //
  1233. // Don't change the value on the computer object.
  1234. //
  1235. AttributesToUpdate[j].CurrentValue = NULL;
  1236. AttributesToUpdate[j].CurrentValueLength = 0;
  1237. }
  1238. //
  1239. // If this is the ServerPrincipalName attribute, we are
  1240. // prepared to remove it for NT3.5 and NT4 clients.
  1241. // However, don't touch this attribute if there is any
  1242. // doubt about the OS version that the client runs.
  1243. //
  1244. if ( Results.pAttr[i].attrTyp == ATT_SERVICE_PRINCIPAL_NAME &&
  1245. (OsVersionInfo == NULL ||
  1246. (OsVersionInfo->dwMajorVersion != 3 &&
  1247. OsVersionInfo->dwMajorVersion != 4)) ){
  1248. AttributesToUpdate[j].CurrentValue = NULL;
  1249. AttributesToUpdate[j].CurrentValueLength = 0;
  1250. }
  1251. }
  1252. break;
  1253. }
  1254. }
  1255. //
  1256. // If the DS returned an attribute we didn't query,
  1257. //
  1258. if ( j >= LsapDsMachineClientSetAttrsCount ) {
  1259. if ( SavedStatus == STATUS_SUCCESS ) {
  1260. SavedStatus = STATUS_INVALID_PARAMETER;
  1261. }
  1262. }
  1263. }
  1264. //
  1265. // Loop through each attribute of interest deciding to
  1266. // remove it or replace it.
  1267. //
  1268. RemoveAttrBlock.attrCount = 0;
  1269. RemoveAttrBlock.pAttr = RemoveAttributes;
  1270. ReplaceAttrBlock.attrCount = 0;
  1271. ReplaceAttrBlock.pAttr = ReplaceAttributes;
  1272. for ( i=0; i<LsapDsMachineClientSetAttrsCount; i++ ) {
  1273. //
  1274. // Write out the new name if it is different that the old name.
  1275. //
  1276. // Difference is defined as:
  1277. // A current name is present and is different from the one we're being asked to write
  1278. // There is no current name and there is a new name
  1279. // There is a current name and there is no new name (delete the current name)
  1280. //
  1281. if (( AttributesToUpdate[i].NewValue && AttributesToUpdate[i].CurrentValue &&
  1282. (AttributesToUpdate[i].CurrentValueLength != wcslen( AttributesToUpdate[i].NewValue ) ||
  1283. _wcsnicmp( AttributesToUpdate[i].NewValue,
  1284. AttributesToUpdate[i].CurrentValue,
  1285. AttributesToUpdate[i].CurrentValueLength))) ||
  1286. ( AttributesToUpdate[i].CurrentValue == NULL && AttributesToUpdate[i].NewValue != NULL) ||
  1287. ( AttributesToUpdate[i].CurrentValue != NULL && AttributesToUpdate[i].NewValue == NULL ) ) {
  1288. ULONG attrIndex;
  1289. //
  1290. // If the new attribute is NULL,
  1291. // remove the attribute from the DS
  1292. //
  1293. if ( AttributesToUpdate[i].NewValue == NULL ) {
  1294. RemoveAttributes[ RemoveAttrBlock.attrCount ].attrTyp =
  1295. LsapDsMachineClientSetAttrs[i].attrTyp;
  1296. RemoveAttributes[ RemoveAttrBlock.attrCount ].AttrVal.valCount = 1;
  1297. RemoveAttributes[ RemoveAttrBlock.attrCount ].AttrVal.pAVal =
  1298. &RemoveVals[ RemoveAttrBlock.attrCount ];
  1299. RtlZeroMemory( &RemoveVals[ RemoveAttrBlock.attrCount ],
  1300. sizeof( RemoveVals[ RemoveAttrBlock.attrCount ] ));
  1301. RemoveAttrBlock.attrCount ++;
  1302. //
  1303. // If the new attribute is not NULL,
  1304. // replace the attribute in the DS
  1305. //
  1306. } else {
  1307. ReplaceAttributes[ ReplaceAttrBlock.attrCount ].attrTyp =
  1308. LsapDsMachineClientSetAttrs[i].attrTyp;
  1309. ReplaceAttributes[ ReplaceAttrBlock.attrCount ].AttrVal.valCount = 1;
  1310. ReplaceAttributes[ ReplaceAttrBlock.attrCount ].AttrVal.pAVal =
  1311. &ReplaceVals[ ReplaceAttrBlock.attrCount ];
  1312. RtlZeroMemory( &ReplaceVals[ ReplaceAttrBlock.attrCount ],
  1313. sizeof( ReplaceVals[ ReplaceAttrBlock.attrCount ] ));
  1314. LSAP_DS_SET_DS_ATTRIBUTE_STRING(
  1315. &ReplaceAttributes[ ReplaceAttrBlock.attrCount ],
  1316. AttributesToUpdate[i].NewValue );
  1317. ReplaceAttrBlock.attrCount ++;
  1318. }
  1319. }
  1320. }
  1321. //
  1322. // If there are any attributes to replace,
  1323. // do it now.
  1324. //
  1325. if ( ReplaceAttrBlock.attrCount != 0 ) {
  1326. Status = LsapDsWriteByDsName( MachinePath,
  1327. LSAPDS_REPLACE_ATTRIBUTE,
  1328. &ReplaceAttrBlock );
  1329. if ( !NT_SUCCESS( Status ) ) {
  1330. LsapDsDebugOut(( DEB_ERROR,
  1331. "Replace of attributes to %ws failed with 0x%lx\n",
  1332. SamName,
  1333. Status ));
  1334. }
  1335. }
  1336. //
  1337. // If there are any attributes to remove,
  1338. // do it now.
  1339. //
  1340. if ( RemoveAttrBlock.attrCount != 0 ) {
  1341. Status = LsapDsWriteByDsName( MachinePath,
  1342. LSAPDS_REMOVE_ATTRIBUTE,
  1343. &RemoveAttrBlock );
  1344. if ( !NT_SUCCESS( Status ) ) {
  1345. LsapDsDebugOut(( DEB_ERROR,
  1346. "Remove of attributes to %ws failed with 0x%lx\n",
  1347. SamName,
  1348. Status ));
  1349. }
  1350. }
  1351. //
  1352. // ASSERT: We're done with the machine object
  1353. //
  1354. // Get the name of the Server this computer is linked to, if any.
  1355. //
  1356. AttrBlock.attrCount = LsapDsServerReferenceCountBl;
  1357. AttrBlock.pAttr = LsapDsServerReferenceBl;
  1358. Status = LsapDsReadByDsName( MachinePath,
  1359. 0,
  1360. &AttrBlock,
  1361. &Results3 );
  1362. if ( !NT_SUCCESS( Status ) ) {
  1363. if ( Status != STATUS_NOT_FOUND ) {
  1364. if ( SavedStatus == STATUS_SUCCESS ) {
  1365. SavedStatus = Status;
  1366. }
  1367. } else {
  1368. Status = STATUS_SUCCESS;
  1369. }
  1370. continue;
  1371. }
  1372. if ( Results3.attrCount == 0 ) {
  1373. continue;
  1374. }
  1375. ServerPath = LSAP_DS_GET_DS_ATTRIBUTE_AS_DSNAME( &Results3.pAttr[ 0 ] );
  1376. CurrentServerDnsHostName = NULL;
  1377. CurrentServerDnsHostNameLength = 0;
  1378. //
  1379. // Read the current host name from the server object
  1380. // No point in doing the read if we're doing a delete
  1381. //
  1382. if ( CurrentComputerDnsHostName != NULL ) {
  1383. //
  1384. // Read the current host name from the server object
  1385. //
  1386. AttrBlock.attrCount = LsapDsMachineDnsHostCount;
  1387. AttrBlock.pAttr = LsapDsMachineDnsHost;
  1388. Status = LsapDsReadByDsName(ServerPath,
  1389. 0,
  1390. &AttrBlock,
  1391. &Results2 );
  1392. if ( Status == STATUS_NOT_FOUND ) {
  1393. Results2.attrCount = 0;
  1394. Status = STATUS_SUCCESS;
  1395. }
  1396. if ( !NT_SUCCESS( Status ) ) {
  1397. if ( SavedStatus == STATUS_SUCCESS ) {
  1398. SavedStatus = Status;
  1399. }
  1400. continue;
  1401. }
  1402. if( Results2.attrCount == 1) {
  1403. CurrentServerDnsHostName = LSAP_DS_GET_DS_ATTRIBUTE_AS_PWSTR(&Results2.pAttr[ 0 ] );
  1404. // length in count of characters.
  1405. CurrentServerDnsHostNameLength =
  1406. LSAP_DS_GET_DS_ATTRIBUTE_LENGTH( &Results2.pAttr[ 0 ] ) / sizeof( WCHAR );
  1407. }
  1408. }
  1409. //
  1410. // Write out the new name if it is different that the old name.
  1411. // Difference is defined as:
  1412. // A current name is present and is different from the one we're being asked to write
  1413. // There is no current name and there is a new name
  1414. // There is a current name and there is no new name (delete the current name)
  1415. //
  1416. if ( (CurrentComputerDnsHostName &&
  1417. CurrentServerDnsHostName &&
  1418. (CurrentServerDnsHostNameLength != CurrentComputerDnsHostNameLength ||
  1419. _wcsnicmp( CurrentComputerDnsHostName, CurrentServerDnsHostName, CurrentServerDnsHostNameLength))) ||
  1420. ( CurrentServerDnsHostName == NULL && CurrentComputerDnsHostName != NULL ) ||
  1421. ( CurrentComputerDnsHostName == NULL ) ) {
  1422. ATTRVAL WriteVals[ 1 ];
  1423. ATTR WriteAttributes[ 1 ];
  1424. RtlZeroMemory( &WriteVals, sizeof( ATTRVAL ) );
  1425. WriteAttributes[ 0 ].attrTyp = LsapDsAttributeIds[ LsapDsAttrMachineDns ];
  1426. WriteAttributes[ 0 ].AttrVal.valCount = 1;
  1427. WriteAttributes[ 0 ].AttrVal.pAVal = &WriteVals[ 0 ];
  1428. if ( CurrentComputerDnsHostName ) {
  1429. LSAP_DS_SET_DS_ATTRIBUTE_STRING( &WriteAttributes[ 0 ], CurrentComputerDnsHostName );
  1430. }
  1431. AttrBlock.attrCount = 1;
  1432. AttrBlock.pAttr = WriteAttributes;
  1433. Status = LsapDsWriteByDsName(ServerPath,
  1434. CurrentComputerDnsHostName ?
  1435. LSAPDS_REPLACE_ATTRIBUTE :
  1436. LSAPDS_REMOVE_ATTRIBUTE,
  1437. &AttrBlock );
  1438. if ( !NT_SUCCESS( Status ) ) {
  1439. if ( CurrentComputerDnsHostName ) {
  1440. LsapDsDebugOut(( DEB_ERROR,
  1441. "Write of Dns domain name %ws on server object failed with 0x%lx\n",
  1442. CurrentComputerDnsHostName,
  1443. Status ));
  1444. } else {
  1445. LsapDsDebugOut(( DEB_ERROR,
  1446. "Removal of Dns domain name from server object failed with 0x%lx\n",
  1447. Status ));
  1448. }
  1449. }
  1450. }
  1451. }
  1452. SetDnsHostNameEnd:
  1453. Status = Status == STATUS_SUCCESS ? SavedStatus : Status;
  1454. if ( NT_SUCCESS(Status) ) {
  1455. if ( ARGUMENT_PRESENT( OldDnsHostName )) {
  1456. *OldDnsHostName = CurrentComputerDnsHostName;
  1457. CurrentComputerDnsHostName = NULL;
  1458. }
  1459. }
  1460. if ( CurrentComputerDnsHostName != NULL ) {
  1461. MIDL_user_free( CurrentComputerDnsHostName );
  1462. }
  1463. if ( MachinePaths != NULL ) {
  1464. LsapFreeLsaHeap( MachinePaths );
  1465. }
  1466. if ( AllocatedBuffer != NULL ) {
  1467. LsapFreeLsaHeap( AllocatedBuffer );
  1468. }
  1469. if ( TsActive ) {
  1470. LsapDsDeleteAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  1471. LSAP_DB_DS_OP_TRANSACTION,
  1472. NullObject,
  1473. CloseTransaction );
  1474. }
  1475. LsapExitFunc( "LsaISetClientDnsHostName", Status );
  1476. return Status;
  1477. }
  1478. NTSTATUS
  1479. LsaIQueryUpnSuffixes(
  1480. OUT PLSAP_UPN_SUFFIXES *UpnSuffixes
  1481. )
  1482. /*++
  1483. Routine Description:
  1484. This routine enumerates all of the configured UPN and SPN suffixes
  1485. Arguments:
  1486. UpnSuffixes - Returns a pointer to the UPN Suffixes
  1487. Buffer should be freed using LsaIFree_LSAP_UPN_SUFFIXES
  1488. Returns:
  1489. STATUS_SUCCESS - Success
  1490. STATUS_INVALID_DOMAIN_STATE - The Ds is not installed or running at the time of the call
  1491. STATUS_INSUFFICIENT_RESOURCES - A memory allocation failed
  1492. --*/
  1493. {
  1494. NTSTATUS Status;
  1495. BOOLEAN CloseTransaction = FALSE;
  1496. ULONG i;
  1497. ULONG j;
  1498. PDSNAME DsName;
  1499. BOOLEAN TsActive = FALSE;
  1500. PLSAP_UPN_SUFFIXES Names = NULL;
  1501. ULONG NameCount;
  1502. ULONG NameIndex;
  1503. //
  1504. // Build the list of attribute IDs we need based on the information
  1505. // class
  1506. //
  1507. ATTR UpnSuffixesAttrVals[] = {
  1508. {ATT_UPN_SUFFIXES, {0, NULL} },
  1509. {ATT_MS_DS_SPN_SUFFIXES, {0, NULL} },
  1510. };
  1511. ATTRBLOCK ReadBlock, ReturnedBlock = { 0 };
  1512. // WCHAR RdnBuffer[MAX_RDN_SIZE + 1];
  1513. // ULONG RdnLen;
  1514. // ATTRTYP RdnType;
  1515. LsarpReturnCheckSetup();
  1516. LsapEnterFunc( "LsaIQueryUpnSuffixes" );
  1517. //
  1518. // Make sure the DS is installed
  1519. //
  1520. if ( !LsaDsStateInfo.UseDs ) {
  1521. Status = STATUS_INVALID_DOMAIN_STATE;
  1522. goto Cleanup;
  1523. }
  1524. //
  1525. // See if we already have a transaction going
  1526. //
  1527. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  1528. LSAP_DB_DS_OP_TRANSACTION,
  1529. NullObject,
  1530. &CloseTransaction );
  1531. if ( !NT_SUCCESS( Status ) ) {
  1532. goto Cleanup;
  1533. }
  1534. TsActive = TRUE;;
  1535. //
  1536. // Read the required attributes from the parititions container object
  1537. //
  1538. ReadBlock.attrCount = sizeof(UpnSuffixesAttrVals) / sizeof(ATTR);
  1539. ReadBlock.pAttr = UpnSuffixesAttrVals;
  1540. Status = LsapDsReadByDsName( LsaDsStateInfo.DsPartitionsContainer,
  1541. 0,
  1542. &ReadBlock,
  1543. &ReturnedBlock );
  1544. //
  1545. // Allow for the case where the Partitions container doesn't exist.
  1546. //
  1547. if ( Status == STATUS_NOT_FOUND ) {
  1548. ReturnedBlock.attrCount = 0;
  1549. Status = STATUS_SUCCESS;
  1550. }
  1551. if ( !NT_SUCCESS(Status) ) {
  1552. goto Cleanup;
  1553. }
  1554. //
  1555. // Determine the number of suffixes to return
  1556. //
  1557. NameCount = 0;
  1558. for ( i = 0;
  1559. i < ReturnedBlock.attrCount;
  1560. i++) {
  1561. switch ( ReturnedBlock.pAttr[i].attrTyp ) {
  1562. case ATT_UPN_SUFFIXES:
  1563. case ATT_MS_DS_SPN_SUFFIXES:
  1564. NameCount += ReturnedBlock.pAttr[i].AttrVal.valCount;
  1565. break;
  1566. default:
  1567. Status = STATUS_INVALID_PARAMETER;
  1568. goto Cleanup;
  1569. }
  1570. }
  1571. //
  1572. // Allocate a block to return to the caller
  1573. //
  1574. Names = LsapAllocateLsaHeap( sizeof(LSAP_UPN_SUFFIXES) +
  1575. NameCount * sizeof(UNICODE_STRING) );
  1576. if ( Names == NULL ) {
  1577. Status = STATUS_INSUFFICIENT_RESOURCES;
  1578. goto Cleanup;
  1579. }
  1580. //
  1581. // Return the suffixes.
  1582. //
  1583. NameIndex = 0;
  1584. for ( i = 0;
  1585. i < ReturnedBlock.attrCount;
  1586. i++) {
  1587. switch ( ReturnedBlock.pAttr[i].attrTyp ) {
  1588. case ATT_UPN_SUFFIXES:
  1589. case ATT_MS_DS_SPN_SUFFIXES:
  1590. for ( j = 0; j < ReturnedBlock.pAttr[i].AttrVal.valCount; j++ ) {
  1591. Status = STATUS_SUCCESS;
  1592. LSAPDS_ALLOC_AND_COPY_STRING_TO_UNICODE_ON_SUCCESS(
  1593. Status,
  1594. &Names->Suffixes[NameIndex],
  1595. ReturnedBlock.pAttr[i].AttrVal.pAVal[ j ].pVal,
  1596. ReturnedBlock.pAttr[i].AttrVal.pAVal[ j ].valLen );
  1597. if ( !NT_SUCCESS(Status) ) {
  1598. goto Cleanup;
  1599. }
  1600. NameIndex++;
  1601. }
  1602. break;
  1603. default:
  1604. Status = STATUS_INVALID_PARAMETER;
  1605. goto Cleanup;
  1606. }
  1607. }
  1608. ASSERT( NameCount == NameIndex );
  1609. Names->SuffixCount = NameIndex;
  1610. Status = STATUS_SUCCESS;
  1611. //
  1612. // Free locally used resources
  1613. //
  1614. Cleanup:
  1615. //
  1616. // Destruction of the thread state will delete the memory alloced by the SearchNonUnique call
  1617. //
  1618. if ( TsActive ) {
  1619. LsapDsDeleteAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  1620. LSAP_DB_DS_OP_TRANSACTION,
  1621. NullObject,
  1622. CloseTransaction );
  1623. }
  1624. if ( !NT_SUCCESS( Status ) ) {
  1625. LsaIFree_LSAP_UPN_SUFFIXES( Names );
  1626. } else {
  1627. *UpnSuffixes = Names;
  1628. }
  1629. LsarpReturnPrologue();
  1630. LsapExitFunc( "LsaIQueryUpnSuffixes", Status );
  1631. return( Status );
  1632. }
  1633. VOID
  1634. LsaIFree_LSAP_UPN_SUFFIXES(
  1635. IN PLSAP_UPN_SUFFIXES UpnSuffixes
  1636. )
  1637. /*++
  1638. Routine Description:
  1639. This routine free the LSAP_SUBNET_INFO strcture returned from
  1640. LsaIQuerySubnetInfo.
  1641. Arguments:
  1642. SubnetInformation - Specifies a pointer to the subnet information.
  1643. Returns:
  1644. None.
  1645. --*/
  1646. {
  1647. ULONG i;
  1648. if ( UpnSuffixes != NULL ) {
  1649. for ( i=0; i<UpnSuffixes->SuffixCount; i++) {
  1650. if ( UpnSuffixes->Suffixes[i].Buffer != NULL ) {
  1651. LsapFreeLsaHeap( UpnSuffixes->Suffixes[i].Buffer );
  1652. }
  1653. }
  1654. LsapFreeLsaHeap( UpnSuffixes );
  1655. }
  1656. }
  1657. VOID
  1658. NTAPI
  1659. LsaINotifyNetlogonParametersChangeW(
  1660. IN LSAP_NETLOGON_PARAMETER Parameter,
  1661. IN DWORD dwType,
  1662. IN PWSTR lpData,
  1663. IN DWORD cbData
  1664. )
  1665. /*++
  1666. Routine Description:
  1667. A way for Netlogon to notify LSA of changes to the values under its
  1668. 'Parameters' key that Lsa cares about
  1669. Parameters:
  1670. Parameter the value that has changed
  1671. dwType type of value
  1672. lpData pointer to the data
  1673. cbData number of bytes in the lpData buffer
  1674. Returns:
  1675. Nothing
  1676. --*/
  1677. {
  1678. ASSERT( Parameter == LsaEmulateNT4 );
  1679. ASSERT( dwType == REG_DWORD );
  1680. ASSERT( lpData );
  1681. ASSERT( cbData );
  1682. if ( Parameter == LsaEmulateNT4 ) {
  1683. LsapDbState.EmulateNT4 = ( *( DWORD * )lpData != 0 );
  1684. }
  1685. return;
  1686. }