xref: /reactos/win32ss/user/ntuser/security.c (revision 0f9be539)
1878c2f44SGeorge Bișoc /*
2878c2f44SGeorge Bișoc  * PROJECT:         ReactOS Win32k subsystem
3878c2f44SGeorge Bișoc  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4878c2f44SGeorge Bișoc  * PURPOSE:         Security infrastructure of NTUSER component of Win32k
5*0f9be539SGeorge Bișoc  * COPYRIGHT:       Copyright 2022-2023 George Bișoc <george.bisoc@reactos.org>
6878c2f44SGeorge Bișoc  */
7878c2f44SGeorge Bișoc 
8878c2f44SGeorge Bișoc /* INCLUDES ******************************************************************/
9878c2f44SGeorge Bișoc 
10878c2f44SGeorge Bișoc #include <win32k.h>
11878c2f44SGeorge Bișoc DBG_DEFAULT_CHANNEL(UserSecurity);
12878c2f44SGeorge Bișoc 
13878c2f44SGeorge Bișoc /* FUNCTIONS *****************************************************************/
14878c2f44SGeorge Bișoc 
15878c2f44SGeorge Bișoc /**
16878c2f44SGeorge Bișoc  * @brief
17878c2f44SGeorge Bișoc  * Opens an access token that represents the effective security
18878c2f44SGeorge Bișoc  * context of the caller. The purpose of this function is to query
19878c2f44SGeorge Bișoc  * the authenticated user that is associated with the security
20878c2f44SGeorge Bișoc  * context.
21878c2f44SGeorge Bișoc  *
22878c2f44SGeorge Bișoc  * @return
23878c2f44SGeorge Bișoc  * Returns a handle to an opened access token that represents the
24878c2f44SGeorge Bișoc  * security context of the authenticated user, otherwise NULL.
25878c2f44SGeorge Bișoc  */
26878c2f44SGeorge Bișoc HANDLE
IntGetCurrentAccessToken(VOID)27878c2f44SGeorge Bișoc IntGetCurrentAccessToken(VOID)
28878c2f44SGeorge Bișoc {
29878c2f44SGeorge Bișoc     NTSTATUS Status;
30878c2f44SGeorge Bișoc     HANDLE TokenHandle;
31878c2f44SGeorge Bișoc 
32878c2f44SGeorge Bișoc     /*
33878c2f44SGeorge Bișoc      * Try acquiring the security context by opening
34878c2f44SGeorge Bișoc      * the current thread (or so called impersonation)
35878c2f44SGeorge Bișoc      * token. Such token represents the effective caller.
36878c2f44SGeorge Bișoc      * Otherwise if the current thread does not have a
37878c2f44SGeorge Bișoc      * token (hence no impersonation occurs) then open
38878c2f44SGeorge Bișoc      * the token of main calling process instead.
39878c2f44SGeorge Bișoc      */
40878c2f44SGeorge Bișoc     Status = ZwOpenThreadToken(ZwCurrentThread(),
41878c2f44SGeorge Bișoc                                TOKEN_QUERY,
42878c2f44SGeorge Bișoc                                FALSE,
43878c2f44SGeorge Bișoc                                &TokenHandle);
44878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
45878c2f44SGeorge Bișoc     {
46878c2f44SGeorge Bișoc         /*
47878c2f44SGeorge Bișoc          * We might likely fail to open the thread
48878c2f44SGeorge Bișoc          * token if the process isn't impersonating
49878c2f44SGeorge Bișoc          * a client. In scenarios where the server
50878c2f44SGeorge Bișoc          * isn't impersonating, open the main process
51878c2f44SGeorge Bișoc          * token.
52878c2f44SGeorge Bișoc          */
53878c2f44SGeorge Bișoc         if (Status == STATUS_NO_TOKEN)
54878c2f44SGeorge Bișoc         {
55878c2f44SGeorge Bișoc             TRACE("IntGetCurrentAccessToken(): The thread doesn't have a token, trying to open the process one...\n");
56878c2f44SGeorge Bișoc             Status = ZwOpenProcessToken(ZwCurrentProcess(),
57878c2f44SGeorge Bișoc                                         TOKEN_QUERY,
58878c2f44SGeorge Bișoc                                         &TokenHandle);
59878c2f44SGeorge Bișoc             if (!NT_SUCCESS(Status))
60878c2f44SGeorge Bișoc             {
61878c2f44SGeorge Bișoc                 /* We failed opening process token as well, bail out... */
62878c2f44SGeorge Bișoc                 ERR("IntGetCurrentAccessToken(): Failed to capture security context, couldn't open the process token (Status 0x%08lx)\n", Status);
63878c2f44SGeorge Bișoc                 return NULL;
64878c2f44SGeorge Bișoc             }
65878c2f44SGeorge Bișoc 
66878c2f44SGeorge Bișoc             /* Return the opened token handle */
67878c2f44SGeorge Bișoc             return TokenHandle;
68878c2f44SGeorge Bișoc         }
69878c2f44SGeorge Bișoc 
70878c2f44SGeorge Bișoc         /* There's a thread token but we couldn't open it so bail out */
71878c2f44SGeorge Bișoc         ERR("IntGetCurrentAccessToken(): Failed to capture security context, couldn't open the thread token (Status 0x%08lx)\n", Status);
72878c2f44SGeorge Bișoc         return NULL;
73878c2f44SGeorge Bișoc     }
74878c2f44SGeorge Bișoc 
75878c2f44SGeorge Bișoc     /* Return the opened token handle */
76878c2f44SGeorge Bișoc     return TokenHandle;
77878c2f44SGeorge Bișoc }
78878c2f44SGeorge Bișoc 
79878c2f44SGeorge Bișoc /**
80878c2f44SGeorge Bișoc  * @brief
81878c2f44SGeorge Bișoc  * Allocates a buffer within UM (user mode) address
82878c2f44SGeorge Bișoc  * space area. Such buffer is reserved for security
83878c2f44SGeorge Bișoc  * purposes, such as allocating a buffer for a DACL
84878c2f44SGeorge Bișoc  * or a security descriptor.
85878c2f44SGeorge Bișoc  *
86878c2f44SGeorge Bișoc  * @param[in] Length
87878c2f44SGeorge Bișoc  * The length of the buffer that has to be allocated,
88878c2f44SGeorge Bișoc  * in bytes.
89878c2f44SGeorge Bișoc  *
90878c2f44SGeorge Bișoc  * @return
91878c2f44SGeorge Bișoc  * Returns a pointer to an allocated buffer whose
92878c2f44SGeorge Bișoc  * contents are arbitrary. If the function fails,
93878c2f44SGeorge Bișoc  * it means no pages are available to reserve for
94878c2f44SGeorge Bișoc  * memory allocation for this buffer.
95878c2f44SGeorge Bișoc  */
96878c2f44SGeorge Bișoc PVOID
IntAllocateSecurityBuffer(_In_ SIZE_T Length)97878c2f44SGeorge Bișoc IntAllocateSecurityBuffer(
98878c2f44SGeorge Bișoc     _In_ SIZE_T Length)
99878c2f44SGeorge Bișoc {
100878c2f44SGeorge Bișoc     NTSTATUS Status;
101878c2f44SGeorge Bișoc     PVOID Buffer = NULL;
102878c2f44SGeorge Bișoc 
103878c2f44SGeorge Bișoc     /* Allocate the buffer in UM memory space */
104878c2f44SGeorge Bișoc     Status = ZwAllocateVirtualMemory(ZwCurrentProcess(),
105878c2f44SGeorge Bișoc                                      &Buffer,
106878c2f44SGeorge Bișoc                                      0,
107878c2f44SGeorge Bișoc                                      &Length,
108878c2f44SGeorge Bișoc                                      MEM_COMMIT,
109878c2f44SGeorge Bișoc                                      PAGE_READWRITE);
110878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
111878c2f44SGeorge Bișoc     {
112878c2f44SGeorge Bișoc         ERR("IntAllocateSecurityBuffer(): Failed to allocate the buffer (Status 0x%08lx)\n", Status);
113878c2f44SGeorge Bișoc         return NULL;
114878c2f44SGeorge Bișoc     }
115878c2f44SGeorge Bișoc 
116878c2f44SGeorge Bișoc     return Buffer;
117878c2f44SGeorge Bișoc }
118878c2f44SGeorge Bișoc 
119878c2f44SGeorge Bișoc /**
120878c2f44SGeorge Bișoc  * @brief
121878c2f44SGeorge Bișoc  * Frees an allocated security buffer from UM
122878c2f44SGeorge Bișoc  * memory that is been previously allocated by
123878c2f44SGeorge Bișoc  * IntAllocateSecurityBuffer function.
124878c2f44SGeorge Bișoc  *
125878c2f44SGeorge Bișoc  * @param[in] Buffer
126878c2f44SGeorge Bișoc  * A pointer to a buffer whose contents are
127878c2f44SGeorge Bișoc  * arbitrary, to be freed from UM memory space.
128878c2f44SGeorge Bișoc  *
129878c2f44SGeorge Bișoc  * @return
130878c2f44SGeorge Bișoc  * Nothing.
131878c2f44SGeorge Bișoc  */
132878c2f44SGeorge Bișoc VOID
IntFreeSecurityBuffer(_In_ PVOID Buffer)133878c2f44SGeorge Bișoc IntFreeSecurityBuffer(
134878c2f44SGeorge Bișoc     _In_ PVOID Buffer)
135878c2f44SGeorge Bișoc {
136878c2f44SGeorge Bișoc     SIZE_T Size = 0;
137878c2f44SGeorge Bișoc 
138878c2f44SGeorge Bișoc     ZwFreeVirtualMemory(ZwCurrentProcess(),
139878c2f44SGeorge Bișoc                         &Buffer,
140878c2f44SGeorge Bișoc                         &Size,
141878c2f44SGeorge Bișoc                         MEM_RELEASE);
142878c2f44SGeorge Bișoc }
143878c2f44SGeorge Bișoc 
144878c2f44SGeorge Bișoc /**
145878c2f44SGeorge Bișoc  * @brief
146878c2f44SGeorge Bișoc  * Queries the authenticated user security identifier
147878c2f44SGeorge Bișoc  * (SID) that is associated with the security context
148878c2f44SGeorge Bișoc  * of the access token that is being opened.
149878c2f44SGeorge Bișoc  *
150878c2f44SGeorge Bișoc  * @param[out] User
151878c2f44SGeorge Bișoc  * A pointer to the token user that contains the security
152878c2f44SGeorge Bișoc  * identifier of the authenticated user.
153878c2f44SGeorge Bișoc  *
154878c2f44SGeorge Bișoc  * @return
155878c2f44SGeorge Bișoc  * Returns STATUS_SUCCESS if the function has successfully
156878c2f44SGeorge Bișoc  * queried the token user. STATUS_UNSUCCESSFUL is returned
157878c2f44SGeorge Bișoc  * if the effective token of the caller couldn't be opened.
158878c2f44SGeorge Bișoc  * STATUS_NO_MEMORY is returned if memory allocation for
159878c2f44SGeorge Bișoc  * token user buffer has failed because of lack of necessary
160878c2f44SGeorge Bișoc  * pages reserved for such allocation. A failure NTSTATUS
161878c2f44SGeorge Bișoc  * code is returned otherwise.
162878c2f44SGeorge Bișoc  *
163878c2f44SGeorge Bișoc  * @remarks
164878c2f44SGeorge Bișoc  * !!!WARNING!!! -- THE CALLER WHO QUERIES THE TOKEN USER IS
165878c2f44SGeorge Bișoc  * RESPONSIBLE TO FREE THE ALLOCATED TOKEN USER BUFFER THAT IS
166878c2f44SGeorge Bișoc  * BEING GIVEN.
167878c2f44SGeorge Bișoc  */
168878c2f44SGeorge Bișoc NTSTATUS
IntQueryUserSecurityIdentification(_Out_ PTOKEN_USER * User)169878c2f44SGeorge Bișoc IntQueryUserSecurityIdentification(
170878c2f44SGeorge Bișoc     _Out_ PTOKEN_USER *User)
171878c2f44SGeorge Bișoc {
172878c2f44SGeorge Bișoc     NTSTATUS Status;
173*0f9be539SGeorge Bișoc     PTOKEN_USER UserToken = NULL;
174878c2f44SGeorge Bișoc     HANDLE Token;
175878c2f44SGeorge Bișoc     ULONG BufferLength;
176878c2f44SGeorge Bișoc 
177878c2f44SGeorge Bișoc     /* Initialize the parameter */
178878c2f44SGeorge Bișoc     *User = NULL;
179878c2f44SGeorge Bișoc 
180878c2f44SGeorge Bișoc     /* Open the current token of the caller */
181878c2f44SGeorge Bișoc     Token = IntGetCurrentAccessToken();
182878c2f44SGeorge Bișoc     if (!Token)
183878c2f44SGeorge Bișoc     {
184878c2f44SGeorge Bișoc         ERR("IntQueryUserSecurityIdentification(): Couldn't capture the token!\n");
185878c2f44SGeorge Bișoc         return STATUS_UNSUCCESSFUL;
186878c2f44SGeorge Bișoc     }
187878c2f44SGeorge Bișoc 
188878c2f44SGeorge Bișoc     /*
189878c2f44SGeorge Bișoc      * Since we do not know what the length
190878c2f44SGeorge Bișoc      * of the buffer size should be exactly to
191878c2f44SGeorge Bișoc      * hold the user data, let the function
192878c2f44SGeorge Bișoc      * tell us the size.
193878c2f44SGeorge Bișoc      */
194878c2f44SGeorge Bișoc     Status = ZwQueryInformationToken(Token,
195878c2f44SGeorge Bișoc                                      TokenUser,
196878c2f44SGeorge Bișoc                                      NULL,
197878c2f44SGeorge Bișoc                                      0,
198878c2f44SGeorge Bișoc                                      &BufferLength);
199*0f9be539SGeorge Bișoc     if (Status == STATUS_BUFFER_TOO_SMALL)
200878c2f44SGeorge Bișoc     {
201878c2f44SGeorge Bișoc         /*
202878c2f44SGeorge Bișoc          * Allocate some memory for the buffer
203878c2f44SGeorge Bișoc          * based on the size that the function
204878c2f44SGeorge Bișoc          * gave us.
205878c2f44SGeorge Bișoc          */
206878c2f44SGeorge Bișoc         UserToken = IntAllocateSecurityBuffer(BufferLength);
207878c2f44SGeorge Bișoc         if (!UserToken)
208878c2f44SGeorge Bișoc         {
209878c2f44SGeorge Bișoc             /* Bail out if we failed */
210878c2f44SGeorge Bișoc             ERR("IntQueryUserSecurityIdentification(): Couldn't allocate memory for the token user!\n");
211878c2f44SGeorge Bișoc             ZwClose(Token);
212878c2f44SGeorge Bișoc             return STATUS_NO_MEMORY;
213878c2f44SGeorge Bișoc         }
214878c2f44SGeorge Bișoc     }
215*0f9be539SGeorge Bișoc     else if (!NT_SUCCESS(Status))
216*0f9be539SGeorge Bișoc     {
217*0f9be539SGeorge Bișoc         ERR("IntQueryUserSecurityIdentification(): Failed to query the necessary length for the buffer (Status 0x%08lx)!\n", Status);
218*0f9be539SGeorge Bișoc         ZwClose(Token);
219*0f9be539SGeorge Bișoc         return Status;
220*0f9be539SGeorge Bișoc     }
221878c2f44SGeorge Bișoc 
222878c2f44SGeorge Bișoc     /* Query the user now as we have plenty of space to hold it */
223878c2f44SGeorge Bișoc     Status = ZwQueryInformationToken(Token,
224878c2f44SGeorge Bișoc                                      TokenUser,
225878c2f44SGeorge Bișoc                                      UserToken,
226878c2f44SGeorge Bișoc                                      BufferLength,
227878c2f44SGeorge Bișoc                                      &BufferLength);
228878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
229878c2f44SGeorge Bișoc     {
230878c2f44SGeorge Bișoc         /* We failed, bail out */
231878c2f44SGeorge Bișoc         ERR("IntQueryUserSecurityIdentification(): Failed to query token user (Status 0x%08lx)\n", Status);
232878c2f44SGeorge Bișoc         IntFreeSecurityBuffer(UserToken);
233878c2f44SGeorge Bișoc         ZwClose(Token);
234878c2f44SGeorge Bișoc         return Status;
235878c2f44SGeorge Bișoc     }
236878c2f44SGeorge Bișoc 
237878c2f44SGeorge Bișoc     /* All good, give the buffer to the caller and close the captured token */
238878c2f44SGeorge Bișoc     *User = UserToken;
239878c2f44SGeorge Bișoc     ZwClose(Token);
240878c2f44SGeorge Bișoc 
241878c2f44SGeorge Bișoc     return STATUS_SUCCESS;
242878c2f44SGeorge Bișoc }
243878c2f44SGeorge Bișoc 
244878c2f44SGeorge Bișoc /**
245878c2f44SGeorge Bișoc  * @brief
246aa815e1cSGeorge Bișoc  * Assigns a security descriptor to the desktop
247aa815e1cSGeorge Bișoc  * object during a desktop object parse procedure.
248aa815e1cSGeorge Bișoc  *
249aa815e1cSGeorge Bișoc  * @param[in] WinSta
250aa815e1cSGeorge Bișoc  * A pointer to a window station object, of which
251aa815e1cSGeorge Bișoc  * such object contains its own security descriptor
252aa815e1cSGeorge Bișoc  * that will be captured.
253aa815e1cSGeorge Bișoc  *
254aa815e1cSGeorge Bișoc  * @param[in] Desktop
255aa815e1cSGeorge Bișoc  * A pointer to a desktop object that is created
256aa815e1cSGeorge Bișoc  * during a parse procedure.
257aa815e1cSGeorge Bișoc  *
258aa815e1cSGeorge Bișoc  * @param[in] AccessState
259aa815e1cSGeorge Bișoc  * A pointer to an access state structure that
260aa815e1cSGeorge Bișoc  * describes the progress state of an access in
261aa815e1cSGeorge Bișoc  * action.
262aa815e1cSGeorge Bișoc  *
263aa815e1cSGeorge Bișoc  * @return
264aa815e1cSGeorge Bișoc  * Returns STATUS_SUCCESS if the function has successfully
265aa815e1cSGeorge Bișoc  * assigned new security descriptor to the desktop object.
266aa815e1cSGeorge Bișoc  * A NTSTATUS failure code is returned otherwise.
267aa815e1cSGeorge Bișoc  */
268aa815e1cSGeorge Bișoc NTSTATUS
269aa815e1cSGeorge Bișoc NTAPI
IntAssignDesktopSecurityOnParse(_In_ PWINSTATION_OBJECT WinSta,_In_ PDESKTOP Desktop,_In_ PACCESS_STATE AccessState)270aa815e1cSGeorge Bișoc IntAssignDesktopSecurityOnParse(
271aa815e1cSGeorge Bișoc     _In_ PWINSTATION_OBJECT WinSta,
272aa815e1cSGeorge Bișoc     _In_ PDESKTOP Desktop,
273aa815e1cSGeorge Bișoc     _In_ PACCESS_STATE AccessState)
274aa815e1cSGeorge Bișoc {
275aa815e1cSGeorge Bișoc     NTSTATUS Status;
276aa815e1cSGeorge Bișoc     PSECURITY_DESCRIPTOR CapturedDescriptor;
277aa815e1cSGeorge Bișoc     BOOLEAN MemoryAllocated;
278aa815e1cSGeorge Bișoc 
279aa815e1cSGeorge Bișoc     /*
280aa815e1cSGeorge Bișoc      * Capture the security descriptor from
281aa815e1cSGeorge Bișoc      * the window station. The window station
282aa815e1cSGeorge Bișoc      * in question has a descriptor that is
283aa815e1cSGeorge Bișoc      * inheritable and contains desktop access
284aa815e1cSGeorge Bișoc      * rights as well.
285aa815e1cSGeorge Bișoc      */
286aa815e1cSGeorge Bișoc     Status = ObGetObjectSecurity(WinSta,
287aa815e1cSGeorge Bișoc                                  &CapturedDescriptor,
288aa815e1cSGeorge Bișoc                                  &MemoryAllocated);
289aa815e1cSGeorge Bișoc     if (!NT_SUCCESS(Status))
290aa815e1cSGeorge Bișoc     {
291aa815e1cSGeorge Bișoc         ERR("IntAssignDesktopSecurityOnParse(): Failed to capture the security descriptor from window station (Status 0x%08lx)\n", Status);
292aa815e1cSGeorge Bișoc         return Status;
293aa815e1cSGeorge Bișoc     }
294aa815e1cSGeorge Bișoc 
295aa815e1cSGeorge Bișoc     /* Assign new security to the desktop */
296aa815e1cSGeorge Bișoc     Status = ObAssignSecurity(AccessState,
297aa815e1cSGeorge Bișoc                               CapturedDescriptor,
298aa815e1cSGeorge Bișoc                               Desktop,
299aa815e1cSGeorge Bișoc                               ExDesktopObjectType);
300aa815e1cSGeorge Bișoc     if (!NT_SUCCESS(Status))
301aa815e1cSGeorge Bișoc     {
302aa815e1cSGeorge Bișoc         ERR("IntAssignDesktopSecurityOnParse(): Failed to assign security information to the desktop object (Status 0x%08lx)\n", Status);
303aa815e1cSGeorge Bișoc     }
304aa815e1cSGeorge Bișoc 
305aa815e1cSGeorge Bișoc     /* Release the descriptor that we have captured */
306aa815e1cSGeorge Bișoc     ObReleaseObjectSecurity(CapturedDescriptor, MemoryAllocated);
307aa815e1cSGeorge Bișoc     return Status;
308aa815e1cSGeorge Bișoc }
309aa815e1cSGeorge Bișoc 
310aa815e1cSGeorge Bișoc /**
311aa815e1cSGeorge Bișoc  * @brief
312878c2f44SGeorge Bișoc  * Creates a security descriptor for the service.
313878c2f44SGeorge Bișoc  *
314878c2f44SGeorge Bișoc  * @param[out] ServiceSd
315878c2f44SGeorge Bișoc  * A pointer to a newly allocated and created security
316878c2f44SGeorge Bișoc  * descriptor for the service.
317878c2f44SGeorge Bișoc  *
318878c2f44SGeorge Bișoc  * @return
319878c2f44SGeorge Bișoc  * Returns STATUS_SUCCESS if the function has successfully
320878c2f44SGeorge Bișoc  * queried created the security descriptor. STATUS_NO_MEMORY
321878c2f44SGeorge Bișoc  * is returned if memory allocation for security buffers because
322878c2f44SGeorge Bișoc  * of a lack of needed pages to reserve for such allocation. A
323878c2f44SGeorge Bișoc  * failure NTSTATUS code is returned otherwise.
324878c2f44SGeorge Bișoc  */
325878c2f44SGeorge Bișoc NTSTATUS
326878c2f44SGeorge Bișoc NTAPI
IntCreateServiceSecurity(_Out_ PSECURITY_DESCRIPTOR * ServiceSd)327878c2f44SGeorge Bișoc IntCreateServiceSecurity(
328878c2f44SGeorge Bișoc     _Out_ PSECURITY_DESCRIPTOR *ServiceSd)
329878c2f44SGeorge Bișoc {
330878c2f44SGeorge Bișoc     NTSTATUS Status;
331878c2f44SGeorge Bișoc     PACL ServiceDacl;
332878c2f44SGeorge Bișoc     ULONG DaclSize;
333878c2f44SGeorge Bișoc     ULONG RelSDSize;
334878c2f44SGeorge Bișoc     SECURITY_DESCRIPTOR AbsSD;
335878c2f44SGeorge Bișoc     PSECURITY_DESCRIPTOR RelSD;
336878c2f44SGeorge Bișoc     PTOKEN_USER TokenUser;
337878c2f44SGeorge Bișoc 
338878c2f44SGeorge Bișoc     /* Initialize our local variables */
339878c2f44SGeorge Bișoc     RelSDSize = 0;
340878c2f44SGeorge Bișoc     TokenUser = NULL;
341878c2f44SGeorge Bișoc     RelSD = NULL;
342878c2f44SGeorge Bișoc     ServiceDacl = NULL;
343878c2f44SGeorge Bișoc 
344878c2f44SGeorge Bișoc     /* Query the logged in user of the current security context (aka token) */
345878c2f44SGeorge Bișoc     Status = IntQueryUserSecurityIdentification(&TokenUser);
346878c2f44SGeorge Bișoc     if (!TokenUser)
347878c2f44SGeorge Bișoc     {
348878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to query the token user (Status 0x%08lx)\n", Status);
349878c2f44SGeorge Bișoc         return Status;
350878c2f44SGeorge Bișoc     }
351878c2f44SGeorge Bișoc 
352878c2f44SGeorge Bișoc     /* Initialize the absolute security descriptor */
353878c2f44SGeorge Bișoc     Status = RtlCreateSecurityDescriptor(&AbsSD, SECURITY_DESCRIPTOR_REVISION);
354878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
355878c2f44SGeorge Bișoc     {
356878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to initialize absolute SD (Status 0x%08lx)\n", Status);
357878c2f44SGeorge Bișoc         goto Quit;
358878c2f44SGeorge Bișoc     }
359878c2f44SGeorge Bișoc 
360878c2f44SGeorge Bișoc     /*
361878c2f44SGeorge Bișoc      * Build up the size of access control
362878c2f44SGeorge Bișoc      * list (the DACL) necessary to initialize
363878c2f44SGeorge Bișoc      * our ACL. The first two entry members
364878c2f44SGeorge Bișoc      * of ACL field are the authenticated user
365878c2f44SGeorge Bișoc      * that is associated with the security
366878c2f44SGeorge Bișoc      * context of the token. Then here come
367878c2f44SGeorge Bișoc      * the last two entries which are admins.
368878c2f44SGeorge Bișoc      * Why the ACL contains two ACEs of the
369878c2f44SGeorge Bișoc      * same SID is because of service access
370878c2f44SGeorge Bișoc      * rights and ACE inheritance.
371878c2f44SGeorge Bișoc      *
372878c2f44SGeorge Bișoc      * A service is composed of a default
373878c2f44SGeorge Bișoc      * desktop and window station upon
374878c2f44SGeorge Bișoc      * booting the system. On Windows connection
375878c2f44SGeorge Bișoc      * to such service is being made if no
376878c2f44SGeorge Bișoc      * default window station and desktop handles
377878c2f44SGeorge Bișoc      * were created before. The desktop and winsta
378878c2f44SGeorge Bișoc      * objects grant access on a separate type basis.
379878c2f44SGeorge Bișoc      * The user is granted full access to the window
380878c2f44SGeorge Bișoc      * station first and then full access to the desktop.
381878c2f44SGeorge Bișoc      * After that admins are granted specific rights
382878c2f44SGeorge Bișoc      * separately, just like the user. Ultimately the
383878c2f44SGeorge Bișoc      * ACEs that handle desktop rights management are
384878c2f44SGeorge Bișoc      * inherited to the default desktop object so
385878c2f44SGeorge Bișoc      * that there's no need to have a separate security
386878c2f44SGeorge Bișoc      * descriptor for the desktop object alone.
387878c2f44SGeorge Bișoc      */
388878c2f44SGeorge Bișoc     DaclSize = sizeof(ACL) +
389878c2f44SGeorge Bișoc                sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(TokenUser->User.Sid) +
390878c2f44SGeorge Bișoc                sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(TokenUser->User.Sid) +
391878c2f44SGeorge Bișoc                sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(SeExports->SeAliasAdminsSid) +
392878c2f44SGeorge Bișoc                sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(SeExports->SeAliasAdminsSid);
393878c2f44SGeorge Bișoc 
394878c2f44SGeorge Bișoc     /* Allocate memory for service DACL */
395878c2f44SGeorge Bișoc     ServiceDacl = IntAllocateSecurityBuffer(DaclSize);
396878c2f44SGeorge Bișoc     if (!ServiceDacl)
397878c2f44SGeorge Bișoc     {
398878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to allocate memory for service DACL!\n");
399878c2f44SGeorge Bișoc         Status = STATUS_NO_MEMORY;
400878c2f44SGeorge Bișoc         goto Quit;
401878c2f44SGeorge Bișoc     }
402878c2f44SGeorge Bișoc 
403878c2f44SGeorge Bișoc     /* Now create the DACL */
404878c2f44SGeorge Bișoc     Status = RtlCreateAcl(ServiceDacl,
405878c2f44SGeorge Bișoc                           DaclSize,
406878c2f44SGeorge Bișoc                           ACL_REVISION);
407878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
408878c2f44SGeorge Bișoc     {
409878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to create service DACL (Status 0x%08lx)\n", Status);
410878c2f44SGeorge Bișoc         goto Quit;
411878c2f44SGeorge Bișoc     }
412878c2f44SGeorge Bișoc 
413878c2f44SGeorge Bișoc     /*
414878c2f44SGeorge Bișoc      * The authenticated user is the ultimate and absolute
415878c2f44SGeorge Bișoc      * king in charge of the created (or opened, whatever that is)
416878c2f44SGeorge Bișoc      * window station object.
417878c2f44SGeorge Bișoc      */
418878c2f44SGeorge Bișoc     Status = RtlAddAccessAllowedAceEx(ServiceDacl,
419878c2f44SGeorge Bișoc                                       ACL_REVISION,
420878c2f44SGeorge Bișoc                                       0,
421878c2f44SGeorge Bișoc                                       WINSTA_ACCESS_ALL,
422878c2f44SGeorge Bișoc                                       TokenUser->User.Sid);
423878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
424878c2f44SGeorge Bișoc     {
425878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to set up window station ACE for authenticated user (Status 0x%08lx)\n", Status);
426878c2f44SGeorge Bișoc         goto Quit;
427878c2f44SGeorge Bișoc     }
428878c2f44SGeorge Bișoc 
429878c2f44SGeorge Bișoc     /*
430878c2f44SGeorge Bișoc      * The authenticated user also has the ultimate power
431878c2f44SGeorge Bișoc      * over the desktop object as well. This ACE cannot
432878c2f44SGeorge Bișoc      * be propagated but inherited. See the comment
433878c2f44SGeorge Bișoc      * above regarding ACL size for further explanation.
434878c2f44SGeorge Bișoc      */
435878c2f44SGeorge Bișoc     Status = RtlAddAccessAllowedAceEx(ServiceDacl,
436878c2f44SGeorge Bișoc                                       ACL_REVISION,
437878c2f44SGeorge Bișoc                                       INHERIT_ONLY_ACE | NO_PROPAGATE_INHERIT_ACE | OBJECT_INHERIT_ACE,
438878c2f44SGeorge Bișoc                                       DESKTOP_ALL_ACCESS,
439878c2f44SGeorge Bișoc                                       TokenUser->User.Sid);
440878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
441878c2f44SGeorge Bișoc     {
442878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to set up desktop ACE for authenticated user (Status 0x%08lx)\n", Status);
443878c2f44SGeorge Bișoc         goto Quit;
444878c2f44SGeorge Bișoc     }
445878c2f44SGeorge Bișoc 
446878c2f44SGeorge Bișoc     /*
447878c2f44SGeorge Bișoc      * Administrators can only enumerate window
448878c2f44SGeorge Bișoc      * stations within a desktop.
449878c2f44SGeorge Bișoc      */
450878c2f44SGeorge Bișoc     Status = RtlAddAccessAllowedAceEx(ServiceDacl,
451878c2f44SGeorge Bișoc                                       ACL_REVISION,
452878c2f44SGeorge Bișoc                                       0,
453878c2f44SGeorge Bișoc                                       WINSTA_ENUMERATE,
454878c2f44SGeorge Bișoc                                       SeExports->SeAliasAdminsSid);
455878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
456878c2f44SGeorge Bișoc     {
457878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to set up window station ACE for admins (Status 0x%08lx)\n", Status);
458878c2f44SGeorge Bișoc         goto Quit;
459878c2f44SGeorge Bișoc     }
460878c2f44SGeorge Bișoc 
461878c2f44SGeorge Bișoc     /*
462878c2f44SGeorge Bișoc      * Administrators have some share of power over
463878c2f44SGeorge Bișoc      * the desktop object. They can enumerate desktops,
464878c2f44SGeorge Bișoc      * write and read upon the object itself.
465878c2f44SGeorge Bișoc      */
466878c2f44SGeorge Bișoc     Status = RtlAddAccessAllowedAceEx(ServiceDacl,
467878c2f44SGeorge Bișoc                                       ACL_REVISION,
468878c2f44SGeorge Bișoc                                       INHERIT_ONLY_ACE | NO_PROPAGATE_INHERIT_ACE | OBJECT_INHERIT_ACE,
469878c2f44SGeorge Bișoc                                       DESKTOP_ENUMERATE | DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS,
470878c2f44SGeorge Bișoc                                       SeExports->SeAliasAdminsSid);
471878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
472878c2f44SGeorge Bișoc     {
473878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to set up desktop ACE for admins (Status 0x%08lx)\n", Status);
474878c2f44SGeorge Bișoc         goto Quit;
475878c2f44SGeorge Bișoc     }
476878c2f44SGeorge Bișoc 
477878c2f44SGeorge Bișoc     /* Set the DACL to absolute SD */
478878c2f44SGeorge Bișoc     Status = RtlSetDaclSecurityDescriptor(&AbsSD,
479878c2f44SGeorge Bișoc                                           TRUE,
480878c2f44SGeorge Bișoc                                           ServiceDacl,
481878c2f44SGeorge Bișoc                                           FALSE);
482878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
483878c2f44SGeorge Bișoc     {
484878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to set up service DACL to absolute SD (Status 0x%08lx)\n", Status);
485878c2f44SGeorge Bișoc         goto Quit;
486878c2f44SGeorge Bișoc     }
487878c2f44SGeorge Bișoc 
488878c2f44SGeorge Bișoc     /* This descriptor is ownerless */
489878c2f44SGeorge Bișoc     Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
490878c2f44SGeorge Bișoc                                            NULL,
491878c2f44SGeorge Bișoc                                            FALSE);
492878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
493878c2f44SGeorge Bișoc     {
494878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to make the absolute SD as ownerless (Status 0x%08lx)\n", Status);
495878c2f44SGeorge Bișoc         goto Quit;
496878c2f44SGeorge Bișoc     }
497878c2f44SGeorge Bișoc 
498878c2f44SGeorge Bișoc     /* This descriptor has no primary group */
499878c2f44SGeorge Bișoc     Status = RtlSetGroupSecurityDescriptor(&AbsSD,
500878c2f44SGeorge Bișoc                                            NULL,
501878c2f44SGeorge Bișoc                                            FALSE);
502878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
503878c2f44SGeorge Bișoc     {
504878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to make the absolute SD as having no primary group (Status 0x%08lx)\n", Status);
505878c2f44SGeorge Bișoc         goto Quit;
506878c2f44SGeorge Bișoc     }
507878c2f44SGeorge Bișoc 
508878c2f44SGeorge Bișoc     /*
509878c2f44SGeorge Bișoc      * Determine how much size is needed to allocate
510878c2f44SGeorge Bișoc      * memory space for our relative security descriptor.
511878c2f44SGeorge Bișoc      */
512878c2f44SGeorge Bișoc     Status = RtlAbsoluteToSelfRelativeSD(&AbsSD,
513878c2f44SGeorge Bișoc                                          NULL,
514878c2f44SGeorge Bișoc                                          &RelSDSize);
515878c2f44SGeorge Bișoc     if (Status != STATUS_BUFFER_TOO_SMALL)
516878c2f44SGeorge Bișoc     {
517878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Unexpected status code, must be STATUS_BUFFER_TOO_SMALL (Status 0x%08lx)\n", Status);
518878c2f44SGeorge Bișoc         goto Quit;
519878c2f44SGeorge Bișoc     }
520878c2f44SGeorge Bișoc 
521878c2f44SGeorge Bișoc     /* Allocate memory for this */
522878c2f44SGeorge Bișoc     RelSD = IntAllocateSecurityBuffer(RelSDSize);
523878c2f44SGeorge Bișoc     if (!RelSD)
524878c2f44SGeorge Bișoc     {
525878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to allocate memory pool for relative SD!\n");
526878c2f44SGeorge Bișoc         Status = STATUS_NO_MEMORY;
527878c2f44SGeorge Bișoc         goto Quit;
528878c2f44SGeorge Bișoc     }
529878c2f44SGeorge Bișoc 
530878c2f44SGeorge Bișoc     /* Convert the absolute SD into a relative one now */
531878c2f44SGeorge Bișoc     Status = RtlAbsoluteToSelfRelativeSD(&AbsSD,
532878c2f44SGeorge Bișoc                                          RelSD,
533878c2f44SGeorge Bișoc                                          &RelSDSize);
534878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
535878c2f44SGeorge Bișoc     {
536878c2f44SGeorge Bișoc         ERR("IntCreateServiceSecurity(): Failed to convert absolute SD to a relative one (Status 0x%08lx)\n", Status);
537878c2f44SGeorge Bișoc         goto Quit;
538878c2f44SGeorge Bișoc     }
539878c2f44SGeorge Bișoc 
540878c2f44SGeorge Bișoc     /* All good, give the SD to the caller */
541878c2f44SGeorge Bișoc     *ServiceSd = RelSD;
542878c2f44SGeorge Bișoc 
543878c2f44SGeorge Bișoc Quit:
544878c2f44SGeorge Bișoc     if (ServiceDacl)
545878c2f44SGeorge Bișoc     {
546878c2f44SGeorge Bișoc         IntFreeSecurityBuffer(ServiceDacl);
547878c2f44SGeorge Bișoc     }
548878c2f44SGeorge Bișoc 
549878c2f44SGeorge Bișoc     if (TokenUser)
550878c2f44SGeorge Bișoc     {
551878c2f44SGeorge Bișoc         IntFreeSecurityBuffer(TokenUser);
552878c2f44SGeorge Bișoc     }
553878c2f44SGeorge Bișoc 
554878c2f44SGeorge Bișoc     if (!NT_SUCCESS(Status))
555878c2f44SGeorge Bișoc     {
556878c2f44SGeorge Bișoc         if (RelSD)
557878c2f44SGeorge Bișoc         {
558878c2f44SGeorge Bișoc             IntFreeSecurityBuffer(RelSD);
559878c2f44SGeorge Bișoc         }
560878c2f44SGeorge Bișoc     }
561878c2f44SGeorge Bișoc 
562878c2f44SGeorge Bișoc     return Status;
563878c2f44SGeorge Bișoc }
564878c2f44SGeorge Bișoc 
565878c2f44SGeorge Bișoc /* EOF */
566