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.

827 lines
22 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. dbpob.c
  5. Abstract:
  6. LSA Database Object Manager - Private Routines
  7. These routines perform low-level functions private to the LSA Database
  8. Object Manager.
  9. Author:
  10. Scott Birrell (ScottBi) January 8, 1992
  11. Environment:
  12. Revision History:
  13. --*/
  14. #include <lsapch2.h>
  15. #include "dbp.h"
  16. NTSTATUS
  17. LsapDbLogicalToPhysicalSubKey(
  18. IN LSAPR_HANDLE ObjectHandle,
  19. OUT PUNICODE_STRING PhysicalSubKeyNameU,
  20. IN PUNICODE_STRING LogicalSubKeyNameU
  21. )
  22. /*++
  23. Routine Description:
  24. This routine converts a Logical Name of a subkey of an open object to
  25. the corresponding Physical Name. The Physical Name of a subkey is the
  26. hierarchic Registry key name relative to the Registry Key corresponding
  27. to the LSA Database root object. It is constructed by extracting the
  28. Physical Name of the object from its handle and appending "\" and the
  29. given Logical SubKey name.
  30. Arguments:
  31. ObjectHandle - Handle to open object from an LsapDbOpenObject call.
  32. PhysicalSubKeyNameU - Pointer to Unicode string that will receive the
  33. Physical Name of the subkey.
  34. LogicalSubKeyNameU - Pointer to Unicode string that contains the
  35. Logical name of the subkey.
  36. Return Value:
  37. NTSTATUS - Standard Nt Result Code
  38. STATUS_INSUFFICIENT_RESOURCES - Not enough system resources to
  39. allocate intermediate and final string buffers needed.
  40. --*/
  41. {
  42. NTSTATUS Status;
  43. LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
  44. Status = LsapDbJoinSubPaths(
  45. &Handle->PhysicalNameU,
  46. LogicalSubKeyNameU,
  47. PhysicalSubKeyNameU
  48. );
  49. return Status;
  50. }
  51. NTSTATUS
  52. LsapDbJoinSubPaths(
  53. IN PUNICODE_STRING MajorSubPathU,
  54. IN PUNICODE_STRING MinorSubPathU,
  55. OUT PUNICODE_STRING JoinedPathU
  56. )
  57. /*++
  58. Routine Description:
  59. This function joins together two parts of a Regsitry SubPath, inserting
  60. a "\" as a separator. The Minor SubPath must not begin with a "\".
  61. Either or both sub path components may be NULL. Except where both
  62. sub path components are NULL, memory is always allocated for the output
  63. buffer. This memory must be freed when no longer required by calling
  64. RtlFreeUnicodeString() on the output string.
  65. Arguments:
  66. MajorSubPathU - Pointer to Unicode String containing an absolute or
  67. relative subpath.
  68. MinorSubPathU - Pointer to Unicode String containing a relative
  69. subpath.
  70. JoinedPathU - Pointer to Unicode String that will receive the joined
  71. path. Memory will be allocated for the JoinedPath buffer.
  72. Return Value:
  73. NTSTATUS - Standard Nt Result Code
  74. STATUS_INSUFFICIENT_RESOURCES - Not enough system resources to
  75. allocate intermediate and final string buffers needed.
  76. --*/
  77. {
  78. NTSTATUS Status = STATUS_SUCCESS;
  79. USHORT JoinedPathLength;
  80. //
  81. // Compute the size needed for the Joined Sub Path string.
  82. // The Joined Sub Path has the following form:
  83. //
  84. // <Major Sub Path> + L"\" + <Minor Sub Path>
  85. //
  86. // where the "+" operator denotes concatenation.
  87. //
  88. // If both major and minor sub path are null, then result string
  89. // is empty.
  90. //
  91. // If either major or minor sub path is null, then path separator is
  92. // omitted.
  93. //
  94. if (MajorSubPathU == NULL) {
  95. //
  96. // If MinorSubPathU is also NULL, just set the output
  97. // buffer size to 0.
  98. //
  99. if (MinorSubPathU == NULL) {
  100. JoinedPathU->Length = 0;
  101. JoinedPathU->Buffer = NULL;
  102. return STATUS_SUCCESS;
  103. }
  104. JoinedPathLength = MinorSubPathU->MaximumLength;
  105. } else if (MinorSubPathU == NULL) {
  106. JoinedPathLength = MajorSubPathU->MaximumLength;
  107. } else {
  108. JoinedPathLength = MajorSubPathU->Length +
  109. (USHORT) sizeof( OBJ_NAME_PATH_SEPARATOR ) +
  110. MinorSubPathU->Length;
  111. }
  112. //
  113. // Now allocate buffer for the Joined Sub Path string
  114. //
  115. JoinedPathU->Length = 0;
  116. JoinedPathU->MaximumLength = JoinedPathLength;
  117. JoinedPathU->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, JoinedPathLength );
  118. if (JoinedPathU->Buffer == NULL) {
  119. Status = STATUS_INSUFFICIENT_RESOURCES;
  120. goto JoinSubPathError;
  121. }
  122. if (MajorSubPathU != NULL) {
  123. Status = RtlAppendUnicodeStringToString( JoinedPathU,
  124. MajorSubPathU
  125. );
  126. if (!NT_SUCCESS(Status)) {
  127. goto JoinSubPathError;
  128. }
  129. }
  130. if (MinorSubPathU != NULL) {
  131. if (MajorSubPathU != NULL) {
  132. Status = RtlAppendUnicodeToString( JoinedPathU,
  133. L"\\"
  134. );
  135. if (!NT_SUCCESS(Status)) {
  136. goto JoinSubPathError;
  137. }
  138. }
  139. Status = RtlAppendUnicodeStringToString( JoinedPathU,
  140. MinorSubPathU
  141. );
  142. if (!NT_SUCCESS(Status)) {
  143. goto JoinSubPathError;
  144. }
  145. }
  146. return Status;
  147. JoinSubPathError:
  148. //
  149. // If necessary, free the Joined Sub Path string buffer.
  150. //
  151. if (JoinedPathU->Buffer != NULL) {
  152. RtlFreeHeap( RtlProcessHeap(), 0, JoinedPathU->Buffer );
  153. JoinedPathU->Buffer = NULL;
  154. }
  155. return Status;
  156. }
  157. NTSTATUS
  158. LsapDbCreateSDObject(
  159. IN LSAPR_HANDLE ContainerHandle,
  160. IN LSAPR_HANDLE ObjectHandle,
  161. OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
  162. )
  163. /*++
  164. Routine Description:
  165. This function creates the initial Security Descriptor Attribute for an LSA
  166. Database object. The DACL in this SD is dependent on the object type.
  167. Arguments:
  168. ContainerHandle - Handle of the parent object
  169. ObjectHandle - Handle to open object.
  170. SecurityDescriptor - Returns a pointer to the security descriptor for the object.
  171. The Security Descriptor should be freed using
  172. RtlFreeHeap( RtlProcessHeap(), 0, SecurityDescriptor );
  173. Return Value:
  174. NTSTATUS - Standard Nt Result Code.
  175. --*/
  176. {
  177. NTSTATUS Status;
  178. ULONG DaclLength;
  179. PACL Dacl = NULL;
  180. HANDLE LsaProcessHandle = NULL;
  181. HANDLE LsaProcessTokenHandle = NULL;
  182. PSECURITY_DESCRIPTOR ContainerDescriptor = NULL;
  183. ULONG ContainerDescriptorLength;
  184. OBJECT_ATTRIBUTES LsaProcessObjectAttributes;
  185. SECURITY_DESCRIPTOR CreatorDescriptor;
  186. LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
  187. PTEB CurrentTeb;
  188. //
  189. // We will be creating a Security Descriptor in Self-Relative format.
  190. // The information that goes into the SD comes from two sources - the Lsa
  191. // Process's token and the information we provide, such as DACL. First,
  192. // we need to open the Lsa process to access its token.
  193. //
  194. *SecurityDescriptor = NULL;
  195. InitializeObjectAttributes(
  196. &LsaProcessObjectAttributes,
  197. NULL,
  198. 0,
  199. NULL,
  200. NULL
  201. );
  202. CurrentTeb = NtCurrentTeb();
  203. Status = NtOpenProcess(
  204. &LsaProcessHandle,
  205. PROCESS_QUERY_INFORMATION,
  206. &LsaProcessObjectAttributes,
  207. &CurrentTeb->ClientId
  208. );
  209. if (!NT_SUCCESS(Status)) {
  210. goto CreateSDError;
  211. }
  212. //
  213. // Now open the Lsa process's token with appropriate access
  214. //
  215. Status = NtOpenProcessToken(
  216. LsaProcessHandle,
  217. TOKEN_QUERY,
  218. &LsaProcessTokenHandle
  219. );
  220. if (!NT_SUCCESS(Status)) {
  221. goto CreateSDError;
  222. }
  223. //
  224. // Next, we want to specify a DACL to define the access for the
  225. // object whose SD is being created.
  226. //
  227. // Give GENERIC_ALL and, if the object is deletable, DELETE access to
  228. // the group DOMAIN_ALIAS_ADMINS.
  229. // Give GENERIC_EXECUTE access to WORLD.
  230. //
  231. // Note that the group ALIAS_ADMINS does NOT require access. This access is not
  232. // required because a logon to a member of DOMAIN_ADMIN results in a token
  233. // being constructed that has ALIAS_ADMINS added (by an Lsa authentication
  234. // filter routine).
  235. //
  236. // Construct a Security Descriptor that will contain only the DACL
  237. // we want and all other fields set to NULL.
  238. //
  239. Status = RtlCreateSecurityDescriptor(
  240. &CreatorDescriptor,
  241. SECURITY_DESCRIPTOR_REVISION
  242. );
  243. if (!NT_SUCCESS(Status)) {
  244. goto CreateSDError;
  245. }
  246. //
  247. // Calculate length of DACL required. It will hold two Access Allowed
  248. // ACE's, one for DOMAIN_ALIAS_ADMINS and one for WORLD. The size of the DACL is
  249. // the size of the ACL header plus the sizes of the ACE's minus a
  250. // redundant ULONG built into the header.
  251. //
  252. DaclLength = sizeof (ACL) - sizeof (ULONG) +
  253. sizeof (ACCESS_ALLOWED_ACE ) +
  254. RtlLengthSid( LsapAliasAdminsSid ) +
  255. sizeof (ACCESS_ALLOWED_ACE ) +
  256. RtlLengthSid( LsapWorldSid ) +
  257. (LsapDbState.DbObjectTypes[Handle->ObjectTypeId].AnonymousLogonAccess == 0 ?
  258. 0 :
  259. (sizeof (ACCESS_ALLOWED_ACE ) +
  260. RtlLengthSid( LsapAnonymousSid ) ) ) +
  261. (LsapDbState.DbObjectTypes[Handle->ObjectTypeId].LocalServiceAccess == 0 ?
  262. 0 :
  263. (sizeof (ACCESS_ALLOWED_ACE ) +
  264. RtlLengthSid( LsapLocalServiceSid ) ) ) +
  265. (LsapDbState.DbObjectTypes[Handle->ObjectTypeId].NetworkServiceAccess == 0 ?
  266. 0 :
  267. (sizeof (ACCESS_ALLOWED_ACE ) +
  268. RtlLengthSid( LsapNetworkServiceSid ) ) );
  269. Dacl = LsapAllocateLsaHeap(DaclLength);
  270. if (Dacl == NULL) {
  271. Status = STATUS_INSUFFICIENT_RESOURCES;
  272. goto CreateSDError;
  273. }
  274. Status = RtlCreateAcl(
  275. Dacl,
  276. DaclLength,
  277. ACL_REVISION
  278. );
  279. if (!NT_SUCCESS(Status)) {
  280. goto CreateSDError;
  281. }
  282. //
  283. // Now add the Access Allowed ACE for the group DOMAIN_ALIAS_ADMINS to the
  284. // object's DACL.
  285. //
  286. Status = RtlAddAccessAllowedAce(
  287. Dacl,
  288. ACL_REVISION,
  289. LsapDbState.DbObjectTypes[Handle->ObjectTypeId].AliasAdminsAccess,
  290. LsapAliasAdminsSid
  291. );
  292. if (!NT_SUCCESS(Status)) {
  293. goto CreateSDError;
  294. }
  295. //
  296. // Now add the Access Allowed ACE for the group WORLD to the
  297. // object's DACL.
  298. //
  299. Status = RtlAddAccessAllowedAce(
  300. Dacl,
  301. ACL_REVISION,
  302. LsapDbState.DbObjectTypes[Handle->ObjectTypeId].WorldAccess,
  303. LsapWorldSid
  304. );
  305. if (!NT_SUCCESS(Status)) {
  306. goto CreateSDError;
  307. }
  308. //
  309. // Now add the Access Allowed ACE for the group AnoymousLogon to the
  310. // object's DACL.
  311. //
  312. if ( LsapDbState.DbObjectTypes[Handle->ObjectTypeId].AnonymousLogonAccess != 0 ) {
  313. Status = RtlAddAccessAllowedAce(
  314. Dacl,
  315. ACL_REVISION,
  316. LsapDbState.DbObjectTypes[Handle->ObjectTypeId].AnonymousLogonAccess,
  317. LsapAnonymousSid
  318. );
  319. if (!NT_SUCCESS(Status)) {
  320. goto CreateSDError;
  321. }
  322. }
  323. //
  324. // Now add the Access Allowed ACE for LocalService to the object's DACL.
  325. //
  326. if ( LsapDbState.DbObjectTypes[Handle->ObjectTypeId].LocalServiceAccess != 0 ) {
  327. Status = RtlAddAccessAllowedAce(
  328. Dacl,
  329. ACL_REVISION,
  330. LsapDbState.DbObjectTypes[Handle->ObjectTypeId].LocalServiceAccess,
  331. LsapLocalServiceSid
  332. );
  333. if (!NT_SUCCESS(Status)) {
  334. goto CreateSDError;
  335. }
  336. }
  337. //
  338. // Now add the Access Allowed ACE for NetworkService to the object's DACL.
  339. //
  340. if ( LsapDbState.DbObjectTypes[Handle->ObjectTypeId].NetworkServiceAccess != 0 ) {
  341. Status = RtlAddAccessAllowedAce(
  342. Dacl,
  343. ACL_REVISION,
  344. LsapDbState.DbObjectTypes[Handle->ObjectTypeId].NetworkServiceAccess,
  345. LsapNetworkServiceSid
  346. );
  347. if (!NT_SUCCESS(Status)) {
  348. goto CreateSDError;
  349. }
  350. }
  351. //
  352. // Set the initial owner of the object
  353. //
  354. Status = RtlSetOwnerSecurityDescriptor(
  355. &CreatorDescriptor,
  356. LsapDbState.DbObjectTypes[Handle->ObjectTypeId].InitialOwnerSid,
  357. FALSE
  358. );
  359. if (!NT_SUCCESS(Status)) {
  360. goto CreateSDError;
  361. }
  362. //
  363. // Hook the newly constructed DACL for the LsaDb object into the
  364. // Modification Descriptor.
  365. //
  366. Status = RtlSetDaclSecurityDescriptor(
  367. &CreatorDescriptor,
  368. TRUE,
  369. Dacl,
  370. FALSE
  371. );
  372. if (!NT_SUCCESS(Status)) {
  373. goto CreateSDError;
  374. }
  375. //
  376. // If there is a container object, obtain its Security Descriptor so that
  377. // we can use it as the basis for our new descriptor. The new
  378. // descriptor will be equal to the container descriptor with DACL replaced
  379. // by the Modification Descriptor just constructed.
  380. //
  381. // Reading the container SD takes several steps:
  382. //
  383. // o Get the length of the Container SD
  384. // o Allocate a buffer for the SD
  385. // o Read the SD
  386. //
  387. // Obtain the length of the container object's SD by issuing a read for
  388. // the SecDesc subkey of the container object's Registry key, with a
  389. // dummy buffer whose size is too small.
  390. //
  391. if (ContainerHandle != NULL) {
  392. //
  393. // Obtain the length of the container object's SD by issuing a read for
  394. // the SecDesc subkey of the container object's Registry key, with a
  395. // dummy buffer whose size is too small.
  396. //
  397. ContainerDescriptorLength = 0;
  398. Status = LsapDbReadAttributeObject(
  399. ContainerHandle,
  400. &LsapDbNames[SecDesc],
  401. NULL,
  402. &ContainerDescriptorLength
  403. );
  404. if (!NT_SUCCESS(Status)) {
  405. goto CreateSDError;
  406. }
  407. //
  408. // Allocate a buffer from the Lsa Heap for the container object's SD.
  409. //
  410. ContainerDescriptor = LsapAllocateLsaHeap( ContainerDescriptorLength );
  411. if (ContainerDescriptor == NULL) {
  412. Status = STATUS_INSUFFICIENT_RESOURCES;
  413. goto CreateSDError;
  414. }
  415. //
  416. // Read the container object's SD. It is the value of the SecDesc
  417. // subkey.
  418. //
  419. Status = LsapDbReadAttributeObject(
  420. ContainerHandle,
  421. &LsapDbNames[SecDesc],
  422. ContainerDescriptor,
  423. &ContainerDescriptorLength
  424. );
  425. if (!NT_SUCCESS(Status)) {
  426. goto CreateSDError;
  427. }
  428. }
  429. //
  430. // Now we are ready to construct the Self-Relative Security Descriptor.
  431. // Information in the SD will be based on that in the LSA Process
  432. // Token, except for the DACL we provide in a Security Descriptor.
  433. // Note that we pass in the LSA Process Token explicitly because we
  434. // are not impersonating a client.
  435. //
  436. Status = RtlNewSecurityObject(
  437. ContainerDescriptor,
  438. &CreatorDescriptor,
  439. SecurityDescriptor,
  440. FALSE,
  441. LsaProcessTokenHandle,
  442. &(LsapDbState.
  443. DbObjectTypes[Handle->ObjectTypeId].GenericMapping)
  444. );
  445. if (!NT_SUCCESS(Status)) {
  446. goto CreateSDError;
  447. }
  448. CreateSDFinish:
  449. //
  450. // If necessary, free the memory allocated for the Container Descriptor
  451. //
  452. if (ContainerDescriptor != NULL) {
  453. LsapFreeLsaHeap( ContainerDescriptor );
  454. ContainerDescriptor = NULL;
  455. }
  456. //
  457. // If necessary, free the memory allocated for the DACL
  458. //
  459. if (Dacl != NULL) {
  460. LsapFreeLsaHeap(Dacl);
  461. Dacl = NULL;
  462. }
  463. //
  464. // Close the Handles to our process and token.
  465. //
  466. if ( LsaProcessHandle != NULL ) {
  467. (VOID) NtClose( LsaProcessHandle );
  468. }
  469. if ( LsaProcessTokenHandle != NULL ) {
  470. (VOID) NtClose( LsaProcessTokenHandle );
  471. }
  472. return(Status);
  473. CreateSDError:
  474. //
  475. // If necessary, free the memory allocated for SecurityDescriptor.
  476. //
  477. if (*SecurityDescriptor != NULL) {
  478. RtlFreeHeap( RtlProcessHeap(), 0, *SecurityDescriptor );
  479. *SecurityDescriptor = NULL;
  480. }
  481. goto CreateSDFinish;
  482. }
  483. NTSTATUS
  484. LsapDbCreateSDAttributeObject(
  485. IN LSAPR_HANDLE ObjectHandle,
  486. IN OUT PLSAP_DB_OBJECT_INFORMATION ObjectInformation
  487. )
  488. /*++
  489. Routine Description:
  490. This function creates the initial Security Descriptor Attribute for an LSA
  491. Database object. The DACL in this SD is dependent on the object type.
  492. Arguments:
  493. ObjectHandle - Handle to open object.
  494. ObjectInformation - Pointer to Object Information structure containing
  495. the object's Sid and type. A pointer to the created SD is filled in.
  496. Return Value:
  497. NTSTATUS - Standard Nt Result Code.
  498. --*/
  499. {
  500. NTSTATUS Status;
  501. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  502. ULONG SecurityDescriptorLength;
  503. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  504. LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) ObjectHandle;
  505. //
  506. // If these references a ds object, lease. We won't set the security on a ds object
  507. //
  508. if ( LsapDsIsHandleDsHandle( ObjectHandle ) ) {
  509. return( STATUS_SUCCESS );
  510. }
  511. //
  512. // Create the Security Descriptor
  513. //
  514. Status = LsapDbCreateSDObject(
  515. (LSAP_DB_HANDLE) ObjectInformation->ObjectAttributes.RootDirectory,
  516. ObjectHandle,
  517. &SecurityDescriptor );
  518. if (!NT_SUCCESS(Status)) {
  519. goto CreateSDError;
  520. }
  521. //
  522. // Set up the Security Quality Of Service
  523. //
  524. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  525. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  526. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  527. SecurityQualityOfService.EffectiveOnly = FALSE;
  528. //
  529. // Store the Security Descriptor
  530. //
  531. ObjectInformation->ObjectAttributes.SecurityDescriptor = SecurityDescriptor;
  532. //
  533. // The InitializeObjectAttributes macro stores NULL for the
  534. // SecurityQualityOfService field, so we must manually copy that
  535. // structure.
  536. //
  537. ObjectInformation->ObjectAttributes.SecurityQualityOfService =
  538. &SecurityQualityOfService;
  539. //
  540. // Obtain the length of the newly created SD.
  541. //
  542. SecurityDescriptorLength = RtlLengthSecurityDescriptor(
  543. SecurityDescriptor
  544. );
  545. //
  546. // Add a Registry transaction to write the Security Descriptor as the
  547. // value of the new object's SecDesc subkey.
  548. //
  549. Status = LsapDbWriteAttributeObject(
  550. Handle,
  551. &LsapDbNames[SecDesc],
  552. SecurityDescriptor,
  553. SecurityDescriptorLength
  554. );
  555. if (!NT_SUCCESS(Status)) {
  556. goto CreateSDError;
  557. }
  558. CreateSDFinish:
  559. return(Status);
  560. CreateSDError:
  561. //
  562. // If necessary, free the memory allocated for SecurityDescriptor.
  563. //
  564. if (SecurityDescriptor != NULL) {
  565. RtlFreeHeap( RtlProcessHeap(), 0, SecurityDescriptor );
  566. SecurityDescriptor = NULL;
  567. ObjectInformation->ObjectAttributes.SecurityDescriptor = NULL;
  568. }
  569. goto CreateSDFinish;
  570. }
  571. NTSTATUS
  572. LsapDbCheckCountObject(
  573. IN LSAP_DB_OBJECT_TYPE_ID ObjectTypeId
  574. )
  575. /*++
  576. Routine Description:
  577. This function checks if the number of objects of a given type has
  578. reached the type-dependent maximum limit (if any). If the limit
  579. is reached, a type-dependent error status is returned. Currently,
  580. only Secret objects have a limit imposed.
  581. Arguments:
  582. Handle - Handle to open object.
  583. ObjectTypeId - Specifies the type of the object.
  584. Return Value:
  585. NTSTATUS - Standard Nt Result Code.
  586. STATUS_TOO_MANY_SECRETS - Too many Secrets
  587. --*/
  588. {
  589. NTSTATUS Status = STATUS_SUCCESS;
  590. PLSAP_DB_OBJECT_TYPE ObjectType;
  591. ObjectType = &(LsapDbState.DbObjectTypes[ObjectTypeId]);
  592. //
  593. // If there is an Object Count Limit, check that it has not been
  594. // reached.
  595. //
  596. if ((ObjectType->ObjectCountLimited) &&
  597. (ObjectType->ObjectCount == ObjectType->MaximumObjectCount)) {
  598. Status = ObjectType->ObjectCountError;
  599. }
  600. return(Status);
  601. }