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.

1915 lines
49 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. dslayer.c
  5. Abstract:
  6. Implemntation of LSA/Ds interface and support routines
  7. Author:
  8. Mac McLain (MacM) Jan 17, 1997
  9. Environment:
  10. User Mode
  11. Revision History:
  12. --*/
  13. #include <lsapch2.h>
  14. #include <dbp.h>
  15. #include <md5.h>
  16. #define LSADSP_MAX_ATTRS_ON_CREATE 3
  17. NTSTATUS
  18. LsapDsInitAllocAsNeededEx(
  19. IN ULONG Options,
  20. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  21. OUT PBOOLEAN Reset
  22. )
  23. {
  24. NTSTATUS Status = STATUS_SUCCESS;
  25. LsapEnterFunc( "LsapDsInitAllocAsNeededEx" );
  26. *Reset = FALSE;
  27. //
  28. // Grab the lock
  29. //
  30. if ( !FLAG_ON( Options, LSAP_DB_NO_LOCK ) ) {
  31. LsapDbAcquireLockEx( ObjectTypeId,
  32. Options );
  33. }
  34. //
  35. // If the LSA has no thread state yet, OR
  36. // We aren't using Sam's transaction and
  37. // the LSA hasn't yet opened one,
  38. // do so now.
  39. //
  40. Status = ( *LsaDsStateInfo.DsFuncTable.pOpenTransaction ) ( Options );
  41. if ( NT_SUCCESS( Status ) ) {
  42. *Reset = TRUE;
  43. } else {
  44. if ( !FLAG_ON( Options, LSAP_DB_NO_LOCK ) ) {
  45. LsapDbReleaseLockEx( ObjectTypeId,
  46. Options );
  47. }
  48. }
  49. LsapDsDebugOut(( DEB_FTRACE, "Leaving LsapDsInitAllocAsNeededEx ( %lu ): 0x%lx\n",
  50. *Reset, Status ));
  51. return( Status );
  52. }
  53. VOID
  54. LsapDsDeleteAllocAsNeededEx(
  55. IN ULONG Options,
  56. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  57. IN BOOLEAN Reset
  58. )
  59. {
  60. LsapDsDeleteAllocAsNeededEx2(
  61. Options,
  62. ObjectTypeId,
  63. Reset,
  64. FALSE // Rollback Transaction
  65. );
  66. }
  67. VOID
  68. LsapDsDeleteAllocAsNeededEx2(
  69. IN ULONG Options,
  70. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId,
  71. IN BOOLEAN Reset,
  72. IN BOOLEAN RollbackTransaction
  73. )
  74. {
  75. LsapDsDebugOut(( DEB_FTRACE, "Entering LsapDsDeleteAllocAsNeededEx ( %lu )\n", Reset ));
  76. if ( Reset ) {
  77. if (RollbackTransaction)
  78. {
  79. ( *LsaDsStateInfo.DsFuncTable.pAbortTransaction )( Options );
  80. }
  81. else
  82. {
  83. ( *LsaDsStateInfo.DsFuncTable.pApplyTransaction )( Options );
  84. }
  85. }
  86. //
  87. // Release the lock if we had opened one
  88. //
  89. if ( !FLAG_ON( Options, LSAP_DB_NO_LOCK ) ) {
  90. LsapDbReleaseLockEx( ObjectTypeId,
  91. Options );
  92. }
  93. LsapDsDebugOut(( DEB_FTRACE, "LsapDsDeleteAllocAsNeededEx: 0\n" ));
  94. }
  95. NTSTATUS
  96. LsapDsReadObjectSD(
  97. IN LSAPR_HANDLE ObjectHandle,
  98. OUT PSECURITY_DESCRIPTOR *ppSD
  99. )
  100. /*++
  101. Routine Description:
  102. This function will ready the security descriptor from the specified object
  103. Arguments:
  104. ObjectHandle - Object to read the SD from
  105. ppSD -- Where the allocated security descriptor is returned. Allocated via
  106. LsapAllocateLsaHeap.
  107. Return Value:
  108. Pointer to allocated memory on success or NULL on failure
  109. --*/
  110. {
  111. NTSTATUS Status = STATUS_SUCCESS;
  112. LSAP_DB_ATTRIBUTE Attribute;
  113. BOOLEAN ReleaseState;
  114. LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
  115. LsapEnterFunc( "LsapDsReadObjectSD" );
  116. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  117. LSAP_DB_DS_OP_TRANSACTION,
  118. InternalHandle->ObjectTypeId,
  119. &ReleaseState );
  120. if ( !NT_SUCCESS( Status ) ) {
  121. LsapExitFunc( "LsapDsReadObjectSD", Status );
  122. return( Status );
  123. }
  124. //
  125. // Make sure we're coming in as DSA, so the access check that the DS does won't fail
  126. //
  127. LsapDsSetDsaFlags( TRUE );
  128. LsapDbInitializeAttributeDs( &Attribute,
  129. SecDesc,
  130. NULL,
  131. 0,
  132. FALSE );
  133. Status = LsapDsReadAttributes(
  134. (PUNICODE_STRING)&((LSAP_DB_HANDLE ) ObjectHandle)->PhysicalNameDs,
  135. LSAPDS_OP_NO_LOCK,
  136. &Attribute,
  137. 1 );
  138. if ( Status == STATUS_SUCCESS ) {
  139. *ppSD = LsapAllocateLsaHeap( Attribute.AttributeValueLength );
  140. if ( *ppSD == NULL ) {
  141. Status = STATUS_INSUFFICIENT_RESOURCES;
  142. } else {
  143. RtlCopyMemory( *ppSD, Attribute.AttributeValue, Attribute.AttributeValueLength );
  144. }
  145. MIDL_user_free( Attribute.AttributeValue );
  146. } else {
  147. *ppSD = NULL;
  148. }
  149. LsapDsDeleteAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  150. LSAP_DB_DS_OP_TRANSACTION,
  151. InternalHandle->ObjectTypeId,
  152. ReleaseState );
  153. LsapExitFunc( "LsapDsReadObjectSD", Status );
  154. return( Status );
  155. }
  156. NTSTATUS
  157. LsapDsTruncateNameToFitCN(
  158. IN PUNICODE_STRING OriginalName,
  159. OUT PUNICODE_STRING TruncatedName
  160. )
  161. /*++
  162. Routine Description
  163. This routine truncates the name to fix the 64 Char CN limit. The truncation
  164. algorithm uses an MD5 Hash to compute the last 16 chars, the first 47
  165. chars are left as they are. The 48'th char is a -. If the name is smaller
  166. than the same limit the original name is returned as is copied into a
  167. new buffer.
  168. Parameters
  169. OriginalName -- The original Name
  170. TruncatedName -- The name truncated if required
  171. Return Values
  172. STATUS_SUCCESS
  173. Other error codes that return a resource failure
  174. --*/
  175. {
  176. MD5_CTX Md5Context;
  177. ULONG i;
  178. #define MAX_CN_SIZE 64
  179. #define TO_HEX(x) (((x)<0xA)?(L'0'+(x)):(L'A'+(x)-0xA))
  180. //
  181. // Allocate memory to hold the new name
  182. //
  183. TruncatedName->Buffer = LsapAllocateLsaHeap(OriginalName->Length);
  184. if (NULL==TruncatedName->Buffer)
  185. {
  186. return(STATUS_INSUFFICIENT_RESOURCES);
  187. }
  188. if (OriginalName->Length<=MAX_CN_SIZE*sizeof(WCHAR))
  189. {
  190. //
  191. // Original Name fits in CN, just copy and return it
  192. //
  193. RtlCopyMemory(
  194. TruncatedName->Buffer,
  195. OriginalName->Buffer,
  196. OriginalName->Length
  197. );
  198. TruncatedName->Length = TruncatedName->MaximumLength = OriginalName->Length;
  199. return (STATUS_SUCCESS);
  200. }
  201. //
  202. // Name does not fit in, invent a unique suffix. This is done by
  203. // computing a MD5 checksum of the original name and
  204. // replacing the last 16 chars by hexprinted version of the lower
  205. // nibbles of the hash
  206. //
  207. MD5Init(&Md5Context);
  208. MD5Update(
  209. &Md5Context,
  210. (PUCHAR) OriginalName->Buffer,
  211. OriginalName->Length
  212. );
  213. MD5Final(&Md5Context);
  214. //
  215. // The new name is the first 46 chars of the original name followed
  216. // by a - and the checksum hex printed out behind. Only the low nibble
  217. // of each byte is used so that only 16 chars of space is taken up
  218. //
  219. RtlCopyMemory(
  220. TruncatedName->Buffer,
  221. OriginalName->Buffer,
  222. OriginalName->Length
  223. );
  224. TruncatedName->Buffer[MAX_CN_SIZE-MD5DIGESTLEN-2] = L'-';
  225. for (i=0;i<MD5DIGESTLEN;i++)
  226. {
  227. TruncatedName->Buffer[MAX_CN_SIZE-MD5DIGESTLEN+i-1] = TO_HEX((0xf & Md5Context.digest[i]));
  228. }
  229. TruncatedName->Length = TruncatedName->MaximumLength = MAX_CN_SIZE * sizeof(WCHAR);
  230. return STATUS_SUCCESS;
  231. }
  232. NTSTATUS
  233. LsapDsGetPhysicalObjectName(
  234. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  235. IN BOOLEAN ObjectShouldExist,
  236. IN PUNICODE_STRING LogicalNameU,
  237. OUT OPTIONAL PUNICODE_STRING PhysicalNameU
  238. )
  239. /*++
  240. Routine Description:
  241. This function returns the Physical Name of an object
  242. given an object information buffer. Memory will be allocated for
  243. the Unicode String Buffers that will receive the name(s).
  244. The Physical Name of an object is the full path of the object relative
  245. to the root ot the Database. It is computed by concatenating the Physical
  246. Name of the Container Object (if any), the Classifying Directory
  247. corresponding to the object type id, and the Logical Name of the
  248. object.
  249. <Physical Name of Object> =
  250. [<Physical Name of Container Object> "\"]
  251. [<Classifying Directory> "\"] <Logical Name of Object>
  252. If there is no Container Object (as in the case of the Policy object)
  253. the <Physical Name of Container Object> and following \ are omitted.
  254. If there is no Classifying Directory (as in the case of the Policy object)
  255. the <Classifying Directory> and following \ are omitted. If neither
  256. Container Object not Classifying Directory exist, the Logical and Physical
  257. names coincide.
  258. Note that memory is allocated by this routine for the output
  259. Unicode string buffer(s). When the output Unicode String(s) are no
  260. longer needed, the memory must be freed by call(s) to
  261. RtlFreeUnicodeString().
  262. Arguments:
  263. ObjectInformation - Pointer to object information containing as a minimum
  264. the object's Logical Name, Container Object's handle and object type
  265. id.
  266. DefaultName - If TRUE, use the default name for the object
  267. LogicalNameU - Optional pointer to Unicode String structure which will
  268. receive the Logical Name of the object. A buffer will be allocated
  269. by this routine for the name text. This memory must be freed when no
  270. longer needed by calling RtlFreeUnicodeString() wiht a pointer such
  271. as LogicalNameU to the Unicode String structure.
  272. PhysicalNameU - Optional pointer to Unicode String structure which will
  273. receive the Physical Name of the object. A buffer will be allocated by
  274. this routine for the name text. This memory must be freed when no
  275. longer needed by calling RtlFreeUnicodeString() with a pointer such as
  276. PhysicalNameU to the Unicode String structure.
  277. Return Value:
  278. NTSTATUS - Standard Nt Result Code
  279. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources to
  280. allocate the name string buffer for the Physical Name or
  281. Logical Name.
  282. STATUS_OBJECT_NAME_INVALID - Failed to produce the proper name
  283. --*/
  284. {
  285. NTSTATUS Status = STATUS_SUCCESS;
  286. LSAP_DB_OBJECT_TYPE_ID ObjectTypeId = ObjectInformation->ObjectTypeId;
  287. POBJECT_ATTRIBUTES ObjectAttributes = &ObjectInformation->ObjectAttributes;
  288. PDSNAME Root = NULL, NewDsName = NULL;
  289. PWSTR Name, LogicalName;
  290. PBYTE Buffer = NULL;
  291. UNICODE_STRING ObjectName, *Object=NULL;
  292. ULONG Length = 0, InitialLength;
  293. USHORT Len = 0, NameLen;
  294. BOOLEAN NameSet = FALSE;
  295. UNICODE_STRING TruncatedName;
  296. LsapEnterFunc( "LsapDsGetPhysicalObjectName" );
  297. RtlZeroMemory( &ObjectName, sizeof( UNICODE_STRING ) );
  298. RtlZeroMemory( &TruncatedName, sizeof( UNICODE_STRING ) );
  299. //
  300. // The stages go as follows:
  301. // Root DS domain path, obtained from LsaDsStateInfo
  302. // Any container path specific to the object type for trusted domain/secret objects
  303. // - or -
  304. // the domain policy path or local policy path if it's a local or domain policy object
  305. //
  306. switch ( ObjectTypeId ) {
  307. case TrustedDomainObject:
  308. Root = LsaDsStateInfo.DsSystemContainer;
  309. Object = LogicalNameU;
  310. if ( ObjectShouldExist ) {
  311. //
  312. // Get the name of the object by searching for it
  313. //
  314. Status = LsapDsTrustedDomainObjectNameForDomain( Object,
  315. FALSE,
  316. &NewDsName );
  317. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  318. Status = LsapDsTrustedDomainObjectNameForDomain( Object,
  319. TRUE,
  320. &NewDsName );
  321. }
  322. if ( NT_SUCCESS( Status ) ) {
  323. NameSet = TRUE;
  324. }
  325. }
  326. break;
  327. case NewTrustedDomainObject:
  328. Root = LsaDsStateInfo.DsSystemContainer;
  329. Object = LogicalNameU;
  330. break;
  331. case SecretObject:
  332. Root = LsaDsStateInfo.DsSystemContainer;
  333. Buffer = LsapAllocateLsaHeap( LogicalNameU->Length + sizeof( LSAP_DS_SECRET_POSTFIX ) -
  334. sizeof(LSA_GLOBAL_SECRET_PREFIX) + sizeof( WCHAR ) );
  335. if ( Buffer == NULL ) {
  336. Status = STATUS_INSUFFICIENT_RESOURCES;
  337. } else {
  338. Name = (PWSTR)LogicalNameU->Buffer + LSA_GLOBAL_SECRET_PREFIX_LENGTH;
  339. NameLen = LogicalNameU->Length - (LSA_GLOBAL_SECRET_PREFIX_LENGTH * sizeof(WCHAR));
  340. RtlCopyMemory( Buffer,
  341. Name,
  342. NameLen );
  343. if ( !ObjectInformation->ObjectAttributeNameOnly ) {
  344. RtlCopyMemory( Buffer + NameLen,
  345. LSAP_DS_SECRET_POSTFIX,
  346. sizeof( LSAP_DS_SECRET_POSTFIX ) );
  347. }
  348. RtlInitUnicodeString( &ObjectName, (PWSTR)Buffer );
  349. Object = &ObjectName;
  350. }
  351. break;
  352. default:
  353. Status = STATUS_INVALID_PARAMETER;
  354. break;
  355. }
  356. //
  357. // Build the physical name
  358. //
  359. if ( NT_SUCCESS ( Status ) ) {
  360. if ( !NameSet ) {
  361. //
  362. // Truncate the name if necessary to fit the common name
  363. // attribute in the schema
  364. //
  365. Status = LsapDsTruncateNameToFitCN(
  366. Object,
  367. &TruncatedName
  368. );
  369. if (!NT_SUCCESS(Status))
  370. {
  371. goto Error;
  372. }
  373. //
  374. // Allocate a default buffer to use...
  375. //
  376. InitialLength = LsapDsLengthAppendRdnLength( Root,
  377. Object->Length + 4 * sizeof( WCHAR ) );
  378. NewDsName = LsapAllocateLsaHeap( InitialLength );
  379. if ( NewDsName == NULL ) {
  380. Status = STATUS_INSUFFICIENT_RESOURCES;
  381. } else {
  382. Length = AppendRDN( Root,
  383. NewDsName,
  384. InitialLength,
  385. TruncatedName.Buffer,
  386. LsapDsGetUnicodeStringLenNoNull( &TruncatedName ) / sizeof( WCHAR ),
  387. ATT_COMMON_NAME );
  388. if ( Length > InitialLength ) {
  389. LsapFreeLsaHeap( NewDsName );
  390. NewDsName = LsapAllocateLsaHeap( Length );
  391. if ( NewDsName == NULL ) {
  392. Status = STATUS_INSUFFICIENT_RESOURCES;
  393. } else {
  394. #if DBG
  395. InitialLength = Length;
  396. #endif
  397. Length = AppendRDN( Root,
  398. NewDsName,
  399. InitialLength,
  400. TruncatedName.Buffer,
  401. LsapDsGetUnicodeStringLenNoNull( &TruncatedName ) /
  402. sizeof( WCHAR ),
  403. ATT_COMMON_NAME );
  404. if ( Length != 0 ) {
  405. Status = STATUS_OBJECT_NAME_INVALID;
  406. #if DBG
  407. LsapDsDebugOut(( DEB_ERROR,
  408. "Failed to build physical name for %wZ. We "
  409. "allocated %lu but needed %lu\n",
  410. Object,
  411. InitialLength,
  412. Length ));
  413. #endif
  414. }
  415. }
  416. }
  417. }
  418. //
  419. // If we are creating a trusted domain name, make sure that the name isn't alread
  420. // in use
  421. //
  422. if ( NT_SUCCESS( Status ) && ( ObjectTypeId == NewTrustedDomainObject ||
  423. ( ObjectTypeId == TrustedDomainObject && ObjectShouldExist == FALSE ) ) ) {
  424. Status = LsapDsVerifyObjectExistenceByDsName( NewDsName );
  425. if ( Status == STATUS_SUCCESS ) {
  426. Status = STATUS_OBJECT_NAME_COLLISION;
  427. } else if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  428. Status = STATUS_SUCCESS;
  429. }
  430. }
  431. }
  432. //
  433. // Now, we copy off the newly allocated dsname string, and return that
  434. //
  435. if ( NT_SUCCESS( Status ) ) {
  436. Length = ( LsapDsNameLenFromDsName( NewDsName ) *
  437. sizeof( WCHAR ) ) + sizeof( WCHAR );
  438. PhysicalNameU->Buffer = LsapAllocateLsaHeap( Length );
  439. if ( PhysicalNameU->Buffer == NULL ) {
  440. Status = STATUS_INSUFFICIENT_RESOURCES;
  441. } else {
  442. RtlCopyMemory( PhysicalNameU->Buffer,
  443. LsapDsNameFromDsName( NewDsName ),
  444. Length );
  445. RtlInitUnicodeString( PhysicalNameU,
  446. PhysicalNameU->Buffer );
  447. }
  448. }
  449. }
  450. Error:
  451. if ( ObjectTypeId == SecretObject ) {
  452. LsapFreeLsaHeap( Buffer );
  453. }
  454. if ( NewDsName != NULL ) {
  455. LsapFreeLsaHeap( NewDsName );
  456. }
  457. if ( TruncatedName.Buffer != NULL ) {
  458. LsapFreeLsaHeap( TruncatedName.Buffer );
  459. }
  460. LsapExitFunc( "LsapDsGetPhysicalObjectName", Status );
  461. return Status;
  462. }
  463. NTSTATUS
  464. LsapDsOpenObject(
  465. IN LSAP_DB_HANDLE ObjectHandle,
  466. IN ULONG OpenMode,
  467. OUT PVOID *pvKey
  468. )
  469. /*++
  470. Routine Description:
  471. Opens the object in the DS
  472. Arguments:
  473. ObjectHandle - Internal LSA object handle
  474. OpenMode - How to open the object
  475. pvKey - Where the key is returned
  476. Return Value:
  477. NTSTATUS - Standard Nt Result Code
  478. --*/
  479. {
  480. NTSTATUS Status = STATUS_SUCCESS;
  481. ATTR NameAttr;
  482. ATTRVAL NameVal;
  483. ATTRBLOCK NameBlock, ReturnBlock;
  484. PDSNAME SearchName = NULL;
  485. BOOLEAN ReleaseState = FALSE;
  486. LSAP_DB_HANDLE InternalHandle = ( LSAP_DB_HANDLE )ObjectHandle;
  487. BOOLEAN InitAllocSucceded = FALSE;
  488. ULONG ObjClass;
  489. LsapEnterFunc( "LsapDsOpenObject" );
  490. //
  491. // Ensure the handle is for one of the objects supported in the DS.
  492. //
  493. switch ( InternalHandle->ObjectTypeId ) {
  494. case TrustedDomainObject:
  495. ObjClass = CLASS_TRUSTED_DOMAIN;
  496. break;
  497. case SecretObject:
  498. ObjClass = CLASS_SECRET;
  499. break;
  500. default:
  501. ASSERT( FALSE );
  502. return STATUS_INVALID_PARAMETER;
  503. }
  504. //
  505. // Start a transaction.
  506. //
  507. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  508. LSAP_DB_DS_OP_TRANSACTION,
  509. InternalHandle->ObjectTypeId,
  510. &ReleaseState );
  511. if ( NT_SUCCESS( Status ) ) {
  512. InitAllocSucceded = TRUE;
  513. Status = LsapAllocAndInitializeDsNameFromUnicode(
  514. (PLSA_UNICODE_STRING)&ObjectHandle->PhysicalNameDs,
  515. &SearchName );
  516. }
  517. if ( NT_SUCCESS( Status ) ) {
  518. //
  519. // Check for the existence of the object
  520. //
  521. NameAttr.attrTyp = ATT_OBJECT_CLASS;
  522. NameAttr.AttrVal.valCount = 1;
  523. NameAttr.AttrVal.pAVal = &NameVal;
  524. NameVal.valLen = SearchName->structLen;
  525. NameVal.pVal = (PBYTE)SearchName;
  526. NameBlock.attrCount = 1;
  527. NameBlock.pAttr = &NameAttr;
  528. Status = LsapDsRead( &ObjectHandle->PhysicalNameDs,
  529. LSAPDS_READ_NO_LOCK,
  530. &NameBlock,
  531. &ReturnBlock);
  532. if ( NT_SUCCESS( Status ) ) {
  533. ULONG ReadVal;
  534. ReadVal = LSAP_DS_GET_DS_ATTRIBUTE_AS_ULONG( ReturnBlock.pAttr );
  535. if ( ReadVal != ObjClass ) {
  536. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  537. }
  538. }
  539. }
  540. if (InitAllocSucceded)
  541. {
  542. LsapDsDeleteAllocAsNeededEx( LSAP_DB_READ_ONLY_TRANSACTION |
  543. LSAP_DB_DS_OP_TRANSACTION,
  544. InternalHandle->ObjectTypeId,
  545. ReleaseState );
  546. }
  547. LsapExitFunc( "LsapDsOpenObject", Status );
  548. return( Status );
  549. }
  550. NTSTATUS
  551. LsapDsVerifyObjectExistenceByDsName(
  552. IN PDSNAME DsName
  553. )
  554. /*++
  555. Routine Description:
  556. Verifies if an object exists in the DS by opening it
  557. Arguments:
  558. DsName - pointer to an object's DS name
  559. Return Value:
  560. NTSTATUS - Standard Nt Result Code
  561. --*/
  562. {
  563. NTSTATUS Status = STATUS_SUCCESS;
  564. ATTR NameAttr;
  565. ATTRVAL NameVal;
  566. ATTRBLOCK NameBlock, ReturnBlock;
  567. BOOLEAN ReleaseState = FALSE;
  568. LsapEnterFunc( "LsapDsOpenObjectByDsName" );
  569. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_NO_LOCK,
  570. NullObject,
  571. &ReleaseState );
  572. if ( NT_SUCCESS( Status ) ) {
  573. //
  574. // Check for the existence of the object
  575. //
  576. NameAttr.attrTyp = ATT_OBJECT_CLASS;
  577. NameAttr.AttrVal.valCount = 1;
  578. NameAttr.AttrVal.pAVal = &NameVal;
  579. NameVal.valLen = 0;
  580. NameVal.pVal = NULL;
  581. NameBlock.attrCount = 1;
  582. NameBlock.pAttr = &NameAttr;
  583. Status = LsapDsReadByDsName( DsName,
  584. LSAPDS_READ_NO_LOCK,
  585. &NameBlock,
  586. &ReturnBlock);
  587. }
  588. LsapDsDeleteAllocAsNeededEx( LSAP_DB_NO_LOCK,
  589. NullObject,
  590. ReleaseState );
  591. LsapExitFunc( "LsapDsOpenObjectByDsName", Status );
  592. return( Status );
  593. }
  594. NTSTATUS
  595. LsapDsOpenTransaction(
  596. IN ULONG Options
  597. )
  598. /*++
  599. Routine Description:
  600. This function starts a transaction within the Ds.
  601. Arguments:
  602. Options - Options to use when opening the transaction. Valid values are:
  603. Return Value:
  604. NTSTATUS - Standard Nt Result Code
  605. Result codes are those returned from the Registry Transaction
  606. Package.
  607. --*/
  608. {
  609. NTSTATUS Status;
  610. PLSADS_PER_THREAD_INFO CurrentThreadInfo;
  611. LsapEnterFunc( "LsapDsOpenTransaction" );
  612. //
  613. // If this operation doesn't do a DS transaction,
  614. // we're done.
  615. //
  616. if ( Options & LSAP_DB_NO_DS_OP_TRANSACTION ) {
  617. Status = STATUS_SUCCESS;
  618. goto Cleanup;
  619. }
  620. //
  621. // Get an LSA thread state.
  622. //
  623. CurrentThreadInfo = LsapCreateThreadInfo();
  624. if ( CurrentThreadInfo == NULL ) {
  625. Status = STATUS_INSUFFICIENT_RESOURCES;
  626. goto Cleanup;
  627. }
  628. //
  629. // If we don't already have a valid thread state, create one
  630. //
  631. if ( CurrentThreadInfo->DsThreadStateUseCount == 0 ) {
  632. CurrentThreadInfo->InitialThreadState = THSave();
  633. Status = LsapDsMapDsReturnToStatus( THCreate( CALLERTYPE_LSA ) );
  634. if ( !NT_SUCCESS( Status ) ) {
  635. THRestore( CurrentThreadInfo->InitialThreadState );
  636. CurrentThreadInfo->InitialThreadState = NULL;
  637. LsapClearThreadInfo();
  638. goto Cleanup;
  639. }
  640. }
  641. CurrentThreadInfo->DsThreadStateUseCount ++;
  642. //
  643. // If we ever want to not really start a transaction here,
  644. // we have to ensure the same flag is passed to apply/abort and look
  645. // at the flag there.
  646. // if ( !FLAG_ON( Options, LSAP_DB_DS_OP_TRANSACTION ) ) {
  647. if ( CurrentThreadInfo->DsTransUseCount == 0 ) {
  648. if ( SampExistsDsTransaction() ) {
  649. ASSERT( !SampExistsDsTransaction() );
  650. DirTransactControl( TRANSACT_DONT_BEGIN_DONT_END );
  651. CurrentThreadInfo->DsOperationCount++;
  652. } else {
  653. DirTransactControl( TRANSACT_BEGIN_DONT_END );
  654. }
  655. LsapDsDebugOut(( DEB_TRACE,
  656. "DirTransactControl( TRANSACT_BEGIN_DONT_END ) in "
  657. "LsapDsOpenTransaction\n" ));
  658. }
  659. CurrentThreadInfo->DsTransUseCount++;
  660. // }
  661. LsapDsSetDsaFlags( TRUE );
  662. Status = STATUS_SUCCESS;
  663. Cleanup:
  664. LsapExitFunc( "LsapDsOpenTransaction", Status );
  665. return( Status );
  666. }
  667. NTSTATUS
  668. LsapDsOpenTransactionDummy(
  669. IN ULONG Options
  670. )
  671. {
  672. if ( Options & LSAP_DB_NO_DS_OP_TRANSACTION ) {
  673. return STATUS_SUCCESS;
  674. } else if ( !( Options & LSAP_DB_DS_OP_TRANSACTION )) {
  675. return STATUS_SUCCESS;
  676. } else {
  677. // ASSERT( FALSE ); // just so i can see who the culprit is, ignorable
  678. return STATUS_DIRECTORY_SERVICE_REQUIRED;
  679. }
  680. }
  681. NTSTATUS
  682. LsapDsApplyTransaction(
  683. IN ULONG Options
  684. )
  685. /*++
  686. Routine Description:
  687. This function applies a transaction within the LSA Database.
  688. Arguments:
  689. Options - Specifies optional actions to be taken. The following
  690. options are recognized, other options relevant to calling routines
  691. are ignored.
  692. LSAP_DB_NO_DS_OP_TRANSACTION - Nothing to do, get out
  693. Return Value:
  694. NTSTATUS - Standard Nt Result Code
  695. Result codes are those returned from the Registry Transaction
  696. Package.
  697. --*/
  698. {
  699. NTSTATUS Status = STATUS_SUCCESS, Status2;
  700. PLSADS_PER_THREAD_INFO CurrentThreadInfo;
  701. LsapEnterFunc( "LsapDsApplyTransaction" );
  702. //
  703. // If this operation doesn't do a DS transaction,
  704. // we're done.
  705. //
  706. if ( Options & LSAP_DB_NO_DS_OP_TRANSACTION ) {
  707. LsapExitFunc( "LsapDsApplyTransaction", 0 );
  708. return( STATUS_SUCCESS );
  709. }
  710. CurrentThreadInfo = LsapQueryThreadInfo();
  711. //
  712. // No thread info, no transaction
  713. //
  714. if ( CurrentThreadInfo == NULL ) {
  715. LsapExitFunc( "LsapDsApplyTransaction", 0 );
  716. return( STATUS_SUCCESS );
  717. }
  718. //
  719. // If we're doing a transaction,
  720. // decrement our count of embedded transactions.
  721. //
  722. if ( CurrentThreadInfo->DsTransUseCount > 0 ) {
  723. CurrentThreadInfo->DsTransUseCount--;
  724. //
  725. // If this is our last transaction,
  726. // commit it.
  727. //
  728. if ( CurrentThreadInfo->DsTransUseCount == 0 ) {
  729. if ( CurrentThreadInfo->DsOperationCount == 0 ) {
  730. //
  731. // The only way we should get here is if we inadvertently marked a current
  732. // "transaction" as active when it has never been used. As such, we can
  733. // simply reset the flag.
  734. //
  735. if ( !SampExistsDsTransaction() ) {
  736. DirTransactControl( TRANSACT_BEGIN_END );
  737. } else {
  738. ASSERT( SampExistsDsTransaction() );
  739. CurrentThreadInfo->DsOperationCount = 1;
  740. }
  741. }
  742. //
  743. // If operations have been made to the DS,
  744. // commit them now.
  745. //
  746. if ( CurrentThreadInfo->DsOperationCount > 0 ) {
  747. Status = LsapDsCauseTransactionToCommitOrAbort( TRUE );
  748. CurrentThreadInfo->DsOperationCount = 0;
  749. }
  750. }
  751. }
  752. //
  753. // If we have a DS thread state,
  754. // decrement our count of uses of that thread state.
  755. //
  756. if ( CurrentThreadInfo->DsThreadStateUseCount > 0 ) {
  757. CurrentThreadInfo->DsThreadStateUseCount --;
  758. //
  759. // If we're now done with our DS thread state,
  760. // destroy it.
  761. //
  762. if ( CurrentThreadInfo->DsThreadStateUseCount == 0 ) {
  763. Status2 = LsapDsMapDsReturnToStatus( THDestroy( ) );
  764. THRestore( CurrentThreadInfo->InitialThreadState );
  765. CurrentThreadInfo->InitialThreadState = NULL;
  766. ASSERT( NT_SUCCESS( Status2 ) );
  767. if ( NT_SUCCESS( Status ) ) {
  768. Status = Status2;
  769. }
  770. }
  771. }
  772. LsapClearThreadInfo();
  773. LsapExitFunc( "LsapDsApplyTransaction", Status );
  774. return( Status );
  775. }
  776. NTSTATUS
  777. LsapDsApplyTransactionDummy(
  778. IN ULONG Options
  779. )
  780. {
  781. return( STATUS_SUCCESS );
  782. }
  783. NTSTATUS
  784. LsapDsAbortTransaction(
  785. IN ULONG Options
  786. )
  787. /*++
  788. Routine Description:
  789. This function aborts a transaction within the LSA Database.
  790. WARNING: The Lsa Database must be in the locked state when this function
  791. is called.
  792. Arguments:
  793. Options - Options to use for aborting the transaction
  794. Return Value:
  795. NTSTATUS - Standard Nt Result Code
  796. Result codes are those returned from the Registry Transaction
  797. Package.
  798. --*/
  799. {
  800. NTSTATUS Status = STATUS_SUCCESS, Status2;
  801. PLSADS_PER_THREAD_INFO CurrentThreadInfo;
  802. LsapEnterFunc( "LsapDsAbortTransaction" );
  803. //
  804. // If this operation doesn't do a DS transaction,
  805. // we're done.
  806. //
  807. if ( Options & LSAP_DB_NO_DS_OP_TRANSACTION ) {
  808. LsapExitFunc( "LsapDsAbortTransaction", 0 );
  809. return( STATUS_SUCCESS );
  810. }
  811. //
  812. // No thread info, no transaction
  813. //
  814. CurrentThreadInfo = LsapQueryThreadInfo();
  815. if ( CurrentThreadInfo == NULL ) {
  816. LsapExitFunc( "LsapDsAbortTransaction", 0 );
  817. return( STATUS_SUCCESS );
  818. }
  819. //
  820. // If we're doing a transaction,
  821. // decrement our count of embedded transactions.
  822. //
  823. if ( CurrentThreadInfo->DsTransUseCount > 0 ) {
  824. CurrentThreadInfo->DsTransUseCount--;
  825. //
  826. // If this is our last transaction,
  827. // abort it.
  828. //
  829. if ( CurrentThreadInfo->DsTransUseCount == 0 ) {
  830. if ( CurrentThreadInfo->DsOperationCount > 0 ) {
  831. //
  832. // Since LsapDsCauseTransactionToCommitOrAbort will return an error
  833. // if it successfully aborts a transaction, we throw the error code away
  834. // We don't need to do anything with the transactions other than to ensure that
  835. // they fail. We'll ensure this by issuing a bad dir call.
  836. //
  837. LsapDsCauseTransactionToCommitOrAbort( FALSE );
  838. } else {
  839. //
  840. // We opened the transaction, but we never used it... Make sure to indicate
  841. // that we don't have one
  842. //
  843. ASSERT(!SampExistsDsTransaction());
  844. DirTransactControl( TRANSACT_BEGIN_END );
  845. }
  846. CurrentThreadInfo->DsOperationCount = 0;
  847. }
  848. }
  849. //
  850. // If we have a DS thread state,
  851. // decrement our count of uses of that thread state.
  852. //
  853. if ( CurrentThreadInfo->DsThreadStateUseCount > 0 ) {
  854. CurrentThreadInfo->DsThreadStateUseCount --;
  855. //
  856. // If we're now done with our DS thread state,
  857. // destroy it.
  858. //
  859. if ( CurrentThreadInfo->DsThreadStateUseCount == 0 ) {
  860. Status2 = LsapDsMapDsReturnToStatus( THDestroy( ) );
  861. THRestore( CurrentThreadInfo->InitialThreadState );
  862. CurrentThreadInfo->InitialThreadState = NULL;
  863. ASSERT( NT_SUCCESS( Status2 ) );
  864. if ( NT_SUCCESS( Status ) ) {
  865. Status = Status2;
  866. }
  867. }
  868. }
  869. LsapClearThreadInfo();
  870. LsapExitFunc( "LsapDsAbortTransaction", Status );
  871. return( Status );
  872. }
  873. NTSTATUS
  874. LsapDsAbortTransactionDummy(
  875. IN ULONG Options
  876. )
  877. {
  878. return( STATUS_SUCCESS );
  879. }
  880. NTSTATUS
  881. LsapDsCreateObject(
  882. IN PUNICODE_STRING ObjectPath,
  883. IN ULONG Flags,
  884. IN LSAP_DB_OBJECT_TYPE_ID ObjectType
  885. )
  886. {
  887. NTSTATUS Status = STATUS_SUCCESS;
  888. ULONG Value = 0;
  889. ULONG Items = 1;
  890. PBYTE NulLVal = NULL;
  891. PSECURITY_DESCRIPTOR pSD = NULL;
  892. ULONG cbSD = 0;
  893. ATTRTYP AttrType[LSADSP_MAX_ATTRS_ON_CREATE] = {
  894. ATT_OBJECT_CLASS,
  895. ATT_NT_SECURITY_DESCRIPTOR,
  896. 0
  897. };
  898. ULONG ObjClass;
  899. ATTRVAL Values[LSADSP_MAX_ATTRS_ON_CREATE] = {
  900. {sizeof(ULONG), (PUCHAR)&ObjClass},
  901. {0, (PUCHAR)NULL},
  902. {sizeof(ULONG), (PUCHAR)&Value}
  903. };
  904. switch ( ObjectType ) {
  905. case TrustedDomainObject:
  906. ObjClass = CLASS_TRUSTED_DOMAIN;
  907. break;
  908. case SecretObject:
  909. ObjClass = CLASS_SECRET;
  910. break;
  911. default:
  912. Status = STATUS_INVALID_PARAMETER;
  913. break;
  914. }
  915. if ( !NT_SUCCESS( Status ) ) {
  916. goto Exit;
  917. }
  918. if (Flags & LSAPDS_CREATE_WITH_SD) {
  919. //
  920. // Get the default security descriptor with the owner
  921. // set to the owner of the token of the caller
  922. //
  923. Status = LsapDsGetDefaultSecurityDescriptor(ObjClass,
  924. &pSD,
  925. &cbSD);
  926. if (NT_SUCCESS(Status)) {
  927. Values[Items].valLen = cbSD;
  928. Values[Items].pVal = pSD;
  929. Items++;
  930. }
  931. }
  932. if ( !NT_SUCCESS( Status ) ) {
  933. goto Exit;
  934. }
  935. if ( NT_SUCCESS( Status ) ) {
  936. Status = LsapDsCreateAndSetObject(
  937. ObjectPath,
  938. Flags,
  939. Items,
  940. AttrType,
  941. Values );
  942. }
  943. Exit:
  944. if (pSD) {
  945. LsapFreeLsaHeap(pSD);
  946. }
  947. LsapExitFunc( "LsapDsCreateObject", Status );
  948. return( Status );
  949. }
  950. NTSTATUS
  951. LsapDsDeleteObject(
  952. IN PUNICODE_STRING ObjectPath
  953. )
  954. {
  955. NTSTATUS Status = STATUS_SUCCESS;
  956. PDSNAME DsName;
  957. BOOLEAN ReleaseState;
  958. LsapEnterFunc( "LsapDsDeleteObject" );
  959. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_NO_LOCK,
  960. NullObject,
  961. &ReleaseState );
  962. if ( NT_SUCCESS( Status ) ) {
  963. Status = LsapAllocAndInitializeDsNameFromUnicode(
  964. ObjectPath,
  965. &DsName
  966. );
  967. if ( NT_SUCCESS( Status ) ) {
  968. Status = LsapDsRemove( DsName );
  969. THFree( DsName );
  970. }
  971. LsapDsDeleteAllocAsNeededEx( LSAP_DB_NO_LOCK,
  972. NullObject,
  973. ReleaseState );
  974. }
  975. LsapExitFunc( "LsapDsDeleteObject", Status );
  976. return( Status );
  977. }
  978. NTSTATUS
  979. LsapDsWriteAttributesByDsName(
  980. IN PDSNAME ObjectPath,
  981. IN PLSAP_DB_ATTRIBUTE Attributes,
  982. IN ULONG AttributeCount,
  983. IN ULONG Options
  984. )
  985. {
  986. NTSTATUS Status = STATUS_SUCCESS;
  987. ATTRBLOCK AttrBlock;
  988. PATTR Attrs;
  989. ULONG i, AttrBlockIndex = 0;
  990. LsapEnterFunc( "LsapDsWriteAttributesByDsName" );
  991. LsapDsSetDsaFlags( TRUE );
  992. //
  993. // Ok, first, build the list of Ds attributes
  994. //
  995. Attrs = LsapDsAlloc( sizeof( ATTR ) * AttributeCount );
  996. if ( Attrs == NULL ) {
  997. Status = STATUS_NO_MEMORY;
  998. } else {
  999. for ( i = 0 ; i < AttributeCount && NT_SUCCESS( Status ); i++ ) {
  1000. if ( !Attributes[ i ].PseudoAttribute ) {
  1001. Status = LsapDsLsaAttributeToDsAttribute( &Attributes[ i ],
  1002. &Attrs[ AttrBlockIndex++ ] );
  1003. }
  1004. }
  1005. if ( NT_SUCCESS( Status ) ) {
  1006. AttrBlock.attrCount = AttrBlockIndex;
  1007. AttrBlock.pAttr = Attrs;
  1008. //
  1009. // Now, simply write it out
  1010. //
  1011. Status = LsapDsWriteByDsName( ObjectPath,
  1012. LSAPDS_REPLACE_ATTRIBUTE | Options,
  1013. &AttrBlock );
  1014. }
  1015. }
  1016. LsapExitFunc( "LsapDsWriteAttributesByDsName", Status );
  1017. return( Status );
  1018. }
  1019. NTSTATUS
  1020. LsapDsWriteAttributes(
  1021. IN PUNICODE_STRING ObjectPath,
  1022. IN PLSAP_DB_ATTRIBUTE Attributes,
  1023. IN ULONG AttributeCount,
  1024. IN ULONG Options
  1025. )
  1026. {
  1027. NTSTATUS Status = STATUS_SUCCESS;
  1028. PDSNAME DsName = NULL;
  1029. BOOLEAN ReleaseState;
  1030. LsapEnterFunc( "LsapDsWriteAttributes" );
  1031. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_NO_LOCK,
  1032. NullObject,
  1033. &ReleaseState );
  1034. if ( !NT_SUCCESS( Status ) ) {
  1035. LsapExitFunc( "LsapDsWriteAttributes", Status );
  1036. return( Status );
  1037. }
  1038. //
  1039. // Build the DSName
  1040. //
  1041. Status = LsapAllocAndInitializeDsNameFromUnicode(
  1042. ObjectPath,
  1043. &DsName );
  1044. if ( NT_SUCCESS( Status ) ) {
  1045. Status = LsapDsWriteAttributesByDsName( DsName,
  1046. Attributes,
  1047. AttributeCount,
  1048. Options );
  1049. LsapDsFree( DsName );
  1050. }
  1051. LsapDsDeleteAllocAsNeededEx( LSAP_DB_NO_LOCK,
  1052. NullObject,
  1053. ReleaseState );
  1054. LsapExitFunc( "LsapDsWriteAttributes", Status );
  1055. return( Status );
  1056. }
  1057. NTSTATUS
  1058. LsapDsReadAttributesByDsName(
  1059. IN PDSNAME ObjectPath,
  1060. IN ULONG Options,
  1061. IN OUT PLSAP_DB_ATTRIBUTE Attributes,
  1062. IN ULONG AttributeCount
  1063. )
  1064. {
  1065. NTSTATUS Status = STATUS_SUCCESS;
  1066. ATTRBLOCK AttrBlock;
  1067. ATTRBLOCK ReadAttr;
  1068. PATTR Attrs;
  1069. ULONG i, j;
  1070. BOOLEAN ReleaseState;
  1071. LsapEnterFunc( "LsapDsReadAttributesByDsName" );
  1072. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_NO_LOCK,
  1073. NullObject,
  1074. &ReleaseState );
  1075. if ( !NT_SUCCESS( Status ) ) {
  1076. LsapExitFunc( "LsapDsReadAttributesByDsName", Status );
  1077. return( Status );
  1078. }
  1079. LsapDsSetDsaFlags( TRUE );
  1080. //
  1081. // Ok, first, build the list of Ds attributes
  1082. //
  1083. Attrs = LsapDsAlloc( sizeof( ATTR ) * AttributeCount );
  1084. if ( Attrs == NULL ) {
  1085. Status = STATUS_NO_MEMORY;
  1086. } else {
  1087. for ( i = 0 ; i < AttributeCount; i++ ) {
  1088. Attrs[i].attrTyp = Attributes[i].DsAttId;
  1089. Attrs[i].AttrVal.valCount = 0;
  1090. Attrs[i].AttrVal.pAVal = NULL;
  1091. }
  1092. AttrBlock.attrCount = AttributeCount;
  1093. AttrBlock.pAttr = Attrs;
  1094. //
  1095. // Now, simply write it out
  1096. //
  1097. Status = LsapDsReadByDsName( ObjectPath, Options, &AttrBlock, &ReadAttr );
  1098. //
  1099. // If that worked, fill in the rest of our attributes
  1100. //
  1101. if ( NT_SUCCESS( Status ) ) {
  1102. #if DBG
  1103. if ( AttributeCount != ReadAttr.attrCount ) {
  1104. LsapDsDebugOut(( DEB_WARN,
  1105. "LsapDsReadAttributes: Expected %lu attributes, got %lu\n",
  1106. AttributeCount, ReadAttr.attrCount ));
  1107. }
  1108. #endif
  1109. for ( j = 0; j < AttributeCount; j++ ) {
  1110. for ( i = 0 ; i < ReadAttr.attrCount && NT_SUCCESS( Status ); i++ ) {
  1111. if ( Attributes[ j ].DsAttId == ReadAttr.pAttr[ i ].attrTyp ) {
  1112. Status = LsapDsDsAttributeToLsaAttribute( ReadAttr.pAttr[i].AttrVal.pAVal,
  1113. &Attributes[j] );
  1114. break;
  1115. }
  1116. }
  1117. //
  1118. // If we got throught the loop and the value wasn't found, see if our attribute
  1119. // can default to zero. If not, it's an error
  1120. //
  1121. if ( i >= ReadAttr.attrCount ) {
  1122. if ( Attributes[ j ].CanDefaultToZero == TRUE ) {
  1123. Attributes[ j ].AttributeValue = NULL;
  1124. Attributes[ j ].AttributeValueLength = 0;
  1125. } else {
  1126. Status = STATUS_NOT_FOUND;
  1127. LsapDsDebugOut(( DEB_ERROR,
  1128. "Attribute %wZ not found on object %wZ\n",
  1129. &Attributes[ j ].AttributeName,
  1130. ObjectPath ));
  1131. }
  1132. }
  1133. }
  1134. } else if ( AttributeCount == 1 && Status == STATUS_NOT_FOUND ) {
  1135. //
  1136. // If we were only looking for one attribute, it's possible that its ok for that
  1137. // attribute to be null.
  1138. //
  1139. if ( Attributes[ 0 ].CanDefaultToZero ) {
  1140. Status = STATUS_SUCCESS;
  1141. Attributes[ 0 ].AttributeValue = NULL;
  1142. Attributes[ 0 ].AttributeValueLength = 0;
  1143. }
  1144. }
  1145. }
  1146. LsapDsDeleteAllocAsNeededEx( LSAP_DB_NO_LOCK,
  1147. NullObject,
  1148. ReleaseState );
  1149. LsapExitFunc( "LsapDsReadAttributesByDsName", Status );
  1150. return( Status );
  1151. }
  1152. NTSTATUS
  1153. LsapDsReadAttributes(
  1154. IN PUNICODE_STRING ObjectPath,
  1155. IN ULONG Options,
  1156. IN OUT PLSAP_DB_ATTRIBUTE Attributes,
  1157. IN ULONG AttributeCount
  1158. )
  1159. {
  1160. NTSTATUS Status = STATUS_SUCCESS;
  1161. PDSNAME DsName = NULL;
  1162. BOOLEAN ReleaseState;
  1163. LsapEnterFunc( "LsapDsReadAttributes" );
  1164. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_NO_LOCK,
  1165. NullObject,
  1166. &ReleaseState );
  1167. if ( !NT_SUCCESS( Status ) ) {
  1168. LsapExitFunc( "LsapDsReadAttributes", Status );
  1169. return( Status );
  1170. }
  1171. //
  1172. // Build the DSName
  1173. //
  1174. Status = LsapAllocAndInitializeDsNameFromUnicode(
  1175. ObjectPath,
  1176. &DsName );
  1177. if ( NT_SUCCESS( Status ) ) {
  1178. Status = LsapDsReadAttributesByDsName( DsName,
  1179. Options,
  1180. Attributes,
  1181. AttributeCount );
  1182. LsapDsFree( DsName );
  1183. }
  1184. LsapDsDeleteAllocAsNeededEx( LSAP_DB_NO_LOCK,
  1185. NullObject,
  1186. ReleaseState );
  1187. LsapExitFunc( "LsapDsReadAttributes", Status );
  1188. return( Status );
  1189. }
  1190. NTSTATUS
  1191. LsapDsDeleteAttributes(
  1192. IN PUNICODE_STRING ObjectPath,
  1193. IN OUT PLSAP_DB_ATTRIBUTE Attributes,
  1194. IN ULONG AttributeCount
  1195. )
  1196. {
  1197. NTSTATUS Status = STATUS_SUCCESS;
  1198. ATTRBLOCK AttrBlock;
  1199. PATTR Attrs;
  1200. ULONG i;
  1201. LsapEnterFunc( "LsapDsDeleteAttributes" );
  1202. LsapDsSetDsaFlags( TRUE );
  1203. //
  1204. // Ok, first, build the list of Ds attributes
  1205. //
  1206. Attrs = LsapDsAlloc( sizeof( ATTR ) * AttributeCount );
  1207. if ( Attrs == NULL ) {
  1208. Status = STATUS_NO_MEMORY;
  1209. } else {
  1210. for ( i = 0 ; i < AttributeCount && NT_SUCCESS( Status ); i++ ) {
  1211. Attributes[i].AttributeValueLength = 0;
  1212. Attributes[i].AttributeValue = NULL;
  1213. Status = LsapDsLsaAttributeToDsAttribute( &Attributes[i], &Attrs[i] );
  1214. }
  1215. if ( NT_SUCCESS( Status ) ) {
  1216. AttrBlock.attrCount = AttributeCount;
  1217. AttrBlock.pAttr = Attrs;
  1218. //
  1219. // Now, simply write it out
  1220. //
  1221. Status = LsapDsWrite( ObjectPath, AT_CHOICE_REMOVE_ATT, &AttrBlock );
  1222. }
  1223. }
  1224. LsapExitFunc( "LsapDsDeleteAttributes", Status );
  1225. return( Status );
  1226. }
  1227. NTSTATUS
  1228. LsapDsTrustedDomainSidToLogicalName(
  1229. IN PSID Sid,
  1230. OUT PUNICODE_STRING LogicalNameU
  1231. )
  1232. /*++
  1233. Routine Description:
  1234. This function generates the Logical Name (Internal LSA Database Name)
  1235. of a trusted domain object from its Sid. Currently, only the Relative
  1236. Arguments:
  1237. Sid - Pointer to the Sid to be looked up. It
  1238. LogicalNameU - Pointer to a Unicode String structure that will receive
  1239. the Logical Name. Note that memory for the string buffer in this
  1240. Unicode String will be allocated by this routine if successful. The
  1241. caller must free this memory after use by calling RtlFreeUnicodeString.
  1242. Return Value:
  1243. NTSTATUS - Standard Nt Status code
  1244. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
  1245. to allocate buffer for Unicode String name.
  1246. --*/
  1247. {
  1248. NTSTATUS Status;
  1249. ATTR SidAttr;
  1250. ATTRVAL SidVal;
  1251. ATTRBLOCK SidBlock;
  1252. PDSNAME FoundName = NULL;
  1253. BOOLEAN ReleaseState;
  1254. WCHAR RdnBuffer[MAX_RDN_SIZE + 1];
  1255. ULONG RdnLen;
  1256. ATTRBLOCK ReadBlock, ReturnedBlock;
  1257. ATTRTYP RdnType;
  1258. ATTR ReadAttr[] = {
  1259. {LsapDsAttributeIds[ LsapDsAttrTrustPartner ], {0, NULL} }
  1260. };
  1261. LsapEnterFunc( "LsapDsTrustedDomainSidToLogicalName" );
  1262. //
  1263. // First, verify that the given Sid is valid
  1264. //
  1265. if (!RtlValidSid( Sid )) {
  1266. LsapExitFunc( "LsapDsTrustedDomainSidToLogicalName", STATUS_INVALID_PARAMETER );
  1267. return( STATUS_INVALID_PARAMETER );
  1268. }
  1269. Status = LsapDsInitAllocAsNeededEx( LSAP_DB_DS_OP_TRANSACTION |
  1270. LSAP_DB_READ_ONLY_TRANSACTION,
  1271. TrustedDomainObject,
  1272. &ReleaseState );
  1273. if ( NT_SUCCESS( Status ) ) {
  1274. //
  1275. // Check for the existence of the object
  1276. //
  1277. SidAttr.attrTyp = ATT_SECURITY_IDENTIFIER;
  1278. SidAttr.AttrVal.valCount = 1;
  1279. SidAttr.AttrVal.pAVal = &SidVal;
  1280. SidVal.valLen = RtlLengthSid( Sid );
  1281. SidVal.pVal = (PBYTE)Sid;
  1282. SidBlock.attrCount = 1;
  1283. SidBlock.pAttr = &SidAttr;
  1284. Status = LsapDsSearchUnique( LSAPDS_SEARCH_LEVEL | LSAPDS_OP_NO_TRANS,
  1285. LsaDsStateInfo.DsSystemContainer,
  1286. &SidAttr,
  1287. 1,
  1288. &FoundName );
  1289. if ( NT_SUCCESS( Status ) ) {
  1290. ReadBlock.attrCount = sizeof( ReadAttr ) / sizeof( ATTR );
  1291. ReadBlock.pAttr = ReadAttr;
  1292. Status = LsapDsReadByDsName( FoundName,
  1293. LSAPDS_READ_NO_LOCK,
  1294. &ReadBlock,
  1295. &ReturnedBlock );
  1296. if ( NT_SUCCESS( Status ) && LogicalNameU ) {
  1297. LSAPDS_ALLOC_AND_COPY_STRING_TO_UNICODE_ON_SUCCESS(
  1298. Status,
  1299. LogicalNameU,
  1300. ReturnedBlock.pAttr[0].AttrVal.pAVal[ 0 ].pVal,
  1301. ReturnedBlock.pAttr[0].AttrVal.pAVal[ 0 ].valLen );
  1302. }
  1303. LsapFreeLsaHeap( FoundName );
  1304. }
  1305. LsapDsDeleteAllocAsNeededEx( LSAP_DB_DS_OP_TRANSACTION |
  1306. LSAP_DB_READ_ONLY_TRANSACTION,
  1307. TrustedDomainObject,
  1308. ReleaseState );
  1309. }
  1310. LsapExitFunc( "LsapDsTrustedDomainSidToLogicalName", Status );
  1311. return( Status );
  1312. }
  1313. VOID
  1314. LsapDsContinueTransaction(
  1315. VOID
  1316. )
  1317. /*++
  1318. Routine Description:
  1319. Call this function when we've just done a Dir* call and want to continue
  1320. the transaction.
  1321. Arguments:
  1322. None.
  1323. Return Value:
  1324. None.
  1325. --*/
  1326. {
  1327. PLSADS_PER_THREAD_INFO CurrentThreadInfo;
  1328. LsapEnterFunc( "LsapDsContinueTransaction" );
  1329. CurrentThreadInfo = LsapQueryThreadInfo();
  1330. ASSERT( CurrentThreadInfo != NULL && CurrentThreadInfo->DsThreadStateUseCount > 0 );
  1331. if ( CurrentThreadInfo != NULL ) {
  1332. //
  1333. // Tell the DS that there's more to come.
  1334. //
  1335. //
  1336. // Current code assumes every Dir*
  1337. // uses a transaction and if one is not started starts one. However, DirNotifyUnRegister
  1338. // doesn't start a transaction at all. And sometimes Dir* calls may not start
  1339. // a transaction due to memory shortage or the service is shutting down. Therefore
  1340. // it is best to check if there is actually a transaction or not.
  1341. //
  1342. if ( CurrentThreadInfo->DsTransUseCount && SampExistsDsTransaction() ) {
  1343. DirTransactControl( TRANSACT_DONT_BEGIN_DONT_END );
  1344. CurrentThreadInfo->DsOperationCount++;
  1345. }
  1346. }
  1347. LsapExitFunc( "LsapDsContinueTransaction", 0 );
  1348. }