xref: /reactos/ntoskrnl/se/acl.c (revision 8b75dce4)
1c2c66affSColin Finck /*
26413009cSGeorge Bișoc  * PROJECT:     ReactOS Kernel
36413009cSGeorge Bișoc  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
46413009cSGeorge Bișoc  * PURPOSE:     Access control lists (ACLs) implementation
56413009cSGeorge Bișoc  * COPYRIGHT:   Copyright David Welch <welch@cwcom.net>
6c2c66affSColin Finck  */
7c2c66affSColin Finck 
8c2c66affSColin Finck /* INCLUDES *******************************************************************/
9c2c66affSColin Finck 
10c2c66affSColin Finck #include <ntoskrnl.h>
11c2c66affSColin Finck #define NDEBUG
12c2c66affSColin Finck #include <debug.h>
13c2c66affSColin Finck 
14c2c66affSColin Finck /* GLOBALS ********************************************************************/
15c2c66affSColin Finck 
16c2c66affSColin Finck PACL SePublicDefaultDacl = NULL;
17c2c66affSColin Finck PACL SeSystemDefaultDacl = NULL;
18c2c66affSColin Finck PACL SePublicDefaultUnrestrictedDacl = NULL;
19c2c66affSColin Finck PACL SePublicOpenDacl = NULL;
20c2c66affSColin Finck PACL SePublicOpenUnrestrictedDacl = NULL;
21c2c66affSColin Finck PACL SeUnrestrictedDacl = NULL;
22b28530d4SGeorge Bișoc PACL SeSystemAnonymousLogonDacl = NULL;
23c2c66affSColin Finck 
24c2c66affSColin Finck /* FUNCTIONS ******************************************************************/
25c2c66affSColin Finck 
266413009cSGeorge Bișoc /**
276413009cSGeorge Bișoc  * @brief
286413009cSGeorge Bișoc  * Initializes known discretionary access control lists in the system upon
296413009cSGeorge Bișoc  * kernel and Executive initialization procedure.
306413009cSGeorge Bișoc  *
316413009cSGeorge Bișoc  * @return
326413009cSGeorge Bișoc  * Returns TRUE if all the DACLs have been successfully initialized,
336413009cSGeorge Bișoc  * FALSE otherwise.
346413009cSGeorge Bișoc  */
355c7ce447SVictor Perevertkin CODE_SEG("INIT")
36b20f8151SSerge Gautherie BOOLEAN
37c2c66affSColin Finck NTAPI
SepInitDACLs(VOID)38c2c66affSColin Finck SepInitDACLs(VOID)
39c2c66affSColin Finck {
40c2c66affSColin Finck     ULONG AclLength;
41c2c66affSColin Finck 
42c2c66affSColin Finck     /* create PublicDefaultDacl */
43c2c66affSColin Finck     AclLength = sizeof(ACL) +
44c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
45c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
46c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
47c2c66affSColin Finck 
48c2c66affSColin Finck     SePublicDefaultDacl = ExAllocatePoolWithTag(PagedPool,
49c2c66affSColin Finck                                                 AclLength,
50c2c66affSColin Finck                                                 TAG_ACL);
51c2c66affSColin Finck     if (SePublicDefaultDacl == NULL)
52c2c66affSColin Finck         return FALSE;
53c2c66affSColin Finck 
54c2c66affSColin Finck     RtlCreateAcl(SePublicDefaultDacl,
55c2c66affSColin Finck                  AclLength,
56c2c66affSColin Finck                  ACL_REVISION);
57c2c66affSColin Finck 
58c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicDefaultDacl,
59c2c66affSColin Finck                            ACL_REVISION,
60c2c66affSColin Finck                            GENERIC_EXECUTE,
61c2c66affSColin Finck                            SeWorldSid);
62c2c66affSColin Finck 
63c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicDefaultDacl,
64c2c66affSColin Finck                            ACL_REVISION,
65c2c66affSColin Finck                            GENERIC_ALL,
66c2c66affSColin Finck                            SeLocalSystemSid);
67c2c66affSColin Finck 
68c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicDefaultDacl,
69c2c66affSColin Finck                            ACL_REVISION,
70c2c66affSColin Finck                            GENERIC_ALL,
71c2c66affSColin Finck                            SeAliasAdminsSid);
72c2c66affSColin Finck 
73c2c66affSColin Finck     /* create PublicDefaultUnrestrictedDacl */
74c2c66affSColin Finck     AclLength = sizeof(ACL) +
75c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
76c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
77c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
78c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
79c2c66affSColin Finck 
80c2c66affSColin Finck     SePublicDefaultUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
81c2c66affSColin Finck                                                             AclLength,
82c2c66affSColin Finck                                                             TAG_ACL);
83c2c66affSColin Finck     if (SePublicDefaultUnrestrictedDacl == NULL)
84c2c66affSColin Finck         return FALSE;
85c2c66affSColin Finck 
86c2c66affSColin Finck     RtlCreateAcl(SePublicDefaultUnrestrictedDacl,
87c2c66affSColin Finck                  AclLength,
88c2c66affSColin Finck                  ACL_REVISION);
89c2c66affSColin Finck 
90c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
91c2c66affSColin Finck                            ACL_REVISION,
92c2c66affSColin Finck                            GENERIC_EXECUTE,
93c2c66affSColin Finck                            SeWorldSid);
94c2c66affSColin Finck 
95c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
96c2c66affSColin Finck                            ACL_REVISION,
97c2c66affSColin Finck                            GENERIC_ALL,
98c2c66affSColin Finck                            SeLocalSystemSid);
99c2c66affSColin Finck 
100c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
101c2c66affSColin Finck                            ACL_REVISION,
102c2c66affSColin Finck                            GENERIC_ALL,
103c2c66affSColin Finck                            SeAliasAdminsSid);
104c2c66affSColin Finck 
105c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
106c2c66affSColin Finck                            ACL_REVISION,
107c2c66affSColin Finck                            GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL,
108c2c66affSColin Finck                            SeRestrictedCodeSid);
109c2c66affSColin Finck 
110c2c66affSColin Finck     /* create PublicOpenDacl */
111c2c66affSColin Finck     AclLength = sizeof(ACL) +
112c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
113c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
114c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
115c2c66affSColin Finck 
116c2c66affSColin Finck     SePublicOpenDacl = ExAllocatePoolWithTag(PagedPool,
117c2c66affSColin Finck                                              AclLength,
118c2c66affSColin Finck                                              TAG_ACL);
119c2c66affSColin Finck     if (SePublicOpenDacl == NULL)
120c2c66affSColin Finck         return FALSE;
121c2c66affSColin Finck 
122c2c66affSColin Finck     RtlCreateAcl(SePublicOpenDacl,
123c2c66affSColin Finck                  AclLength,
124c2c66affSColin Finck                  ACL_REVISION);
125c2c66affSColin Finck 
126c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicOpenDacl,
127c2c66affSColin Finck                            ACL_REVISION,
128c2c66affSColin Finck                            GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
129c2c66affSColin Finck                            SeWorldSid);
130c2c66affSColin Finck 
131c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicOpenDacl,
132c2c66affSColin Finck                            ACL_REVISION,
133c2c66affSColin Finck                            GENERIC_ALL,
134c2c66affSColin Finck                            SeLocalSystemSid);
135c2c66affSColin Finck 
136c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicOpenDacl,
137c2c66affSColin Finck                            ACL_REVISION,
138c2c66affSColin Finck                            GENERIC_ALL,
139c2c66affSColin Finck                            SeAliasAdminsSid);
140c2c66affSColin Finck 
141c2c66affSColin Finck     /* create PublicOpenUnrestrictedDacl */
142c2c66affSColin Finck     AclLength = sizeof(ACL) +
143c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
144c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
145c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
146c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
147c2c66affSColin Finck 
148c2c66affSColin Finck     SePublicOpenUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
149c2c66affSColin Finck                                                          AclLength,
150c2c66affSColin Finck                                                          TAG_ACL);
151c2c66affSColin Finck     if (SePublicOpenUnrestrictedDacl == NULL)
152c2c66affSColin Finck         return FALSE;
153c2c66affSColin Finck 
154c2c66affSColin Finck     RtlCreateAcl(SePublicOpenUnrestrictedDacl,
155c2c66affSColin Finck                  AclLength,
156c2c66affSColin Finck                  ACL_REVISION);
157c2c66affSColin Finck 
158c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
159c2c66affSColin Finck                            ACL_REVISION,
160c2c66affSColin Finck                            GENERIC_ALL,
161c2c66affSColin Finck                            SeWorldSid);
162c2c66affSColin Finck 
163c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
164c2c66affSColin Finck                            ACL_REVISION,
165c2c66affSColin Finck                            GENERIC_ALL,
166c2c66affSColin Finck                            SeLocalSystemSid);
167c2c66affSColin Finck 
168c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
169c2c66affSColin Finck                            ACL_REVISION,
170c2c66affSColin Finck                            GENERIC_ALL,
171c2c66affSColin Finck                            SeAliasAdminsSid);
172c2c66affSColin Finck 
173c2c66affSColin Finck     RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
174c2c66affSColin Finck                            ACL_REVISION,
175c2c66affSColin Finck                            GENERIC_READ | GENERIC_EXECUTE,
176c2c66affSColin Finck                            SeRestrictedCodeSid);
177c2c66affSColin Finck 
178c2c66affSColin Finck     /* create SystemDefaultDacl */
179c2c66affSColin Finck     AclLength = sizeof(ACL) +
180c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
181c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
182c2c66affSColin Finck 
183c2c66affSColin Finck     SeSystemDefaultDacl = ExAllocatePoolWithTag(PagedPool,
184c2c66affSColin Finck                                                 AclLength,
185c2c66affSColin Finck                                                 TAG_ACL);
186c2c66affSColin Finck     if (SeSystemDefaultDacl == NULL)
187c2c66affSColin Finck         return FALSE;
188c2c66affSColin Finck 
189c2c66affSColin Finck     RtlCreateAcl(SeSystemDefaultDacl,
190c2c66affSColin Finck                  AclLength,
191c2c66affSColin Finck                  ACL_REVISION);
192c2c66affSColin Finck 
193c2c66affSColin Finck     RtlAddAccessAllowedAce(SeSystemDefaultDacl,
194c2c66affSColin Finck                            ACL_REVISION,
195c2c66affSColin Finck                            GENERIC_ALL,
196c2c66affSColin Finck                            SeLocalSystemSid);
197c2c66affSColin Finck 
198c2c66affSColin Finck     RtlAddAccessAllowedAce(SeSystemDefaultDacl,
199c2c66affSColin Finck                            ACL_REVISION,
200c2c66affSColin Finck                            GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL,
201c2c66affSColin Finck                            SeAliasAdminsSid);
202c2c66affSColin Finck 
203c2c66affSColin Finck     /* create UnrestrictedDacl */
204c2c66affSColin Finck     AclLength = sizeof(ACL) +
205c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
206c2c66affSColin Finck                 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
207c2c66affSColin Finck 
208c2c66affSColin Finck     SeUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
209c2c66affSColin Finck                                                AclLength,
210c2c66affSColin Finck                                                TAG_ACL);
211c2c66affSColin Finck     if (SeUnrestrictedDacl == NULL)
212c2c66affSColin Finck         return FALSE;
213c2c66affSColin Finck 
214c2c66affSColin Finck     RtlCreateAcl(SeUnrestrictedDacl,
215c2c66affSColin Finck                  AclLength,
216c2c66affSColin Finck                  ACL_REVISION);
217c2c66affSColin Finck 
218c2c66affSColin Finck     RtlAddAccessAllowedAce(SeUnrestrictedDacl,
219c2c66affSColin Finck                            ACL_REVISION,
220c2c66affSColin Finck                            GENERIC_ALL,
221c2c66affSColin Finck                            SeWorldSid);
222c2c66affSColin Finck 
223c2c66affSColin Finck     RtlAddAccessAllowedAce(SeUnrestrictedDacl,
224c2c66affSColin Finck                            ACL_REVISION,
225c2c66affSColin Finck                            GENERIC_READ | GENERIC_EXECUTE,
226c2c66affSColin Finck                            SeRestrictedCodeSid);
227c2c66affSColin Finck 
228b28530d4SGeorge Bișoc     /* create SystemAnonymousLogonDacl */
229b28530d4SGeorge Bișoc     AclLength = sizeof(ACL) +
230b28530d4SGeorge Bișoc                 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
231b28530d4SGeorge Bișoc                 (sizeof(ACE) + RtlLengthSid(SeAnonymousLogonSid));
232b28530d4SGeorge Bișoc 
233b28530d4SGeorge Bișoc     SeSystemAnonymousLogonDacl = ExAllocatePoolWithTag(PagedPool,
234b28530d4SGeorge Bișoc                                                        AclLength,
235b28530d4SGeorge Bișoc                                                        TAG_ACL);
236b28530d4SGeorge Bișoc     if (SeSystemAnonymousLogonDacl == NULL)
237b28530d4SGeorge Bișoc         return FALSE;
238b28530d4SGeorge Bișoc 
239b28530d4SGeorge Bișoc     RtlCreateAcl(SeSystemAnonymousLogonDacl,
240b28530d4SGeorge Bișoc                  AclLength,
241b28530d4SGeorge Bișoc                  ACL_REVISION);
242b28530d4SGeorge Bișoc 
243b28530d4SGeorge Bișoc     RtlAddAccessAllowedAce(SeSystemAnonymousLogonDacl,
244b28530d4SGeorge Bișoc                            ACL_REVISION,
245b28530d4SGeorge Bișoc                            GENERIC_ALL,
246b28530d4SGeorge Bișoc                            SeWorldSid);
247b28530d4SGeorge Bișoc 
248b28530d4SGeorge Bișoc     RtlAddAccessAllowedAce(SeSystemAnonymousLogonDacl,
249b28530d4SGeorge Bișoc                            ACL_REVISION,
250b28530d4SGeorge Bișoc                            GENERIC_ALL,
251b28530d4SGeorge Bișoc                            SeAnonymousLogonSid);
252b28530d4SGeorge Bișoc 
253c2c66affSColin Finck     return TRUE;
254c2c66affSColin Finck }
255c2c66affSColin Finck 
2566413009cSGeorge Bișoc /**
2576413009cSGeorge Bișoc  * @brief
2586413009cSGeorge Bișoc  * Allocates a discretionary access control list based on certain properties
2596413009cSGeorge Bișoc  * of a regular and primary access tokens.
2606413009cSGeorge Bișoc  *
2616413009cSGeorge Bișoc  * @param[in] Token
2626413009cSGeorge Bișoc  * An access token.
2636413009cSGeorge Bișoc  *
2646413009cSGeorge Bișoc  * @param[in] PrimaryToken
2656413009cSGeorge Bișoc  * A primary access token.
2666413009cSGeorge Bișoc  *
2676413009cSGeorge Bișoc  * @param[out] Dacl
2686413009cSGeorge Bișoc  * The returned allocated DACL.
2696413009cSGeorge Bișoc  *
2706413009cSGeorge Bișoc  * @return
2716413009cSGeorge Bișoc  * Returns STATUS_SUCCESS if DACL creation from tokens has completed
2726413009cSGeorge Bișoc  * successfully. STATUS_INSUFFICIENT_RESOURCES is returned if DACL
2736413009cSGeorge Bișoc  * allocation from memory pool fails otherwise.
2746413009cSGeorge Bișoc  */
2755b2dda91SHermès Bélusca-Maïto NTSTATUS
2765b2dda91SHermès Bélusca-Maïto NTAPI
SepCreateImpersonationTokenDacl(_In_ PTOKEN Token,_In_ PTOKEN PrimaryToken,_Out_ PACL * Dacl)2775b2dda91SHermès Bélusca-Maïto SepCreateImpersonationTokenDacl(
2785b2dda91SHermès Bélusca-Maïto     _In_ PTOKEN Token,
2795b2dda91SHermès Bélusca-Maïto     _In_ PTOKEN PrimaryToken,
2805b2dda91SHermès Bélusca-Maïto     _Out_ PACL* Dacl)
281c2c66affSColin Finck {
282c2c66affSColin Finck     ULONG AclLength;
2835b2dda91SHermès Bélusca-Maïto     PACL TokenDacl;
284c2c66affSColin Finck 
285c2c66affSColin Finck     PAGED_CODE();
286c2c66affSColin Finck 
2875b2dda91SHermès Bélusca-Maïto     *Dacl = NULL;
2885b2dda91SHermès Bélusca-Maïto 
289c2c66affSColin Finck     AclLength = sizeof(ACL) +
290c2c66affSColin Finck         (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
291c2c66affSColin Finck         (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
2925b2dda91SHermès Bélusca-Maïto         (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)) +
293c2c66affSColin Finck         (sizeof(ACE) + RtlLengthSid(Token->UserAndGroups->Sid)) +
294c2c66affSColin Finck         (sizeof(ACE) + RtlLengthSid(PrimaryToken->UserAndGroups->Sid));
295c2c66affSColin Finck 
296c2c66affSColin Finck     TokenDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL);
297c2c66affSColin Finck     if (TokenDacl == NULL)
298c2c66affSColin Finck     {
299c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
300c2c66affSColin Finck     }
301c2c66affSColin Finck 
302c2c66affSColin Finck     RtlCreateAcl(TokenDacl, AclLength, ACL_REVISION);
303c2c66affSColin Finck     RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
304c2c66affSColin Finck                            Token->UserAndGroups->Sid);
305c2c66affSColin Finck     RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
306c2c66affSColin Finck                            PrimaryToken->UserAndGroups->Sid);
307c2c66affSColin Finck     RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
308c2c66affSColin Finck                            SeAliasAdminsSid);
309c2c66affSColin Finck     RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
310c2c66affSColin Finck                            SeLocalSystemSid);
311c2c66affSColin Finck 
312c2c66affSColin Finck     if (Token->RestrictedSids != NULL || PrimaryToken->RestrictedSids != NULL)
313c2c66affSColin Finck     {
314c2c66affSColin Finck         RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
315c2c66affSColin Finck                                SeRestrictedCodeSid);
316c2c66affSColin Finck     }
3175b2dda91SHermès Bélusca-Maïto 
3185b2dda91SHermès Bélusca-Maïto     *Dacl = TokenDacl;
319c2c66affSColin Finck 
320c2c66affSColin Finck     return STATUS_SUCCESS;
321c2c66affSColin Finck }
322c2c66affSColin Finck 
3236413009cSGeorge Bișoc /**
3246413009cSGeorge Bișoc  * @brief
3256413009cSGeorge Bișoc  * Captures an access control list from an already valid input ACL.
3266413009cSGeorge Bișoc  *
3276413009cSGeorge Bișoc  * @param[in] InputAcl
3286413009cSGeorge Bișoc  * A valid ACL.
3296413009cSGeorge Bișoc  *
3306413009cSGeorge Bișoc  * @param[in] AccessMode
3316413009cSGeorge Bișoc  * Processor level access mode. The processor mode determines how
332*389a2da7SHermès Bélusca-Maïto  * the input arguments are probed.
3336413009cSGeorge Bișoc  *
3346413009cSGeorge Bișoc  * @param[in] PoolType
3356413009cSGeorge Bișoc  * Pool type for new captured ACL for creation. The pool type determines
336*389a2da7SHermès Bélusca-Maïto  * in which memory pool the ACL data should reside.
3376413009cSGeorge Bișoc  *
3386413009cSGeorge Bișoc  * @param[in] CaptureIfKernel
339*389a2da7SHermès Bélusca-Maïto  * If set to TRUE and the processor access mode being KernelMode, we are
340*389a2da7SHermès Bélusca-Maïto  * capturing an ACL directly in the kernel. Otherwise we are capturing
3416413009cSGeorge Bișoc  * within a kernel mode driver.
3426413009cSGeorge Bișoc  *
3436413009cSGeorge Bișoc  * @param[out] CapturedAcl
3446413009cSGeorge Bișoc  * The returned and allocated captured ACL.
3456413009cSGeorge Bișoc  *
3466413009cSGeorge Bișoc  * @return
3476413009cSGeorge Bișoc  * Returns STATUS_SUCCESS if the ACL has been successfully captured.
3486413009cSGeorge Bișoc  * STATUS_INSUFFICIENT_RESOURCES is returned otherwise.
3496413009cSGeorge Bișoc  */
350c2c66affSColin Finck NTSTATUS
351c2c66affSColin Finck NTAPI
SepCaptureAcl(_In_ PACL InputAcl,_In_ KPROCESSOR_MODE AccessMode,_In_ POOL_TYPE PoolType,_In_ BOOLEAN CaptureIfKernel,_Out_ PACL * CapturedAcl)3528567d814SGeorge Bișoc SepCaptureAcl(
3538567d814SGeorge Bișoc     _In_ PACL InputAcl,
3548567d814SGeorge Bișoc     _In_ KPROCESSOR_MODE AccessMode,
3558567d814SGeorge Bișoc     _In_ POOL_TYPE PoolType,
3568567d814SGeorge Bișoc     _In_ BOOLEAN CaptureIfKernel,
3578567d814SGeorge Bișoc     _Out_ PACL *CapturedAcl)
358c2c66affSColin Finck {
359c2c66affSColin Finck     PACL NewAcl;
360*389a2da7SHermès Bélusca-Maïto     ULONG AclSize;
361c2c66affSColin Finck 
362c2c66affSColin Finck     PAGED_CODE();
363c2c66affSColin Finck 
364*389a2da7SHermès Bélusca-Maïto     /* If in kernel mode and we do not capture, just
365*389a2da7SHermès Bélusca-Maïto      * return the given ACL and don't validate it. */
366*389a2da7SHermès Bélusca-Maïto     if ((AccessMode == KernelMode) && !CaptureIfKernel)
367*389a2da7SHermès Bélusca-Maïto     {
368*389a2da7SHermès Bélusca-Maïto         *CapturedAcl = InputAcl;
369*389a2da7SHermès Bélusca-Maïto         return STATUS_SUCCESS;
370*389a2da7SHermès Bélusca-Maïto     }
371*389a2da7SHermès Bélusca-Maïto 
372*389a2da7SHermès Bélusca-Maïto     /* Otherwise, capture and validate the ACL, depending on the access mode */
373c2c66affSColin Finck     if (AccessMode != KernelMode)
374c2c66affSColin Finck     {
375c2c66affSColin Finck         _SEH2_TRY
376c2c66affSColin Finck         {
377c2c66affSColin Finck             ProbeForRead(InputAcl,
378c2c66affSColin Finck                          sizeof(ACL),
379c2c66affSColin Finck                          sizeof(ULONG));
380c2c66affSColin Finck             AclSize = InputAcl->AclSize;
381c2c66affSColin Finck             ProbeForRead(InputAcl,
382c2c66affSColin Finck                          AclSize,
383c2c66affSColin Finck                          sizeof(ULONG));
384c2c66affSColin Finck         }
385c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
386c2c66affSColin Finck         {
387c2c66affSColin Finck             /* Return the exception code */
388c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
389c2c66affSColin Finck         }
390c2c66affSColin Finck         _SEH2_END;
391c2c66affSColin Finck 
392*389a2da7SHermès Bélusca-Maïto         /* Validate the minimal size an ACL can have */
393*389a2da7SHermès Bélusca-Maïto         if (AclSize < sizeof(ACL))
394*389a2da7SHermès Bélusca-Maïto             return STATUS_INVALID_ACL;
395*389a2da7SHermès Bélusca-Maïto 
396c2c66affSColin Finck         NewAcl = ExAllocatePoolWithTag(PoolType,
397c2c66affSColin Finck                                        AclSize,
398c2c66affSColin Finck                                        TAG_ACL);
399*389a2da7SHermès Bélusca-Maïto         if (!NewAcl)
400*389a2da7SHermès Bélusca-Maïto             return STATUS_INSUFFICIENT_RESOURCES;
401*389a2da7SHermès Bélusca-Maïto 
402c2c66affSColin Finck         _SEH2_TRY
403c2c66affSColin Finck         {
404*389a2da7SHermès Bélusca-Maïto             RtlCopyMemory(NewAcl, InputAcl, AclSize);
405c2c66affSColin Finck         }
406c2c66affSColin Finck         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
407c2c66affSColin Finck         {
408c2c66affSColin Finck             /* Free the ACL and return the exception code */
409c2c66affSColin Finck             ExFreePoolWithTag(NewAcl, TAG_ACL);
410c2c66affSColin Finck             _SEH2_YIELD(return _SEH2_GetExceptionCode());
411c2c66affSColin Finck         }
412c2c66affSColin Finck         _SEH2_END;
413c2c66affSColin Finck     }
414c2c66affSColin Finck     else
415c2c66affSColin Finck     {
416c2c66affSColin Finck         AclSize = InputAcl->AclSize;
417c2c66affSColin Finck 
418*389a2da7SHermès Bélusca-Maïto         /* Validate the minimal size an ACL can have */
419*389a2da7SHermès Bélusca-Maïto         if (AclSize < sizeof(ACL))
420*389a2da7SHermès Bélusca-Maïto             return STATUS_INVALID_ACL;
421*389a2da7SHermès Bélusca-Maïto 
422c2c66affSColin Finck         NewAcl = ExAllocatePoolWithTag(PoolType,
423c2c66affSColin Finck                                        AclSize,
424c2c66affSColin Finck                                        TAG_ACL);
425*389a2da7SHermès Bélusca-Maïto         if (!NewAcl)
426*389a2da7SHermès Bélusca-Maïto             return STATUS_INSUFFICIENT_RESOURCES;
427c2c66affSColin Finck 
428*389a2da7SHermès Bélusca-Maïto         RtlCopyMemory(NewAcl, InputAcl, AclSize);
429*389a2da7SHermès Bélusca-Maïto     }
430*389a2da7SHermès Bélusca-Maïto 
431*389a2da7SHermès Bélusca-Maïto     /* Validate the captured ACL */
432*389a2da7SHermès Bélusca-Maïto     if (!RtlValidAcl(NewAcl))
433c2c66affSColin Finck     {
434*389a2da7SHermès Bélusca-Maïto         /* Free the ACL and fail */
435*389a2da7SHermès Bélusca-Maïto         ExFreePoolWithTag(NewAcl, TAG_ACL);
436*389a2da7SHermès Bélusca-Maïto         return STATUS_INVALID_ACL;
437*389a2da7SHermès Bélusca-Maïto     }
438c2c66affSColin Finck 
439*389a2da7SHermès Bélusca-Maïto     /* It's valid, return it */
440c2c66affSColin Finck     *CapturedAcl = NewAcl;
441*389a2da7SHermès Bélusca-Maïto     return STATUS_SUCCESS;
442c2c66affSColin Finck }
443c2c66affSColin Finck 
4446413009cSGeorge Bișoc /**
4456413009cSGeorge Bișoc  * @brief
4466413009cSGeorge Bișoc  * Releases (frees) a captured ACL from the memory pool.
4476413009cSGeorge Bișoc  *
4486413009cSGeorge Bișoc  * @param[in] CapturedAcl
4496413009cSGeorge Bișoc  * A valid captured ACL to free.
4506413009cSGeorge Bișoc  *
4516413009cSGeorge Bișoc  * @param[in] AccessMode
4526413009cSGeorge Bișoc  * Processor level access mode.
4536413009cSGeorge Bișoc  *
4546413009cSGeorge Bișoc  * @param[in] CaptureIfKernel
4556413009cSGeorge Bișoc  * If set to TRUE and the processor access mode being KernelMode, we're
4566413009cSGeorge Bișoc  * releasing an ACL directly in the kernel. Otherwise we're releasing
4576413009cSGeorge Bișoc  * within a kernel mode driver.
4586413009cSGeorge Bișoc  *
4596413009cSGeorge Bișoc  * @return
4606413009cSGeorge Bișoc  * Nothing.
4616413009cSGeorge Bișoc  */
462c2c66affSColin Finck VOID
463c2c66affSColin Finck NTAPI
SepReleaseAcl(_In_ PACL CapturedAcl,_In_ KPROCESSOR_MODE AccessMode,_In_ BOOLEAN CaptureIfKernel)4648567d814SGeorge Bișoc SepReleaseAcl(
4658567d814SGeorge Bișoc     _In_ PACL CapturedAcl,
4668567d814SGeorge Bișoc     _In_ KPROCESSOR_MODE AccessMode,
4678567d814SGeorge Bișoc     _In_ BOOLEAN CaptureIfKernel)
468c2c66affSColin Finck {
469c2c66affSColin Finck     PAGED_CODE();
470c2c66affSColin Finck 
471c2c66affSColin Finck     if (CapturedAcl != NULL &&
472c2c66affSColin Finck         (AccessMode != KernelMode ||
473c2c66affSColin Finck          (AccessMode == KernelMode && CaptureIfKernel)))
474c2c66affSColin Finck     {
475c2c66affSColin Finck         ExFreePoolWithTag(CapturedAcl, TAG_ACL);
476c2c66affSColin Finck     }
477c2c66affSColin Finck }
478c2c66affSColin Finck 
4796413009cSGeorge Bișoc /**
4806413009cSGeorge Bișoc  * @brief
4816413009cSGeorge Bișoc  * Determines if a certain ACE can or cannot be propagated based on
4826413009cSGeorge Bișoc  * ACE inheritation flags and whatnot.
4836413009cSGeorge Bișoc  *
4846413009cSGeorge Bișoc  * @param[in] AceFlags
4856413009cSGeorge Bișoc  * Bit flags of an ACE to perform propagation checks.
4866413009cSGeorge Bișoc  *
4876413009cSGeorge Bișoc  * @param[out] NewAceFlags
4886413009cSGeorge Bișoc  * New ACE bit blags based on the specific ACE flags of the first
4896413009cSGeorge Bișoc  * argument parameter.
4906413009cSGeorge Bișoc  *
4916413009cSGeorge Bișoc  * @param[in] IsInherited
4926413009cSGeorge Bișoc  * If set to TRUE, an ACE is deemed as directly inherited from another
4936413009cSGeorge Bișoc  * instance. In that case we're allowed to propagate.
4946413009cSGeorge Bișoc  *
4956413009cSGeorge Bișoc  * @param[in] IsDirectoryObject
4966413009cSGeorge Bișoc  * If set to TRUE, an object directly inherits this ACE so we can propagate
4976413009cSGeorge Bișoc  * it.
4986413009cSGeorge Bișoc  *
4996413009cSGeorge Bișoc  * @return
5006413009cSGeorge Bișoc  * Returns TRUE if an ACE can be propagated, FALSE otherwise.
5016413009cSGeorge Bișoc  */
502c2c66affSColin Finck BOOLEAN
SepShouldPropagateAce(_In_ UCHAR AceFlags,_Out_ PUCHAR NewAceFlags,_In_ BOOLEAN IsInherited,_In_ BOOLEAN IsDirectoryObject)503c2c66affSColin Finck SepShouldPropagateAce(
504c2c66affSColin Finck     _In_ UCHAR AceFlags,
505c2c66affSColin Finck     _Out_ PUCHAR NewAceFlags,
506c2c66affSColin Finck     _In_ BOOLEAN IsInherited,
507c2c66affSColin Finck     _In_ BOOLEAN IsDirectoryObject)
508c2c66affSColin Finck {
509c2c66affSColin Finck     if (!IsInherited)
510c2c66affSColin Finck     {
511c2c66affSColin Finck         *NewAceFlags = AceFlags;
512c2c66affSColin Finck         return TRUE;
513c2c66affSColin Finck     }
514c2c66affSColin Finck 
515c2c66affSColin Finck     if (!IsDirectoryObject)
516c2c66affSColin Finck     {
517c2c66affSColin Finck         if (AceFlags & OBJECT_INHERIT_ACE)
518c2c66affSColin Finck         {
519c2c66affSColin Finck             *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
520c2c66affSColin Finck             return TRUE;
521c2c66affSColin Finck         }
522c2c66affSColin Finck         return FALSE;
523c2c66affSColin Finck     }
524c2c66affSColin Finck 
525c2c66affSColin Finck     if (AceFlags & NO_PROPAGATE_INHERIT_ACE)
526c2c66affSColin Finck     {
527c2c66affSColin Finck         if (AceFlags & CONTAINER_INHERIT_ACE)
528c2c66affSColin Finck         {
529c2c66affSColin Finck             *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
530c2c66affSColin Finck             return TRUE;
531c2c66affSColin Finck         }
532c2c66affSColin Finck         return FALSE;
533c2c66affSColin Finck     }
534c2c66affSColin Finck 
535c2c66affSColin Finck     if (AceFlags & CONTAINER_INHERIT_ACE)
536c2c66affSColin Finck     {
537c2c66affSColin Finck         *NewAceFlags = CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE) | (AceFlags & ~VALID_INHERIT_FLAGS);
538c2c66affSColin Finck         return TRUE;
539c2c66affSColin Finck     }
540c2c66affSColin Finck 
541c2c66affSColin Finck     if (AceFlags & OBJECT_INHERIT_ACE)
542c2c66affSColin Finck     {
543c2c66affSColin Finck         *NewAceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | (AceFlags & ~VALID_INHERIT_FLAGS);
544c2c66affSColin Finck         return TRUE;
545c2c66affSColin Finck     }
546c2c66affSColin Finck 
547c2c66affSColin Finck     return FALSE;
548c2c66affSColin Finck }
549c2c66affSColin Finck 
5506413009cSGeorge Bișoc /**
5516413009cSGeorge Bișoc  * @brief
5526413009cSGeorge Bișoc  * Propagates (copies) an access control list.
5536413009cSGeorge Bișoc  *
5546413009cSGeorge Bișoc  * @param[out] AclDest
5556413009cSGeorge Bișoc  * The destination parameter with propagated ACL.
5566413009cSGeorge Bișoc  *
5576413009cSGeorge Bișoc  * @param[in,out] AclLength
5586413009cSGeorge Bișoc  * The length of the ACL that we propagate.
5596413009cSGeorge Bișoc  *
5606413009cSGeorge Bișoc  * @param[in] AclSource
5616413009cSGeorge Bișoc  * The source instance of a valid ACL.
5626413009cSGeorge Bișoc  *
5636413009cSGeorge Bișoc  * @param[in] Owner
5646413009cSGeorge Bișoc  * A SID that represents the main user that identifies the ACL.
5656413009cSGeorge Bișoc  *
5666413009cSGeorge Bișoc  * @param[in] Group
5676413009cSGeorge Bișoc  * A SID that represents a group that identifies the ACL.
5686413009cSGeorge Bișoc  *
5696413009cSGeorge Bișoc  * @param[in] IsInherited
5706413009cSGeorge Bișoc  * If set to TRUE, that means the ACL is directly inherited.
5716413009cSGeorge Bișoc  *
5726413009cSGeorge Bișoc  * @param[in] IsDirectoryObject
5736413009cSGeorge Bișoc  * If set to TRUE, that means the ACL is directly inherited because
5746413009cSGeorge Bișoc  * of the object that inherits it.
5756413009cSGeorge Bișoc  *
5766413009cSGeorge Bișoc  * @param[in] GenericMapping
5776413009cSGeorge Bișoc  * Generic mapping of access rights to map only certain effective
5786413009cSGeorge Bișoc  * ACEs.
5796413009cSGeorge Bișoc  *
5806413009cSGeorge Bișoc  * @return
5816413009cSGeorge Bișoc  * Returns STATUS_SUCCESS if ACL has been propagated successfully.
5826413009cSGeorge Bișoc  * STATUS_BUFFER_TOO_SMALL is returned if the ACL length is not greater
5836413009cSGeorge Bișoc  * than the maximum written size of the buffer for ACL propagation
5846413009cSGeorge Bișoc  * otherwise.
5856413009cSGeorge Bișoc  */
586c2c66affSColin Finck NTSTATUS
587c2c66affSColin Finck SepPropagateAcl(
_Out_writes_bytes_opt_(AclLength)588c2c66affSColin Finck     _Out_writes_bytes_opt_(AclLength) PACL AclDest,
589c2c66affSColin Finck     _Inout_ PULONG AclLength,
590c2c66affSColin Finck     _In_reads_bytes_(AclSource->AclSize) PACL AclSource,
591c2c66affSColin Finck     _In_ PSID Owner,
592c2c66affSColin Finck     _In_ PSID Group,
593c2c66affSColin Finck     _In_ BOOLEAN IsInherited,
594c2c66affSColin Finck     _In_ BOOLEAN IsDirectoryObject,
595c2c66affSColin Finck     _In_ PGENERIC_MAPPING GenericMapping)
596c2c66affSColin Finck {
597c2c66affSColin Finck     ACCESS_MASK Mask;
598c2c66affSColin Finck     PACCESS_ALLOWED_ACE AceSource;
599c2c66affSColin Finck     PACCESS_ALLOWED_ACE AceDest;
600c2c66affSColin Finck     PUCHAR CurrentDest;
601c2c66affSColin Finck     PUCHAR CurrentSource;
602c2c66affSColin Finck     ULONG i;
603c2c66affSColin Finck     ULONG Written;
604c2c66affSColin Finck     UCHAR AceFlags;
605c2c66affSColin Finck     USHORT AceSize;
606c2c66affSColin Finck     USHORT AceCount = 0;
607c2c66affSColin Finck     PSID Sid;
608c2c66affSColin Finck     BOOLEAN WriteTwoAces;
609c2c66affSColin Finck 
610c2c66affSColin Finck     ASSERT(RtlValidAcl(AclSource));
611c2c66affSColin Finck     ASSERT(AclSource->AclSize % sizeof(ULONG) == 0);
612c2c66affSColin Finck     ASSERT(AclSource->Sbz1 == 0);
613c2c66affSColin Finck     ASSERT(AclSource->Sbz2 == 0);
614c2c66affSColin Finck 
615c2c66affSColin Finck     Written = 0;
616c2c66affSColin Finck     if (*AclLength >= Written + sizeof(ACL))
617c2c66affSColin Finck     {
618c2c66affSColin Finck         RtlCopyMemory(AclDest,
619c2c66affSColin Finck                       AclSource,
620c2c66affSColin Finck                       sizeof(ACL));
621c2c66affSColin Finck     }
622c2c66affSColin Finck     Written += sizeof(ACL);
623c2c66affSColin Finck 
624c2c66affSColin Finck     CurrentDest = (PUCHAR)(AclDest + 1);
625c2c66affSColin Finck     CurrentSource = (PUCHAR)(AclSource + 1);
626c2c66affSColin Finck     for (i = 0; i < AclSource->AceCount; i++)
627c2c66affSColin Finck     {
628c2c66affSColin Finck         ASSERT((ULONG_PTR)CurrentDest % sizeof(ULONG) == 0);
629c2c66affSColin Finck         ASSERT((ULONG_PTR)CurrentSource % sizeof(ULONG) == 0);
630c2c66affSColin Finck         AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
631c2c66affSColin Finck         AceSource = (PACCESS_ALLOWED_ACE)CurrentSource;
632c2c66affSColin Finck 
633c2c66affSColin Finck         if (AceSource->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE)
634c2c66affSColin Finck         {
635c2c66affSColin Finck             /* FIXME: handle object & compound ACEs */
636c2c66affSColin Finck             AceSize = AceSource->Header.AceSize;
637c2c66affSColin Finck 
638c2c66affSColin Finck             if (*AclLength >= Written + AceSize)
639c2c66affSColin Finck             {
640c2c66affSColin Finck                 RtlCopyMemory(AceDest, AceSource, AceSize);
641c2c66affSColin Finck             }
642c2c66affSColin Finck             CurrentDest += AceSize;
643c2c66affSColin Finck             CurrentSource += AceSize;
644c2c66affSColin Finck             Written += AceSize;
645c2c66affSColin Finck             AceCount++;
646c2c66affSColin Finck             continue;
647c2c66affSColin Finck         }
648c2c66affSColin Finck 
649c2c66affSColin Finck         /* These all have the same structure */
650c2c66affSColin Finck         ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE ||
651c2c66affSColin Finck                AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE ||
652c2c66affSColin Finck                AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE ||
653c2c66affSColin Finck                AceSource->Header.AceType == SYSTEM_ALARM_ACE_TYPE);
654c2c66affSColin Finck 
655c2c66affSColin Finck         ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0);
656c2c66affSColin Finck         ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource));
657c2c66affSColin Finck         if (!SepShouldPropagateAce(AceSource->Header.AceFlags,
658c2c66affSColin Finck                                    &AceFlags,
659c2c66affSColin Finck                                    IsInherited,
660c2c66affSColin Finck                                    IsDirectoryObject))
661c2c66affSColin Finck         {
662c2c66affSColin Finck             CurrentSource += AceSource->Header.AceSize;
663c2c66affSColin Finck             continue;
664c2c66affSColin Finck         }
665c2c66affSColin Finck 
666c2c66affSColin Finck         /* FIXME: filter out duplicate ACEs */
667c2c66affSColin Finck         AceSize = AceSource->Header.AceSize;
668c2c66affSColin Finck         Mask = AceSource->Mask;
669c2c66affSColin Finck         Sid = (PSID)&AceSource->SidStart;
670c2c66affSColin Finck         ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid));
671c2c66affSColin Finck 
672c2c66affSColin Finck         WriteTwoAces = FALSE;
673c2c66affSColin Finck         /* Map effective ACE to specific rights */
674c2c66affSColin Finck         if (!(AceFlags & INHERIT_ONLY_ACE))
675c2c66affSColin Finck         {
676c2c66affSColin Finck             RtlMapGenericMask(&Mask, GenericMapping);
677c2c66affSColin Finck             Mask &= GenericMapping->GenericAll;
678c2c66affSColin Finck 
679c2c66affSColin Finck             if (IsInherited)
680c2c66affSColin Finck             {
681c2c66affSColin Finck                 if (RtlEqualSid(Sid, SeCreatorOwnerSid))
682c2c66affSColin Finck                     Sid = Owner;
683c2c66affSColin Finck                 else if (RtlEqualSid(Sid, SeCreatorGroupSid))
684c2c66affSColin Finck                     Sid = Group;
685c2c66affSColin Finck                 AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid);
686c2c66affSColin Finck 
687c2c66affSColin Finck                 /*
688c2c66affSColin Finck                  * A generic container ACE becomes two ACEs:
689c2c66affSColin Finck                  * - a specific effective ACE with no inheritance flags
690c2c66affSColin Finck                  * - an inherit-only ACE that keeps the generic rights
691c2c66affSColin Finck                  */
692c2c66affSColin Finck                 if (IsDirectoryObject &&
693c2c66affSColin Finck                     (AceFlags & CONTAINER_INHERIT_ACE) &&
694c2c66affSColin Finck                     (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart))
695c2c66affSColin Finck                 {
696c2c66affSColin Finck                     WriteTwoAces = TRUE;
697c2c66affSColin Finck                 }
698c2c66affSColin Finck             }
699c2c66affSColin Finck         }
700c2c66affSColin Finck 
701c2c66affSColin Finck         while (1)
702c2c66affSColin Finck         {
703c2c66affSColin Finck             if (*AclLength >= Written + AceSize)
704c2c66affSColin Finck             {
705c2c66affSColin Finck                 AceDest->Header.AceType = AceSource->Header.AceType;
706c2c66affSColin Finck                 AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS
707c2c66affSColin Finck                                                         : AceFlags;
708c2c66affSColin Finck                 AceDest->Header.AceSize = AceSize;
709c2c66affSColin Finck                 AceDest->Mask = Mask;
710c2c66affSColin Finck                 RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart),
711c2c66affSColin Finck                            (PSID)&AceDest->SidStart,
712c2c66affSColin Finck                            Sid);
713c2c66affSColin Finck             }
714c2c66affSColin Finck             Written += AceSize;
715c2c66affSColin Finck 
716c2c66affSColin Finck             AceCount++;
717c2c66affSColin Finck             CurrentDest += AceSize;
718c2c66affSColin Finck 
719c2c66affSColin Finck             if (!WriteTwoAces)
720c2c66affSColin Finck                 break;
721c2c66affSColin Finck 
722c2c66affSColin Finck             /* Second ACE keeps all the generics from the source ACE */
723c2c66affSColin Finck             WriteTwoAces = FALSE;
724c2c66affSColin Finck             AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
725c2c66affSColin Finck             AceSize = AceSource->Header.AceSize;
726c2c66affSColin Finck             Mask = AceSource->Mask;
727c2c66affSColin Finck             Sid = (PSID)&AceSource->SidStart;
728c2c66affSColin Finck             AceFlags |= INHERIT_ONLY_ACE;
729c2c66affSColin Finck         }
730c2c66affSColin Finck 
731c2c66affSColin Finck         CurrentSource += AceSource->Header.AceSize;
732c2c66affSColin Finck     }
733c2c66affSColin Finck 
734c2c66affSColin Finck     if (*AclLength >= sizeof(ACL))
735c2c66affSColin Finck     {
736c2c66affSColin Finck         AclDest->AceCount = AceCount;
737c2c66affSColin Finck         AclDest->AclSize = Written;
738c2c66affSColin Finck     }
739c2c66affSColin Finck 
740c2c66affSColin Finck     if (Written > *AclLength)
741c2c66affSColin Finck     {
742c2c66affSColin Finck         *AclLength = Written;
743c2c66affSColin Finck         return STATUS_BUFFER_TOO_SMALL;
744c2c66affSColin Finck     }
745c2c66affSColin Finck     *AclLength = Written;
746c2c66affSColin Finck     return STATUS_SUCCESS;
747c2c66affSColin Finck }
748c2c66affSColin Finck 
7496413009cSGeorge Bișoc /**
7506413009cSGeorge Bișoc  * @brief
7516413009cSGeorge Bișoc  * Selects an ACL and returns it to the caller.
7526413009cSGeorge Bișoc  *
7536413009cSGeorge Bișoc  * @param[in] ExplicitAcl
7546413009cSGeorge Bișoc  * If specified, the specified ACL to the call will be
7556413009cSGeorge Bișoc  * the selected ACL for the caller.
7566413009cSGeorge Bișoc  *
7576413009cSGeorge Bișoc  * @param[in] ExplicitPresent
7586413009cSGeorge Bișoc  * If set to TRUE and with specific ACL filled to the call, the
7596413009cSGeorge Bișoc  * function will immediately return the specific ACL as the selected
7606413009cSGeorge Bișoc  * ACL for the caller.
7616413009cSGeorge Bișoc  *
7626413009cSGeorge Bișoc  * @param[in] ExplicitDefaulted
7636413009cSGeorge Bișoc  * If set to FALSE and with specific ACL filled to the call, the ACL
7646413009cSGeorge Bișoc  * is not a default ACL. Otherwise it's a default ACL that we cannot
7656413009cSGeorge Bișoc  * select it as is.
7666413009cSGeorge Bișoc  *
7676413009cSGeorge Bișoc  * @param[in] ParentAcl
7686413009cSGeorge Bișoc  * If specified, the parent ACL will be used to determine the exact ACL
7696413009cSGeorge Bișoc  * length to check  if the ACL in question is not empty. If the list
7706413009cSGeorge Bișoc  * is not empty then the function will select such ACL to the caller.
7716413009cSGeorge Bișoc  *
7726413009cSGeorge Bișoc  * @param[in] DefaultAcl
7736413009cSGeorge Bișoc  * If specified, the default ACL will be the selected one for the caller.
7746413009cSGeorge Bișoc  *
7756413009cSGeorge Bișoc  * @param[out] AclLength
7766413009cSGeorge Bișoc  * The size length of an ACL.
7776413009cSGeorge Bișoc  *
7786413009cSGeorge Bișoc  * @param[in] Owner
7796413009cSGeorge Bișoc  * A SID that represents the main user that identifies the ACL.
7806413009cSGeorge Bișoc  *
7816413009cSGeorge Bișoc  * @param[in] Group
7826413009cSGeorge Bișoc  * A SID that represents a group that identifies the ACL.
7836413009cSGeorge Bișoc  *
7846413009cSGeorge Bișoc  * @param[out] AclPresent
7856413009cSGeorge Bișoc  * The returned boolean value, indicating if the ACL that we want to select
7866413009cSGeorge Bișoc  * does actually exist.
7876413009cSGeorge Bișoc  *
7886413009cSGeorge Bișoc  * @param[out] IsInherited
7896413009cSGeorge Bișoc  * The returned boolean value, indicating if the ACL we want to select it
7906413009cSGeorge Bișoc  * is actually inherited or not.
7916413009cSGeorge Bișoc  *
7926413009cSGeorge Bișoc  * @param[in] IsDirectoryObject
7936413009cSGeorge Bișoc  * If set to TRUE, the object inherits this ACL.
7946413009cSGeorge Bișoc  *
7956413009cSGeorge Bișoc  * @param[in] GenericMapping
7966413009cSGeorge Bișoc  * Generic mapping of access rights to map only certain effective
7976413009cSGeorge Bișoc  * ACEs of an ACL that we want to select it.
7986413009cSGeorge Bișoc  *
7996413009cSGeorge Bișoc  * @return
8006413009cSGeorge Bișoc  * Returns the selected access control list (ACL) to the caller,
8016413009cSGeorge Bișoc  * NULL otherwise.
8026413009cSGeorge Bișoc  */
803c2c66affSColin Finck PACL
SepSelectAcl(_In_opt_ PACL ExplicitAcl,_In_ BOOLEAN ExplicitPresent,_In_ BOOLEAN ExplicitDefaulted,_In_opt_ PACL ParentAcl,_In_opt_ PACL DefaultAcl,_Out_ PULONG AclLength,_In_ PSID Owner,_In_ PSID Group,_Out_ PBOOLEAN AclPresent,_Out_ PBOOLEAN IsInherited,_In_ BOOLEAN IsDirectoryObject,_In_ PGENERIC_MAPPING GenericMapping)804c2c66affSColin Finck SepSelectAcl(
805c2c66affSColin Finck     _In_opt_ PACL ExplicitAcl,
806c2c66affSColin Finck     _In_ BOOLEAN ExplicitPresent,
807c2c66affSColin Finck     _In_ BOOLEAN ExplicitDefaulted,
808c2c66affSColin Finck     _In_opt_ PACL ParentAcl,
809c2c66affSColin Finck     _In_opt_ PACL DefaultAcl,
810c2c66affSColin Finck     _Out_ PULONG AclLength,
811c2c66affSColin Finck     _In_ PSID Owner,
812c2c66affSColin Finck     _In_ PSID Group,
813c2c66affSColin Finck     _Out_ PBOOLEAN AclPresent,
814c2c66affSColin Finck     _Out_ PBOOLEAN IsInherited,
815c2c66affSColin Finck     _In_ BOOLEAN IsDirectoryObject,
816c2c66affSColin Finck     _In_ PGENERIC_MAPPING GenericMapping)
817c2c66affSColin Finck {
818c2c66affSColin Finck     PACL Acl;
819c2c66affSColin Finck     NTSTATUS Status;
820c2c66affSColin Finck 
821c2c66affSColin Finck     *AclPresent = TRUE;
822c2c66affSColin Finck     if (ExplicitPresent && !ExplicitDefaulted)
823c2c66affSColin Finck     {
824c2c66affSColin Finck         Acl = ExplicitAcl;
825c2c66affSColin Finck     }
826c2c66affSColin Finck     else
827c2c66affSColin Finck     {
828c2c66affSColin Finck         if (ParentAcl)
829c2c66affSColin Finck         {
830c2c66affSColin Finck             *IsInherited = TRUE;
831c2c66affSColin Finck             *AclLength = 0;
832c2c66affSColin Finck             Status = SepPropagateAcl(NULL,
833c2c66affSColin Finck                                      AclLength,
834c2c66affSColin Finck                                      ParentAcl,
835c2c66affSColin Finck                                      Owner,
836c2c66affSColin Finck                                      Group,
837c2c66affSColin Finck                                      *IsInherited,
838c2c66affSColin Finck                                      IsDirectoryObject,
839c2c66affSColin Finck                                      GenericMapping);
840c2c66affSColin Finck             ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
841c2c66affSColin Finck 
842c2c66affSColin Finck             /* Use the parent ACL only if it's not empty */
843c2c66affSColin Finck             if (*AclLength != sizeof(ACL))
844c2c66affSColin Finck                 return ParentAcl;
845c2c66affSColin Finck         }
846c2c66affSColin Finck 
847c2c66affSColin Finck         if (ExplicitPresent)
848c2c66affSColin Finck         {
849c2c66affSColin Finck             Acl = ExplicitAcl;
850c2c66affSColin Finck         }
851c2c66affSColin Finck         else if (DefaultAcl)
852c2c66affSColin Finck         {
853c2c66affSColin Finck             Acl = DefaultAcl;
854c2c66affSColin Finck         }
855c2c66affSColin Finck         else
856c2c66affSColin Finck         {
857c2c66affSColin Finck             *AclPresent = FALSE;
858c2c66affSColin Finck             Acl = NULL;
859c2c66affSColin Finck         }
860c2c66affSColin Finck     }
861c2c66affSColin Finck 
862c2c66affSColin Finck     *IsInherited = FALSE;
863c2c66affSColin Finck     *AclLength = 0;
864c2c66affSColin Finck     if (Acl)
865c2c66affSColin Finck     {
866c2c66affSColin Finck         /* Get the length */
867c2c66affSColin Finck         Status = SepPropagateAcl(NULL,
868c2c66affSColin Finck                                  AclLength,
869c2c66affSColin Finck                                  Acl,
870c2c66affSColin Finck                                  Owner,
871c2c66affSColin Finck                                  Group,
872c2c66affSColin Finck                                  *IsInherited,
873c2c66affSColin Finck                                  IsDirectoryObject,
874c2c66affSColin Finck                                  GenericMapping);
875c2c66affSColin Finck         ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
876c2c66affSColin Finck     }
877c2c66affSColin Finck     return Acl;
878c2c66affSColin Finck }
879c2c66affSColin Finck 
880c2c66affSColin Finck /* EOF */
881