Source code of Windows XP (NT5)
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.

523 lines
11 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Acledit.c
  5. Abstract:
  6. This Module implements the Acl rtl editing functions that are defined in
  7. ntseapi.h
  8. Author:
  9. Gary Kimura (GaryKi) 9-Nov-1989
  10. Environment:
  11. Pure Runtime Library Routine
  12. Revision History:
  13. --*/
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include "seopaque.h"
  17. //
  18. // Define the local macros and procedure for this module
  19. //
  20. //
  21. // Return a pointer to the first Ace in an Acl (even if the Acl is empty).
  22. //
  23. // PACE_HEADER
  24. // FirstAce (
  25. // IN PACL Acl
  26. // );
  27. //
  28. #define FirstAce(Acl) ((PVOID)((PUCHAR)(Acl) + sizeof(ACL)))
  29. VOID
  30. AddData (
  31. IN PVOID From,
  32. IN ULONG FromSize,
  33. IN PVOID To,
  34. IN ULONG ToSize
  35. );
  36. VOID
  37. DeleteData (
  38. IN PVOID Data,
  39. IN ULONG RemoveSize,
  40. IN ULONG TotalSize
  41. );
  42. NTSTATUS
  43. RtlMakePosixAcl(
  44. IN ULONG AclRevision,
  45. IN PSID UserSid,
  46. IN PSID GroupSid,
  47. IN ACCESS_MASK UserAccess,
  48. IN ACCESS_MASK GroupAccess,
  49. IN ACCESS_MASK OtherAccess,
  50. IN ULONG AclLength,
  51. OUT PACL Acl,
  52. OUT PULONG ReturnLength
  53. )
  54. /*++
  55. Routine Description:
  56. NOTE: THIS ROUTINE IS STILL BEING SPEC'D.
  57. Make an ACL representing Posix protection from AccessMask and
  58. security account ID (SID) information.
  59. Arguments:
  60. AclRevision - Indicates the ACL revision level of the access masks
  61. provided. The ACL generated will be revision compatible with this
  62. value and will not be a higher revision than this value.
  63. UserSid - Provides the SID of the user (owner).
  64. GroupSid - Provides the SID of the primary group.
  65. UserAccess - Specifies the accesses to be given to the user (owner).
  66. GroupAccess - Specifies the accesses to be given to the primary group.
  67. OtherAccess - Specifies the accesses to be given to others (WORLD).
  68. AclLength - Provides the length (in bytes) of the Acl buffer.
  69. Acl - Points to a buffer to receive the generated ACL.
  70. ReturnLength - Returns the actual length needed to store the resultant
  71. ACL. If this length is greater than that specified in AclLength,
  72. then STATUS_BUFFER_TOO_SMALL is returned and no ACL is generated.
  73. Return Values:
  74. STATUS_SUCCESS - The service completed successfully.
  75. STATUS_UNKNOWN_REVISION - The revision level specified is not supported
  76. by this service.
  77. STATUS_BUFFER_TOO_SMALL - Indicates the length of the output buffer
  78. wasn't large enough to hold the generated ACL. The length needed
  79. is returned via the ReturnLength parameter.
  80. --*/
  81. {
  82. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  83. ULONG UserSidLength;
  84. ULONG GroupSidLength;
  85. ULONG WorldSidLength;
  86. ULONG RequiredAclSize;
  87. ULONG AceSize;
  88. ULONG CurrentAce;
  89. PACCESS_ALLOWED_ACE Ace;
  90. NTSTATUS Status;
  91. PSID WorldSid;
  92. if (!RtlValidSid( UserSid ) || !RtlValidSid( GroupSid )) {
  93. return( STATUS_INVALID_SID );
  94. }
  95. UserSidLength = RtlLengthSid( UserSid );
  96. GroupSidLength = RtlLengthSid( GroupSid );
  97. WorldSidLength = RtlLengthRequiredSid( 1 );
  98. //
  99. // Figure out how much room we need for an ACL and three
  100. // ACCESS_ALLOWED Ace's
  101. //
  102. RequiredAclSize = sizeof( ACL );
  103. AceSize = sizeof( ACCESS_ALLOWED_ACE ) - sizeof( ULONG );
  104. RequiredAclSize += (AceSize * 3) +
  105. UserSidLength +
  106. GroupSidLength +
  107. WorldSidLength ;
  108. if (RequiredAclSize > AclLength) {
  109. *ReturnLength = RequiredAclSize;
  110. return( STATUS_BUFFER_TOO_SMALL );
  111. }
  112. //
  113. // The passed buffer is big enough, build the ACL in it.
  114. //
  115. Status = RtlCreateAcl(
  116. Acl,
  117. RequiredAclSize,
  118. AclRevision
  119. );
  120. if (!NT_SUCCESS( Status )) {
  121. return( Status );
  122. }
  123. Status = RtlAddAccessAllowedAce(
  124. Acl,
  125. ACL_REVISION2,
  126. UserAccess,
  127. UserSid
  128. );
  129. if (!NT_SUCCESS( Status )) {
  130. return( Status );
  131. }
  132. Status = RtlAddAccessAllowedAce(
  133. Acl,
  134. ACL_REVISION2,
  135. GroupAccess,
  136. GroupSid
  137. );
  138. if (!NT_SUCCESS( Status )) {
  139. return( Status );
  140. }
  141. Status = RtlAllocateAndInitializeSid(&WorldSidAuthority, 1,
  142. SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &WorldSid);
  143. if (!NT_SUCCESS( Status )) {
  144. return( Status );
  145. }
  146. Status = RtlAddAccessAllowedAce(
  147. Acl,
  148. ACL_REVISION2,
  149. OtherAccess,
  150. WorldSid
  151. );
  152. RtlFreeSid(WorldSid);
  153. if (!NT_SUCCESS( Status )) {
  154. return( Status );
  155. }
  156. return( STATUS_SUCCESS );
  157. }
  158. NTSTATUS
  159. RtlInterpretPosixAcl(
  160. IN ULONG AclRevision,
  161. IN PSID UserSid,
  162. IN PSID GroupSid,
  163. IN PACL Acl,
  164. OUT PACCESS_MASK UserAccess,
  165. OUT PACCESS_MASK GroupAccess,
  166. OUT PACCESS_MASK OtherAccess
  167. )
  168. /*++
  169. Routine Description:
  170. NOTE: THIS ROUTINE IS STILL BEING SPEC'D.
  171. Interpret an ACL representing Posix protection, returning AccessMasks.
  172. Use security account IDs (SIDs) for object owner and primary group
  173. identification.
  174. This algorithm will pick up the first match of a given SID and ignore
  175. all further matches of that SID. The first unrecognized SID becomes
  176. the "other" SID.
  177. Arguments:
  178. AclRevision - Indicates the ACL revision level of the access masks to
  179. be returned.
  180. UserSid - Provides the SID of the user (owner).
  181. GroupSid - Provides the SID of the primary group.
  182. Acl - Points to a buffer containing the ACL to interpret.
  183. UserAccess - Receives the accesses allowed for the user (owner).
  184. GroupAccess - Receives the accesses allowed for the primary group.
  185. OtherAccess - Receives the accesses allowed for others (WORLD).
  186. Return Values:
  187. STATUS_SUCCESS - The service completed successfully.
  188. STATUS_UNKNOWN_REVISION - The revision level specified is not supported
  189. by this service.
  190. STATUS_EXTRENEOUS_INFORMATION - This warning status value indicates the
  191. ACL contained protection or other information unrelated to Posix
  192. style protection. This is a warning only. The interpretation was
  193. otherwise successful and all access masks were returned.
  194. STATUS_COULD_NOT_INTERPRET - Indicates the ACL does not contain
  195. sufficient Posix style (user/group) protection information. The
  196. ACL could not be interpreted.
  197. --*/
  198. {
  199. NTSTATUS Status = STATUS_SUCCESS;
  200. BOOLEAN UserFound = FALSE;
  201. BOOLEAN GroupFound = FALSE;
  202. BOOLEAN OtherFound = FALSE;
  203. ULONG i;
  204. PKNOWN_ACE Ace;
  205. *UserAccess = *GroupAccess = *OtherAccess = 0;
  206. if (AclRevision != ACL_REVISION2) {
  207. return( STATUS_UNKNOWN_REVISION );
  208. }
  209. //
  210. // Special case for ACLs that are just "Everyone: Full Control".
  211. //
  212. if (Acl->AceCount < 3) {
  213. SID_IDENTIFIER_AUTHORITY WorldSidAuth = SECURITY_WORLD_SID_AUTHORITY;
  214. PSID WorldSid;
  215. Status = RtlAllocateAndInitializeSid(&WorldSidAuth, 1,
  216. SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &WorldSid);
  217. if (!NT_SUCCESS( Status )) {
  218. return( Status );
  219. }
  220. Status = RtlGetAce(Acl, 0, (PVOID *)&Ace);
  221. if (!NT_SUCCESS(Status)) {
  222. RtlFreeSid(WorldSid);
  223. return Status;
  224. }
  225. if (RtlEqualSid((PSID)&Ace->SidStart, WorldSid)) {
  226. *UserAccess = *GroupAccess = *OtherAccess = Ace->Mask;
  227. RtlFreeSid(WorldSid);
  228. return STATUS_SUCCESS;
  229. }
  230. RtlFreeSid(WorldSid);
  231. }
  232. for (i = 0; i < Acl->AceCount && (!UserFound || !GroupFound || !OtherFound);
  233. ++i) {
  234. Status = RtlGetAce(Acl, i, (PVOID *)&Ace);
  235. if (!NT_SUCCESS(Status)) {
  236. return Status;
  237. }
  238. if (Ace->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
  239. Status = STATUS_EXTRANEOUS_INFORMATION;
  240. continue;
  241. }
  242. if (RtlEqualSid(
  243. (PSID)(&Ace->SidStart),
  244. UserSid
  245. ) && !UserFound) {
  246. *UserAccess = Ace->Mask;
  247. UserFound = TRUE;
  248. continue;
  249. }
  250. if (RtlEqualSid(
  251. (PSID)(&Ace->SidStart),
  252. GroupSid
  253. ) && !GroupFound) {
  254. *GroupAccess = Ace->Mask;
  255. GroupFound = TRUE;
  256. continue;
  257. }
  258. //
  259. // It isn't the user, and it isn't the group, pick it up
  260. // as "other"
  261. //
  262. if (!OtherFound) {
  263. *OtherAccess = Ace->Mask;
  264. OtherFound = TRUE;
  265. continue;
  266. }
  267. }
  268. return( Status );
  269. }
  270. //
  271. // Internal support routine
  272. //
  273. VOID
  274. AddData (
  275. IN PVOID From,
  276. IN ULONG FromSize,
  277. IN PVOID To,
  278. IN ULONG ToSize
  279. )
  280. /*++
  281. Routine Description:
  282. This routine copies data to a string of bytes. It does this by moving
  283. over data in the to string so that the from string will fit. It also
  284. assumes that the checks that the data will fit in memory have already
  285. been done. Pictorally the results are as follows.
  286. Before:
  287. From -> ffffffffff
  288. To -> tttttttttttttttt
  289. After:
  290. From -> ffffffffff
  291. To -> fffffffffftttttttttttttttt
  292. Arguments:
  293. From - Supplies a pointer to the source buffer
  294. FromSize - Supplies the size of the from buffer in bytes
  295. To - Supplies a pointer to the destination buffer
  296. ToSize - Supplies the size of the to buffer in bytes
  297. Return Value:
  298. None
  299. --*/
  300. {
  301. LONG i;
  302. //
  303. // Shift over the To buffer enough to fit in the From buffer
  304. //
  305. for (i = ToSize - 1; i >= 0; i--) {
  306. ((PUCHAR)To)[i+FromSize] = ((PUCHAR)To)[i];
  307. }
  308. //
  309. // Now copy over the From buffer
  310. //
  311. for (i = 0; (ULONG)i < FromSize; i += 1) {
  312. ((PUCHAR)To)[i] = ((PUCHAR)From)[i];
  313. }
  314. //
  315. // and return to our caller
  316. //
  317. return;
  318. }
  319. //
  320. // Internal support routine
  321. //
  322. VOID
  323. DeleteData (
  324. IN PVOID Data,
  325. IN ULONG RemoveSize,
  326. IN ULONG TotalSize
  327. )
  328. /*++
  329. Routine Description:
  330. This routine deletes a string of bytes from the front of a data buffer
  331. and compresses the data. It also zeros out the part of the string
  332. that is no longer in use. Pictorially the results are as follows
  333. Before:
  334. Data = DDDDDddddd
  335. RemoveSize = 5
  336. TotalSize = 10
  337. After:
  338. Data = ddddd00000
  339. Arguments:
  340. Data - Supplies a pointer to the data being altered
  341. RemoveSize - Supplies the number of bytes to delete from the front
  342. of the data buffer
  343. TotalSize - Supplies the total number of bytes in the data buffer
  344. before the delete operation
  345. Return Value:
  346. None
  347. --*/
  348. {
  349. ULONG i;
  350. //
  351. // Shift over the buffer to remove the amount
  352. //
  353. for (i = RemoveSize; i < TotalSize; i++) {
  354. ((PUCHAR)Data)[i-RemoveSize] = ((PUCHAR)Data)[i];
  355. }
  356. //
  357. // Now as a safety precaution we'll zero out the rest of the string
  358. //
  359. for (i = TotalSize - RemoveSize; i < TotalSize; i++) {
  360. ((PUCHAR)Data)[i] = 0;
  361. }
  362. //
  363. // And return to our caller
  364. //
  365. return;
  366. }