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.

802 lines
19 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. reglayer.c
  5. Abstract:
  6. Implemntation of LSA/Registry 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. NTSTATUS
  16. LsapRegReadObjectSD(
  17. IN LSAPR_HANDLE ObjectHandle,
  18. OUT PSECURITY_DESCRIPTOR *ppSD
  19. )
  20. /*++
  21. Routine Description:
  22. This function will ready the security descriptor from the specified object
  23. Arguments:
  24. ObjectHandle - Object to read the SD from
  25. ppSD -- Where the allocated security descriptor is returned. Allocated via
  26. LsapAllocateLsaHeap.
  27. Return Value:
  28. Pointer to allocated memory on success or NULL on failure
  29. --*/
  30. {
  31. NTSTATUS Status = STATUS_SUCCESS;
  32. ULONG SecurityDescriptorLength = 0;
  33. Status = LsapDbReadAttributeObject(
  34. ObjectHandle,
  35. &LsapDbNames[SecDesc],
  36. NULL,
  37. &SecurityDescriptorLength
  38. );
  39. if ( NT_SUCCESS(Status ) ) {
  40. //
  41. // Allocate a buffer from the Lsa Heap for the existing object's SD.
  42. //
  43. *ppSD = LsapAllocateLsaHeap( SecurityDescriptorLength );
  44. if ( *ppSD == NULL ) {
  45. Status = STATUS_INSUFFICIENT_RESOURCES;
  46. } else {
  47. //
  48. // Read the SD. It is the value of the SecDesc subkey.
  49. //
  50. Status = LsapDbReadAttributeObject(
  51. ObjectHandle,
  52. &LsapDbNames[SecDesc],
  53. *ppSD,
  54. &SecurityDescriptorLength
  55. );
  56. if ( !NT_SUCCESS( Status ) ) {
  57. LsapFreeLsaHeap( *ppSD );
  58. *ppSD = NULL;
  59. }
  60. }
  61. }
  62. return( Status );
  63. }
  64. NTSTATUS
  65. LsapRegGetPhysicalObjectName(
  66. IN PLSAP_DB_OBJECT_INFORMATION ObjectInformation,
  67. IN PUNICODE_STRING LogicalNameU,
  68. OUT OPTIONAL PUNICODE_STRING PhysicalNameU
  69. )
  70. /*++
  71. Routine Description:
  72. This function returns the Physical Name of an object
  73. given an object information buffer. Memory will be allocated for
  74. the Unicode String Buffers that will receive the name(s).
  75. The Physical Name of an object is the full path of the object relative
  76. to the root ot the Database. It is computed by concatenating the Physical
  77. Name of the Container Object (if any), the Classifying Directory
  78. corresponding to the object type id, and the Logical Name of the
  79. object.
  80. <Physical Name of Object> =
  81. [<Physical Name of Container Object> "\"]
  82. [<Classifying Directory> "\"] <Logical Name of Object>
  83. If there is no Container Object (as in the case of the Policy object)
  84. the <Physical Name of Container Object> and following \ are omitted.
  85. If there is no Classifying Directory (as in the case of the Policy object)
  86. the <Classifying Directory> and following \ are omitted. If neither
  87. Container Object not Classifying Directory exist, the Logical and Physical
  88. names coincide.
  89. Note that memory is allocated by this routine for the output
  90. Unicode string buffer(s). When the output Unicode String(s) are no
  91. longer needed, the memory must be freed by call(s) to
  92. RtlFreeUnicodeString().
  93. Arguments:
  94. ObjectInformation - Pointer to object information containing as a minimum
  95. the object's Logical Name, Container Object's handle and object type
  96. id.
  97. LogicalNameU - Optional pointer to Unicode String structure which will
  98. receive the Logical Name of the object. A buffer will be allocated
  99. by this routine for the name text. This memory must be freed when no
  100. longer needed by calling RtlFreeUnicodeString() wiht a pointer such
  101. as LogicalNameU to the Unicode String structure.
  102. PhysicalNameU - Optional pointer to Unicode String structure which will
  103. receive the Physical Name of the object. A buffer will be allocated by
  104. this routine for the name text. This memory must be freed when no
  105. longer needed by calling RtlFreeUnicodeString() with a pointer such as
  106. PhysicalNameU to the Unicode String structure.
  107. Return Value:
  108. NTSTATUS - Standard Nt Result Code
  109. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources to
  110. allocate the name string buffer for the Physical Name or
  111. Logical Name.
  112. --*/
  113. {
  114. NTSTATUS Status;
  115. PUNICODE_STRING ContainerPhysicalNameU = NULL;
  116. PUNICODE_STRING ClassifyingDirU = NULL;
  117. UNICODE_STRING IntermediatePath1U;
  118. PUNICODE_STRING JoinedPath1U = &IntermediatePath1U;
  119. LSAP_DB_OBJECT_TYPE_ID ObjectTypeId = ObjectInformation->ObjectTypeId;
  120. POBJECT_ATTRIBUTES ObjectAttributes = &ObjectInformation->ObjectAttributes;
  121. //
  122. // Initialize
  123. //
  124. RtlInitUnicodeString( &IntermediatePath1U, NULL );
  125. //
  126. // The Physical Name of the object is requested. Construct this
  127. // in stages. First, get the Container Object Physical Name from
  128. // the handle stored inside ObjectAttributes.
  129. //
  130. if (ObjectAttributes->RootDirectory != NULL) {
  131. ContainerPhysicalNameU =
  132. &(((LSAP_DB_HANDLE)
  133. ObjectAttributes->RootDirectory)->PhysicalNameU);
  134. }
  135. //
  136. // Next, get the Classifying Directory name appropriate to the
  137. // object type.
  138. //
  139. if (LsapDbContDirs[ObjectTypeId].Length != 0) {
  140. ClassifyingDirU = &LsapDbContDirs[ObjectTypeId];
  141. }
  142. //
  143. // Now join the Physical Name of the Container Object and Classifying
  144. // Directory together. If there is no Container Object and no
  145. // Classifying Directory, just set the result to NULL.
  146. //
  147. if (ContainerPhysicalNameU == NULL && ClassifyingDirU == NULL) {
  148. JoinedPath1U = NULL;
  149. } else {
  150. Status = LsapDbJoinSubPaths(
  151. ContainerPhysicalNameU,
  152. ClassifyingDirU,
  153. JoinedPath1U
  154. );
  155. if (!NT_SUCCESS(Status)) {
  156. goto GetNamesError;
  157. }
  158. }
  159. //
  160. // Now join the Physical Name of the Containing Object, Classifying
  161. // Directory and Logical Name of the object together. Note that
  162. // JoinedPath1U may be NULL, but LogicalNameU is never NULL.
  163. //
  164. Status = LsapDbJoinSubPaths(
  165. JoinedPath1U,
  166. LogicalNameU,
  167. PhysicalNameU
  168. );
  169. if (JoinedPath1U != NULL) {
  170. RtlFreeUnicodeString( JoinedPath1U );
  171. JoinedPath1U = NULL; // so we don't try to free it again
  172. }
  173. if (!NT_SUCCESS(Status)) {
  174. goto GetNamesError;
  175. }
  176. goto GetNamesFinish;
  177. GetNamesError:
  178. //
  179. // If necessary, free any string buffer allocated to JoinedPath1U
  180. //
  181. if (JoinedPath1U != NULL) {
  182. RtlFreeUnicodeString( JoinedPath1U );
  183. }
  184. GetNamesFinish:
  185. return( Status );
  186. }
  187. NTSTATUS
  188. LsapRegOpenObject(
  189. IN LSAP_DB_HANDLE ObjectHandle,
  190. IN ULONG OpenMode,
  191. OUT PVOID *pvKey
  192. )
  193. /*++
  194. Routine Description:
  195. Opens the object in the LSA registry database
  196. Arguments:
  197. ObjectHandle - Internal LSA object handle
  198. OpenMode - How to open the object
  199. pvKey - Where the key is returned
  200. Return Value:
  201. NTSTATUS - Standard Nt Result Code
  202. --*/
  203. {
  204. NTSTATUS Status;
  205. OBJECT_ATTRIBUTES OpenKeyObjectAttributes;
  206. //
  207. // Setup Object Attributes structure for opening the Registry key of
  208. // the object. Specify as path the Physical Name of the object, this
  209. // being the path of the object's Registry Key relative to the
  210. // LSA Database root key.
  211. //
  212. InitializeObjectAttributes(
  213. &OpenKeyObjectAttributes,
  214. &(ObjectHandle->PhysicalNameU),
  215. OBJ_CASE_INSENSITIVE,
  216. LsapDbState.DbRootRegKeyHandle,
  217. NULL
  218. );
  219. //
  220. // Now attempt to open the object's Registry Key. Store the Registry
  221. // Key handle in the object's handle.
  222. //
  223. Status = RtlpNtOpenKey(
  224. (PHANDLE) pvKey,
  225. KEY_READ | KEY_WRITE,
  226. &OpenKeyObjectAttributes,
  227. 0L
  228. );
  229. return( Status );
  230. }
  231. NTSTATUS
  232. LsapRegOpenTransaction(
  233. )
  234. /*++
  235. Routine Description:
  236. This function starts a transaction within the LSA Database.
  237. WARNING: The Lsa Database must be in the locked state when this function
  238. is called.
  239. Arguments:
  240. None.
  241. Return Value:
  242. NTSTATUS - Standard Nt Result Code
  243. Result codes are those returned from the Registry Transaction
  244. Package.
  245. --*/
  246. {
  247. NTSTATUS Status = STATUS_SUCCESS;
  248. LsapDsDebugOut(( DEB_FTRACE, "LsapRegOpenTransaction\n" ));
  249. LsapDbLockAcquire( &LsapDbState.RegistryLock );
  250. ASSERT( LsapDbState.RegistryTransactionOpen == FALSE );
  251. Status = RtlStartRXact(LsapDbState.RXactContext);
  252. ASSERT( NT_SUCCESS( Status ) || Status == STATUS_NO_MEMORY );
  253. if ( NT_SUCCESS( Status ) ) {
  254. LsapDbState.RegistryTransactionOpen = TRUE;
  255. LsapDbState.RegistryModificationCount = 0;
  256. } else {
  257. LsapDbLockRelease( &LsapDbState.RegistryLock );
  258. }
  259. LsapDsDebugOut(( DEB_FTRACE, "LsapRegOpenTransaction: 0x%lx\n", Status ));
  260. return Status;
  261. }
  262. NTSTATUS
  263. LsapRegApplyTransaction(
  264. )
  265. /*++
  266. Routine Description:
  267. This function applies a transaction within the LSA Database.
  268. WARNING: The Lsa Database must be in the locked state when this function
  269. is called.
  270. Arguments:
  271. ObjectHandle - Handle to an LSA object. This is expected to have
  272. already been validated.
  273. Options - Specifies optional actions to be taken. The following
  274. options are recognized, other options relevant to calling routines
  275. are ignored.
  276. LSAP_DB_OMIT_REPLICATOR_NOTIFICATION - Omit notification to
  277. Replicator.
  278. Return Value:
  279. NTSTATUS - Standard Nt Result Code
  280. Result codes are those returned from the Registry Transaction
  281. Package.
  282. --*/
  283. {
  284. NTSTATUS Status = STATUS_SUCCESS;
  285. LsapDsDebugOut(( DEB_FTRACE, "LsapRegApplyTransaction\n" ));
  286. //
  287. ASSERT( LsapDbState.RegistryTransactionOpen == TRUE );
  288. //
  289. // Apply the Registry Transaction.
  290. //
  291. if ( LsapDbState.RegistryModificationCount > 0 ) {
  292. Status = RtlApplyRXact(LsapDbState.RXactContext);
  293. } else {
  294. Status = RtlAbortRXact(LsapDbState.RXactContext);
  295. }
  296. if ( NT_SUCCESS( Status ) ) {
  297. LsapDbState.RegistryTransactionOpen = FALSE;
  298. LsapDbState.RegistryModificationCount = 0;
  299. LsapDbLockRelease( &LsapDbState.RegistryLock );
  300. }
  301. LsapDsDebugOut(( DEB_FTRACE, "LsapRegApplyTransaction: 0x%lx\n", Status ));
  302. return( Status );
  303. }
  304. NTSTATUS
  305. LsapRegAbortTransaction(
  306. )
  307. /*++
  308. Routine Description:
  309. This function aborts a transaction within the LSA Database.
  310. WARNING: The Lsa Database must be in the locked state when this function
  311. is called.
  312. Arguments:
  313. None.
  314. Return Value:
  315. NTSTATUS - Standard Nt Result Code
  316. Result codes are those returned from the Registry Transaction
  317. Package.
  318. --*/
  319. {
  320. NTSTATUS Status = STATUS_SUCCESS;
  321. LsapDsDebugOut(( DEB_FTRACE, "LsapRegAbortTransaction\n" ));
  322. ASSERT( LsapDbState.RegistryTransactionOpen == TRUE );
  323. Status = RtlAbortRXact(LsapDbState.RXactContext);
  324. if ( NT_SUCCESS( Status ) ) {
  325. LsapDbState.RegistryTransactionOpen = FALSE;
  326. LsapDbState.RegistryModificationCount = 0;
  327. }
  328. ASSERT( NT_SUCCESS( Status ) );
  329. LsapDbLockRelease( &LsapDbState.RegistryLock );
  330. LsapDsDebugOut(( DEB_FTRACE, "LsapRegAbortTransaction: 0x%lx\n", Status ));
  331. return( Status );
  332. }
  333. NTSTATUS
  334. LsapRegCreateObject(
  335. IN PUNICODE_STRING ObjectPath,
  336. IN LSAP_DB_OBJECT_TYPE_ID ObjectType
  337. )
  338. {
  339. NTSTATUS Status;
  340. LsapDsDebugOut(( DEB_FTRACE, "LsapRegCreateObject\n" ));
  341. Status = RtlAddActionToRXact(
  342. LsapDbState.RXactContext,
  343. RtlRXactOperationSetValue,
  344. ObjectPath,
  345. ObjectType,
  346. NULL, // No Key Value needed
  347. 0L
  348. );
  349. if ( NT_SUCCESS( Status ) ) {
  350. LsapDbState.RegistryModificationCount++;
  351. }
  352. LsapDsDebugOut(( DEB_FTRACE, "LsapRegCreateObjectL 0x%lx\n", Status ));
  353. return( Status );
  354. }
  355. NTSTATUS
  356. LsapRegDeleteObject(
  357. IN PUNICODE_STRING ObjectPath
  358. )
  359. {
  360. NTSTATUS Status;
  361. LsapDsDebugOut(( DEB_FTRACE, "LsapRegDeleteObject\n" ));
  362. Status = RtlAddActionToRXact(
  363. LsapDbState.RXactContext,
  364. RtlRXactOperationDelete,
  365. ObjectPath,
  366. 0L,
  367. NULL,
  368. 0
  369. );
  370. if ( NT_SUCCESS( Status ) ) {
  371. LsapDbState.RegistryModificationCount++;
  372. }
  373. LsapDsDebugOut(( DEB_FTRACE, "LsapRegDeleteObject: 0x%lx\n", Status ));
  374. return( Status );
  375. }
  376. NTSTATUS
  377. LsapRegWriteAttribute(
  378. IN PUNICODE_STRING AttributePath,
  379. IN PVOID pvAttribute,
  380. IN ULONG AttributeLength
  381. )
  382. {
  383. NTSTATUS Status;
  384. LsapDsDebugOut(( DEB_FTRACE, "LsapRegWriteAttribute\n" ));
  385. Status = RtlAddActionToRXact(
  386. LsapDbState.RXactContext,
  387. RtlRXactOperationSetValue,
  388. AttributePath,
  389. 0L,
  390. pvAttribute,
  391. AttributeLength
  392. );
  393. if ( NT_SUCCESS( Status ) ) {
  394. LsapDbState.RegistryModificationCount++;
  395. }
  396. LsapDsDebugOut(( DEB_FTRACE, "LsapRegWriteAttribute: 0x%lx\n", Status ));
  397. return( Status );
  398. }
  399. NTSTATUS
  400. LsapRegDeleteAttribute(
  401. IN PUNICODE_STRING AttributePath,
  402. IN BOOLEAN DeleteSecurely,
  403. IN ULONG AttributeLength
  404. )
  405. /*++
  406. Routine Description:
  407. Deletes a registry attribute
  408. Arguments:
  409. AttributePath full pathname of attribute to delete
  410. DeleteSecurely fill value with zero prior to deletion?
  411. AttributeLength number of bytes to fill with zero (must be equal to
  412. actual length of the attribute for secure deletion to
  413. work); ignored if DeleteSecurely is FALSE
  414. Returns:
  415. STATUS_SUCCESS if happy
  416. STATUS_ error code otherwise
  417. --*/
  418. {
  419. NTSTATUS Status;
  420. PBYTE Buffer = NULL;
  421. LsapDsDebugOut(( DEB_FTRACE, "LsapRegDeleteAttribute\n" ));
  422. if ( DeleteSecurely &&
  423. AttributeLength > 0 ) {
  424. Buffer = ( PBYTE )LsapAllocateLsaHeap( AttributeLength );
  425. if ( Buffer == NULL ) {
  426. return STATUS_INSUFFICIENT_RESOURCES;
  427. }
  428. //
  429. // NOTE: LsapAllocateLsaHeap returns memory that is zero-filled
  430. // but even if it didn't, filling the secret value with
  431. // random junk is just as good
  432. //
  433. Status = LsapRegWriteAttribute(
  434. AttributePath,
  435. Buffer,
  436. AttributeLength
  437. );
  438. if ( !NT_SUCCESS( Status )) {
  439. LsapFreeLsaHeap( Buffer );
  440. return Status;
  441. }
  442. }
  443. Status = RtlAddActionToRXact(
  444. LsapDbState.RXactContext,
  445. RtlRXactOperationDelete,
  446. AttributePath,
  447. 0L,
  448. NULL,
  449. 0
  450. );
  451. if ( NT_SUCCESS( Status ) ) {
  452. LsapDbState.RegistryModificationCount++;
  453. }
  454. LsapDsDebugOut(( DEB_FTRACE, "LsapRegDeleteAttribute: 0x%lx\n", Status ));
  455. LsapFreeLsaHeap( Buffer );
  456. return( Status );
  457. }
  458. NTSTATUS
  459. LsapRegReadAttribute(
  460. IN LSAPR_HANDLE ObjectHandle,
  461. IN PUNICODE_STRING AttributeName,
  462. IN OPTIONAL PVOID AttributeValue,
  463. IN OUT PULONG AttributeValueLength
  464. )
  465. {
  466. //
  467. // The LSA Database is implemented as a subtree of the Configuration
  468. // Registry. In this implementation, Lsa Database objects correspond
  469. // to Registry keys and "attributes" and their "values" correspond to
  470. // Registry "subkeys" and "values" of the Registry key representing the
  471. // object.
  472. //
  473. NTSTATUS Status, SecondaryStatus;
  474. ULONG SubKeyValueActualLength;
  475. OBJECT_ATTRIBUTES ObjectAttributes;
  476. HANDLE SubKeyHandle = NULL;
  477. LSAP_DB_HANDLE InternalHandle = (LSAP_DB_HANDLE) ObjectHandle;
  478. //
  479. // Reading an attribute of an object is simpler than writing one,
  480. // because the Registry Transaction package is not used. Since an
  481. // attribute is stored as the value of a subkey of the object's
  482. // Registry Key, we can simply call the Registry API RtlpNtReadKey
  483. // specifying the relative name of the subkey and the parent key's
  484. // handle.
  485. //
  486. // Prior to opening the subkey in the Registry, setup ObjectAttributes
  487. // containing the SubKey name and the Registry Handle for the LSA Database
  488. // Root.
  489. //
  490. InitializeObjectAttributes(
  491. &ObjectAttributes,
  492. AttributeName,
  493. OBJ_CASE_INSENSITIVE,
  494. InternalHandle->KeyHandle,
  495. NULL
  496. );
  497. //
  498. // Open the subkey
  499. //
  500. Status = RtlpNtOpenKey(
  501. &SubKeyHandle,
  502. KEY_READ,
  503. &ObjectAttributes,
  504. 0L
  505. );
  506. if (!NT_SUCCESS(Status)) {
  507. SubKeyHandle = NULL; //For error processing
  508. return(Status);
  509. }
  510. //
  511. // Now query the size of the buffer required to read the subkey's
  512. // value.
  513. //
  514. SubKeyValueActualLength = *AttributeValueLength;
  515. //
  516. // If a NULL buffer parameter has been supplied or the size of the
  517. // buffer given is 0, this is just a size query.
  518. //
  519. if (!ARGUMENT_PRESENT(AttributeValue) || *AttributeValueLength == 0) {
  520. Status = RtlpNtQueryValueKey(
  521. SubKeyHandle,
  522. NULL,
  523. NULL,
  524. &SubKeyValueActualLength,
  525. NULL
  526. );
  527. if ((Status == STATUS_BUFFER_OVERFLOW) || NT_SUCCESS(Status)) {
  528. *AttributeValueLength = SubKeyValueActualLength;
  529. Status = STATUS_SUCCESS;
  530. goto ReadAttError;
  531. } else {
  532. goto ReadAttError;
  533. }
  534. }
  535. //
  536. // Supplied buffer is large enough to hold the SubKey's value.
  537. // Query the value.
  538. //
  539. Status = RtlpNtQueryValueKey(
  540. SubKeyHandle,
  541. NULL,
  542. AttributeValue,
  543. &SubKeyValueActualLength,
  544. NULL
  545. );
  546. if( (Status == STATUS_BUFFER_OVERFLOW) || NT_SUCCESS(Status) ) {
  547. //
  548. // Return the length of the Sub Key.
  549. //
  550. *AttributeValueLength = SubKeyValueActualLength;
  551. }
  552. ReadAttFinish:
  553. //
  554. // If necessary, close the Sub Key
  555. //
  556. if (SubKeyHandle != NULL) {
  557. SecondaryStatus = NtClose( SubKeyHandle );
  558. }
  559. return(Status);
  560. ReadAttError:
  561. goto ReadAttFinish;
  562. }