xref: /reactos/base/system/winlogon/security.c (revision 09dde2cf)
1 /*
2  * PROJECT:         ReactOS Winlogon
3  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:         Security utility infrastructure implementation of Winlogon
5  * COPYRIGHT:       Copyright 2022 George Bișoc <george.bisoc@reactos.org>
6  */
7 
8 /* INCLUDES *****************************************************************/
9 
10 #include "winlogon.h"
11 
12 /* DEFINES ******************************************************************/
13 
14 #define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \
15     DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | \
16     DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \
17     DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)
18 
19 #define DESKTOP_ADMINS_LIMITED (DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS | \
20     DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_ENUMERATE)
21 
22 #define DESKTOP_INTERACTIVE_LIMITED (STANDARD_RIGHTS_READ | DESKTOP_ENUMERATE | \
23     DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW)
24 
25 #define DESKTOP_WINLOGON_ADMINS_LIMITED (STANDARD_RIGHTS_REQUIRED | DESKTOP_ENUMERATE)
26 
27 #define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \
28     WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \
29     WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \
30     WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | \
31     STANDARD_RIGHTS_REQUIRED)
32 
33 #define WINSTA_ADMINS_LIMITED (WINSTA_READATTRIBUTES | WINSTA_ENUMERATE)
34 
35 #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | \
36     GENERIC_EXECUTE | GENERIC_ALL)
37 
38 /* GLOBALS ******************************************************************/
39 
40 static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
41 
42 /* FUNCTIONS ****************************************************************/
43 
44 /**
45  * @brief
46  * Converts an absolute security descriptor to a self-relative
47  * format.
48  *
49  * @param[in] AbsoluteSd
50  * A pointer to an absolute security descriptor to be
51  * converted.
52  *
53  * @return
54  * Returns a pointer to a converted security descriptor in
55  * self-relative format. If the function fails, NULL is returned
56  * otherwise.
57  *
58  * @remarks
59  * The function allocates the security descriptor buffer in memory
60  * heap, the caller is entirely responsible for freeing such buffer
61  * from when it's no longer needed.
62  */
63 PSECURITY_DESCRIPTOR
64 ConvertToSelfRelative(
65     _In_ PSECURITY_DESCRIPTOR AbsoluteSd)
66 {
67     PSECURITY_DESCRIPTOR RelativeSd;
68     DWORD DescriptorLength = 0;
69 
70     /* Determine the size for our buffer to allocate */
71     if (!MakeSelfRelativeSD(AbsoluteSd, NULL, &DescriptorLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
72     {
73         ERR("ConvertToSelfRelative(): Unexpected error code (error code %lu -- must be ERROR_INSUFFICIENT_BUFFER)\n", GetLastError());
74         return NULL;
75     }
76 
77     /* Allocate the buffer now */
78     RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(),
79                                  HEAP_ZERO_MEMORY,
80                                  DescriptorLength);
81     if (RelativeSd == NULL)
82     {
83         ERR("ConvertToSelfRelative(): Failed to allocate buffer for relative SD!\n");
84         return NULL;
85     }
86 
87     /* Convert the security descriptor now */
88     if (!MakeSelfRelativeSD(AbsoluteSd, RelativeSd, &DescriptorLength))
89     {
90         ERR("ConvertToSelfRelative(): Failed to convert the security descriptor to a self relative format (error code %lu)\n", GetLastError());
91         RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
92         return NULL;
93     }
94 
95     return RelativeSd;
96 }
97 
98 /**
99  * @brief
100  * Creates a security descriptor for the default
101  * window station upon its creation.
102  *
103  * @param[out] WinstaSd
104  * A pointer to a created security descriptor for
105  * the window station.
106  *
107  * @return
108  * Returns TRUE if the function has successfully
109  * created the security descriptor, FALSE otherwise.
110  */
111 BOOL
112 CreateWinstaSecurity(
113     _Out_ PSECURITY_DESCRIPTOR *WinstaSd)
114 {
115     BOOL Success = FALSE;
116     SECURITY_DESCRIPTOR AbsoluteSd;
117     PSECURITY_DESCRIPTOR RelativeSd = NULL;
118     PSID WinlogonSid = NULL, AdminsSid = NULL, NetworkServiceSid = NULL; /* NetworkServiceSid is a HACK, see the comment below for information */
119     DWORD DaclSize;
120     PACL Dacl;
121 
122     /* Create the Winlogon SID */
123     if (!AllocateAndInitializeSid(&NtAuthority,
124                                   1,
125                                   SECURITY_LOCAL_SYSTEM_RID,
126                                   0, 0, 0, 0, 0, 0, 0,
127                                   &WinlogonSid))
128     {
129         ERR("CreateWinstaSecurity(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
130         return FALSE;
131     }
132 
133     /* Create the admins SID */
134     if (!AllocateAndInitializeSid(&NtAuthority,
135                                   2,
136                                   SECURITY_BUILTIN_DOMAIN_RID,
137                                   DOMAIN_ALIAS_RID_ADMINS,
138                                   0, 0, 0, 0, 0, 0,
139                                   &AdminsSid))
140     {
141         ERR("CreateWinstaSecurity(): Failed to create the admins SID (error code %lu)\n", GetLastError());
142         goto Quit;
143     }
144 
145     /* HACK: Create the network service SID */
146     if (!AllocateAndInitializeSid(&NtAuthority,
147                                   1,
148                                   SECURITY_NETWORK_SERVICE_RID,
149                                   0, 0, 0, 0, 0, 0, 0,
150                                   &NetworkServiceSid))
151     {
152         ERR("CreateWinstaSecurity(): Failed to create the network service SID (error code %lu)\n", GetLastError());
153         goto Quit;
154     }
155 
156     /*
157      * Build up the DACL size. This includes a number
158      * of four ACEs of two different SIDs. The first two
159      * ACEs give both window station and generic access
160      * to Winlogon, the last two give limited window station
161      * and desktop access to admins.
162      *
163      * ===================== !!!MUST READ!!! =====================
164      *
165      * HACK -- Include in the DACL two more ACEs for network
166      * service SID. Network services will be granted full
167      * access to the default window station. Whilst technically
168      * services that are either network or local ones are part
169      * and act on behalf of the system, what we are doing here
170      * is a hack because of two reasons:
171      *
172      * 1) Winlogon does not allow default window station (Winsta0)
173      * access to network services on Windows. As a matter of fact,
174      * network services must access their own service window station
175      * (aka Service-0x0-3e4$) which never gets created. Why it never
176      * gets created is explained on the second point.
177      *
178      * 2) Our LSASS terribly lacks in code that handles special logon
179      * service types, NetworkService and LocalService. For this reason
180      * whenever an access token is created for a network service process
181      * for example, its authentication ID (aka LogonId represented as a LUID)
182      * is a uniquely generated ID by LSASS for this process. This is wrong
183      * on so many levels, partly because a network service is not a regular
184      * service and network services have their own special authentication logon
185      * ID (with its respective LUID as {0x3e4, 0x0}). On top of that, a network
186      * service process must have an impersonation token but for whatever reason
187      * we are creating a primary access token instead.
188      *
189      * FOR ANYONE WHO'S INTERESTED ON FIXING THIS, DO NOT FORGET TO REMOVE THIS
190      * HACK!!!
191      *
192      * =========================== !!!END!!! ================================
193      */
194     DaclSize = sizeof(ACL) +
195                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
196                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
197                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
198                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
199                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(NetworkServiceSid) +
200                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(NetworkServiceSid);
201 
202     /* Allocate the DACL now */
203     Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
204                            HEAP_ZERO_MEMORY,
205                            DaclSize);
206     if (Dacl == NULL)
207     {
208         ERR("CreateWinstaSecurity(): Failed to allocate memory buffer for DACL!\n");
209         goto Quit;
210     }
211 
212     /* Initialize it */
213     if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
214     {
215         ERR("CreateWinstaSecurity(): Failed to initialize DACL (error code %lu)\n", GetLastError());
216         goto Quit;
217     }
218 
219     /* First ACE -- give full winsta access to Winlogon */
220     if (!AddAccessAllowedAceEx(Dacl,
221                                ACL_REVISION,
222                                NO_PROPAGATE_INHERIT_ACE,
223                                WINSTA_ALL,
224                                WinlogonSid))
225     {
226         ERR("CreateWinstaSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
227         goto Quit;
228     }
229 
230     /* Second ACE -- give full generic access to Winlogon */
231     if (!AddAccessAllowedAceEx(Dacl,
232                                ACL_REVISION,
233                                INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
234                                GENERIC_ACCESS,
235                                WinlogonSid))
236     {
237         ERR("CreateWinstaSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
238         goto Quit;
239     }
240 
241     /* Third ACE -- give limited winsta access to admins */
242     if (!AddAccessAllowedAceEx(Dacl,
243                                ACL_REVISION,
244                                NO_PROPAGATE_INHERIT_ACE,
245                                WINSTA_ADMINS_LIMITED,
246                                AdminsSid))
247     {
248         ERR("CreateWinstaSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
249         goto Quit;
250     }
251 
252     /* Fourth ACE -- give limited desktop access to admins */
253     if (!AddAccessAllowedAceEx(Dacl,
254                                ACL_REVISION,
255                                INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
256                                DESKTOP_ADMINS_LIMITED,
257                                AdminsSid))
258     {
259         ERR("CreateWinstaSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
260         goto Quit;
261     }
262 
263     /* HACK: Fifth ACE -- give full access to network services */
264     if (!AddAccessAllowedAceEx(Dacl,
265                                ACL_REVISION,
266                                NO_PROPAGATE_INHERIT_ACE,
267                                WINSTA_ALL,
268                                NetworkServiceSid))
269     {
270         ERR("CreateWinstaSecurity(): Failed to set ACE for network service (error code %lu)\n", GetLastError());
271         goto Quit;
272     }
273 
274     /* HACK: Sixth ACE -- give full generic access to network services */
275     if (!AddAccessAllowedAceEx(Dacl,
276                                ACL_REVISION,
277                                INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
278                                GENERIC_ACCESS,
279                                NetworkServiceSid))
280     {
281         ERR("CreateWinstaSecurity(): Failed to set ACE for network service (error code %lu)\n", GetLastError());
282         goto Quit;
283     }
284 
285     /* Initialize the security descriptor */
286     if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
287     {
288         ERR("CreateWinstaSecurity(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
289         goto Quit;
290     }
291 
292     /* Set the DACL to the descriptor */
293     if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
294     {
295         ERR("CreateWinstaSecurity(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
296         goto Quit;
297     }
298 
299     /* Convert it to self-relative format */
300     RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
301     if (RelativeSd == NULL)
302     {
303         ERR("CreateWinstaSecurity(): Failed to convert security descriptor to self relative format!\n");
304         goto Quit;
305     }
306 
307     /* Give the descriptor to the caller */
308     *WinstaSd = RelativeSd;
309     Success = TRUE;
310 
311 Quit:
312     if (WinlogonSid != NULL)
313     {
314         FreeSid(WinlogonSid);
315     }
316 
317     if (AdminsSid != NULL)
318     {
319         FreeSid(AdminsSid);
320     }
321 
322     /* HACK */
323     if (NetworkServiceSid != NULL)
324     {
325         FreeSid(NetworkServiceSid);
326     }
327     /* END HACK */
328 
329     if (Dacl != NULL)
330     {
331         RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
332     }
333 
334     if (Success == FALSE)
335     {
336         if (RelativeSd != NULL)
337         {
338             RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
339         }
340     }
341 
342     return Success;
343 }
344 
345 /**
346  * @brief
347  * Creates a security descriptor for the default
348  * application desktop upon its creation.
349  *
350  * @param[out] ApplicationDesktopSd
351  * A pointer to a created security descriptor for
352  * the application desktop.
353  *
354  * @return
355  * Returns TRUE if the function has successfully
356  * created the security descriptor, FALSE otherwise.
357  */
358 BOOL
359 CreateApplicationDesktopSecurity(
360     _Out_ PSECURITY_DESCRIPTOR *ApplicationDesktopSd)
361 {
362     BOOL Success = FALSE;
363     SECURITY_DESCRIPTOR AbsoluteSd;
364     PSECURITY_DESCRIPTOR RelativeSd = NULL;
365     PSID WinlogonSid = NULL, AdminsSid = NULL, NetworkServiceSid = NULL; /* NetworkServiceSid is a HACK, see the comment in CreateWinstaSecurity for information */
366     DWORD DaclSize;
367     PACL Dacl;
368 
369     /* Create the Winlogon SID */
370     if (!AllocateAndInitializeSid(&NtAuthority,
371                                   1,
372                                   SECURITY_LOCAL_SYSTEM_RID,
373                                   0, 0, 0, 0, 0, 0, 0,
374                                   &WinlogonSid))
375     {
376         ERR("CreateApplicationDesktopSecurity(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
377         return FALSE;
378     }
379 
380     /* Create the admins SID */
381     if (!AllocateAndInitializeSid(&NtAuthority,
382                                   2,
383                                   SECURITY_BUILTIN_DOMAIN_RID,
384                                   DOMAIN_ALIAS_RID_ADMINS,
385                                   0, 0, 0, 0, 0, 0,
386                                   &AdminsSid))
387     {
388         ERR("CreateApplicationDesktopSecurity(): Failed to create the admins SID (error code %lu)\n", GetLastError());
389         goto Quit;
390     }
391 
392     /* HACK: Create the network service SID */
393     if (!AllocateAndInitializeSid(&NtAuthority,
394                                   1,
395                                   SECURITY_NETWORK_SERVICE_RID,
396                                   0, 0, 0, 0, 0, 0, 0,
397                                   &NetworkServiceSid))
398     {
399         ERR("CreateApplicationDesktopSecurity(): Failed to create the network service SID (error code %lu)\n", GetLastError());
400         goto Quit;
401     }
402 
403     /*
404      * Build up the DACL size. This includes a number
405      * of two ACEs of two different SIDs. The first ACE
406      * gives full access to Winlogon, the last one gives
407      * limited desktop access to admins.
408      */
409     DaclSize = sizeof(ACL) +
410                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
411                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
412                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(NetworkServiceSid); /* HACK */
413 
414     /* Allocate the DACL now */
415     Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
416                            HEAP_ZERO_MEMORY,
417                            DaclSize);
418     if (Dacl == NULL)
419     {
420         ERR("CreateApplicationDesktopSecurity(): Failed to allocate memory buffer for DACL!\n");
421         goto Quit;
422     }
423 
424     /* Initialize it */
425     if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
426     {
427         ERR("CreateApplicationDesktopSecurity(): Failed to initialize DACL (error code %lu)\n", GetLastError());
428         goto Quit;
429     }
430 
431     /* First ACE -- Give full desktop power to Winlogon */
432     if (!AddAccessAllowedAceEx(Dacl,
433                                ACL_REVISION,
434                                0,
435                                DESKTOP_ALL,
436                                WinlogonSid))
437     {
438         ERR("CreateApplicationDesktopSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
439         goto Quit;
440     }
441 
442     /* Second ACE -- Give limited desktop power to admins */
443     if (!AddAccessAllowedAceEx(Dacl,
444                                ACL_REVISION,
445                                0,
446                                DESKTOP_ADMINS_LIMITED,
447                                AdminsSid))
448     {
449         ERR("CreateApplicationDesktopSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
450         goto Quit;
451     }
452 
453     /* HACK: Third ACE -- Give full desktop power to network services */
454     if (!AddAccessAllowedAceEx(Dacl,
455                                ACL_REVISION,
456                                0,
457                                DESKTOP_ALL,
458                                NetworkServiceSid))
459     {
460         ERR("CreateApplicationDesktopSecurity(): Failed to set ACE for network services (error code %lu)\n", GetLastError());
461         goto Quit;
462     }
463 
464     /* Initialize the security descriptor */
465     if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
466     {
467         ERR("CreateApplicationDesktopSecurity(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
468         goto Quit;
469     }
470 
471     /* Set the DACL to the descriptor */
472     if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
473     {
474         ERR("CreateApplicationDesktopSecurity(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
475         goto Quit;
476     }
477 
478     /* Conver it to self-relative format */
479     RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
480     if (RelativeSd == NULL)
481     {
482         ERR("CreateApplicationDesktopSecurity(): Failed to convert security descriptor to self relative format!\n");
483         goto Quit;
484     }
485 
486     /* Give the descriptor to the caller */
487     *ApplicationDesktopSd = RelativeSd;
488     Success = TRUE;
489 
490 Quit:
491     if (WinlogonSid != NULL)
492     {
493         FreeSid(WinlogonSid);
494     }
495 
496     if (AdminsSid != NULL)
497     {
498         FreeSid(AdminsSid);
499     }
500 
501     /* HACK */
502     if (NetworkServiceSid != NULL)
503     {
504         FreeSid(NetworkServiceSid);
505     }
506     /* END HACK */
507 
508     if (Dacl != NULL)
509     {
510         RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
511     }
512 
513     if (Success == FALSE)
514     {
515         if (RelativeSd != NULL)
516         {
517             RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
518         }
519     }
520 
521     return Success;
522 }
523 
524 /**
525  * @brief
526  * Creates a security descriptor for the default
527  * Winlogon desktop. This descriptor serves as a
528  * security measure for the winlogon desktop so
529  * that only Winlogon itself (and admins) can
530  * interact with it.
531  *
532  * @param[out] WinlogonDesktopSd
533  * A pointer to a created security descriptor for
534  * the Winlogon desktop.
535  *
536  * @return
537  * Returns TRUE if the function has successfully
538  * created the security descriptor, FALSE otherwise.
539  */
540 BOOL
541 CreateWinlogonDesktopSecurity(
542     _Out_ PSECURITY_DESCRIPTOR *WinlogonDesktopSd)
543 {
544     BOOL Success = FALSE;
545     SECURITY_DESCRIPTOR AbsoluteSd;
546     PSECURITY_DESCRIPTOR RelativeSd = NULL;
547     PSID WinlogonSid = NULL, AdminsSid = NULL;
548     DWORD DaclSize;
549     PACL Dacl;
550 
551     /* Create the Winlogon SID */
552     if (!AllocateAndInitializeSid(&NtAuthority,
553                                   1,
554                                   SECURITY_LOCAL_SYSTEM_RID,
555                                   0, 0, 0, 0, 0, 0, 0,
556                                   &WinlogonSid))
557     {
558         ERR("CreateWinlogonDesktopSecurity(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
559         return FALSE;
560     }
561 
562     /* Create the admins SID */
563     if (!AllocateAndInitializeSid(&NtAuthority,
564                                   2,
565                                   SECURITY_BUILTIN_DOMAIN_RID,
566                                   DOMAIN_ALIAS_RID_ADMINS,
567                                   0, 0, 0, 0, 0, 0,
568                                   &AdminsSid))
569     {
570         ERR("CreateWinlogonDesktopSecurity(): Failed to create the admins SID (error code %lu)\n", GetLastError());
571         goto Quit;
572     }
573 
574     /*
575      * Build up the DACL size. This includes a number
576      * of two ACEs of two different SIDs. The first ACE
577      * gives full access to Winlogon, the last one gives
578      * limited desktop access to admins.
579      */
580     DaclSize = sizeof(ACL) +
581                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
582                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid);
583 
584     /* Allocate the DACL now */
585     Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
586                            HEAP_ZERO_MEMORY,
587                            DaclSize);
588     if (Dacl == NULL)
589     {
590         ERR("CreateWinlogonDesktopSecurity(): Failed to allocate memory buffer for DACL!\n");
591         goto Quit;
592     }
593 
594     /* Initialize it */
595     if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
596     {
597         ERR("CreateWinlogonDesktopSecurity(): Failed to initialize DACL (error code %lu)\n", GetLastError());
598         goto Quit;
599     }
600 
601     /* First ACE -- Give full desktop access to Winlogon */
602     if (!AddAccessAllowedAceEx(Dacl,
603                                ACL_REVISION,
604                                0,
605                                DESKTOP_ALL,
606                                WinlogonSid))
607     {
608         ERR("CreateWinlogonDesktopSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
609         goto Quit;
610     }
611 
612     /* Second ACE -- Give limited desktop access to admins */
613     if (!AddAccessAllowedAceEx(Dacl,
614                                ACL_REVISION,
615                                0,
616                                DESKTOP_WINLOGON_ADMINS_LIMITED,
617                                AdminsSid))
618     {
619         ERR("CreateWinlogonDesktopSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
620         goto Quit;
621     }
622 
623     /* Initialize the security descriptor */
624     if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
625     {
626         ERR("CreateWinlogonDesktopSecurity(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
627         goto Quit;
628     }
629 
630     /* Set the DACL to the descriptor */
631     if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
632     {
633         ERR("CreateWinlogonDesktopSecurity(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
634         goto Quit;
635     }
636 
637     /* Conver it to self-relative format */
638     RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
639     if (RelativeSd == NULL)
640     {
641         ERR("CreateWinlogonDesktopSecurity(): Failed to convert security descriptor to self relative format!\n");
642         goto Quit;
643     }
644 
645     /* Give the descriptor to the caller */
646     *WinlogonDesktopSd = RelativeSd;
647     Success = TRUE;
648 
649 Quit:
650     if (WinlogonSid != NULL)
651     {
652         FreeSid(WinlogonSid);
653     }
654 
655     if (AdminsSid != NULL)
656     {
657         FreeSid(AdminsSid);
658     }
659 
660     if (Dacl != NULL)
661     {
662         RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
663     }
664 
665     if (Success == FALSE)
666     {
667         if (RelativeSd != NULL)
668         {
669             RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
670         }
671     }
672 
673     return Success;
674 }
675 
676 /**
677  * @brief
678  * Creates a security descriptor for the screen
679  * saver desktop.
680  *
681  * @param[out] ScreenSaverDesktopSd
682  * A pointer to a created security descriptor for
683  * the screen-saver desktop.
684  *
685  * @return
686  * Returns TRUE if the function has successfully
687  * created the security descriptor, FALSE otherwise.
688  */
689 BOOL
690 CreateScreenSaverSecurity(
691     _Out_ PSECURITY_DESCRIPTOR *ScreenSaverDesktopSd)
692 {
693     BOOL Success = FALSE;
694     SECURITY_DESCRIPTOR AbsoluteSd;
695     PSECURITY_DESCRIPTOR RelativeSd = NULL;
696     PSID WinlogonSid = NULL, AdminsSid = NULL, InteractiveSid = NULL;
697     DWORD DaclSize;
698     PACL Dacl;
699 
700     /* Create the Winlogon SID */
701     if (!AllocateAndInitializeSid(&NtAuthority,
702                                   1,
703                                   SECURITY_LOCAL_SYSTEM_RID,
704                                   0, 0, 0, 0, 0, 0, 0,
705                                   &WinlogonSid))
706     {
707         ERR("CreateScreenSaverSecurity(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
708         return FALSE;
709     }
710 
711     /* Create the admins SID */
712     if (!AllocateAndInitializeSid(&NtAuthority,
713                                   2,
714                                   SECURITY_BUILTIN_DOMAIN_RID,
715                                   DOMAIN_ALIAS_RID_ADMINS,
716                                   0, 0, 0, 0, 0, 0,
717                                   &AdminsSid))
718     {
719         ERR("CreateScreenSaverSecurity(): Failed to create the admins SID (error code %lu)\n", GetLastError());
720         goto Quit;
721     }
722 
723     /* Create the interactive logon SID */
724     if (!AllocateAndInitializeSid(&NtAuthority,
725                                   1,
726                                   SECURITY_INTERACTIVE_RID,
727                                   0, 0, 0, 0, 0, 0, 0,
728                                   &InteractiveSid))
729     {
730         ERR("CreateScreenSaverSecurity(): Failed to create the interactive SID (error code %lu)\n", GetLastError());
731         goto Quit;
732     }
733 
734     /*
735      * Build up the DACL size. This includes a number
736      * of three ACEs of three different SIDs. The first ACE
737      * gives full access to Winlogon, the second one gives
738      * limited desktop access to admins and the last one
739      * gives full desktop access to users who have logged in
740      * interactively.
741      */
742     DaclSize = sizeof(ACL) +
743                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
744                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
745                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(InteractiveSid);
746 
747     /* Allocate the DACL now */
748     Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
749                            HEAP_ZERO_MEMORY,
750                            DaclSize);
751     if (Dacl == NULL)
752     {
753         ERR("CreateScreenSaverSecurity(): Failed to allocate memory buffer for DACL!\n");
754         goto Quit;
755     }
756 
757     /* Initialize it */
758     if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
759     {
760         ERR("CreateScreenSaverSecurity(): Failed to initialize DACL (error code %lu)\n", GetLastError());
761         goto Quit;
762     }
763 
764     /* First ACE -- Give full desktop access to Winlogon */
765     if (!AddAccessAllowedAceEx(Dacl,
766                                ACL_REVISION,
767                                0,
768                                DESKTOP_ALL,
769                                WinlogonSid))
770     {
771         ERR("CreateScreenSaverSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
772         goto Quit;
773     }
774 
775     /* Second ACE -- Give limited desktop access to admins */
776     if (!AddAccessAllowedAceEx(Dacl,
777                                ACL_REVISION,
778                                NO_PROPAGATE_INHERIT_ACE,
779                                DESKTOP_ADMINS_LIMITED,
780                                AdminsSid))
781     {
782         ERR("CreateScreenSaverSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
783         goto Quit;
784     }
785 
786     /* Third ACE -- Give full desktop access to interactive logon users */
787     if (!AddAccessAllowedAceEx(Dacl,
788                                ACL_REVISION,
789                                NO_PROPAGATE_INHERIT_ACE,
790                                DESKTOP_INTERACTIVE_LIMITED,
791                                InteractiveSid))
792     {
793         ERR("CreateScreenSaverSecurity(): Failed to set ACE for interactive SID (error code %lu)\n", GetLastError());
794         goto Quit;
795     }
796 
797     /* Initialize the security descriptor */
798     if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
799     {
800         ERR("CreateScreenSaverSecurity(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
801         goto Quit;
802     }
803 
804     /* Set the DACL to the descriptor */
805     if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
806     {
807         ERR("CreateScreenSaverSecurity(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
808         goto Quit;
809     }
810 
811     /* Conver it to self-relative format */
812     RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
813     if (RelativeSd == NULL)
814     {
815         ERR("CreateScreenSaverSecurity(): Failed to convert security descriptor to self relative format!\n");
816         goto Quit;
817     }
818 
819     /* Give the descriptor to the caller */
820     *ScreenSaverDesktopSd = RelativeSd;
821     Success = TRUE;
822 
823 Quit:
824     if (WinlogonSid != NULL)
825     {
826         FreeSid(WinlogonSid);
827     }
828 
829     if (AdminsSid != NULL)
830     {
831         FreeSid(AdminsSid);
832     }
833 
834     if (InteractiveSid != NULL)
835     {
836         FreeSid(InteractiveSid);
837     }
838 
839     if (Dacl != NULL)
840     {
841         RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
842     }
843 
844     if (Success == FALSE)
845     {
846         if (RelativeSd != NULL)
847         {
848             RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
849         }
850     }
851 
852     return Success;
853 }
854 
855 /**
856  * @brief
857  * Assigns access to the specific logon user to
858  * the default window station. Such access is
859  * given to the user when it has logged in.
860  *
861  * @param[in] WinSta
862  * A handle to a window station where the
863  * user is given access to it.
864  *
865  * @param[in] LogonSid
866  * A pointer to a logon SID that represents
867  * the logged in user in question.
868  *
869  * @return
870  * Returns TRUE if the function has successfully
871  * assigned access to the user, FALSE otherwise.
872  */
873 BOOL
874 AllowWinstaAccessToUser(
875     _In_ HWINSTA WinSta,
876     _In_ PSID LogonSid)
877 {
878     BOOL Success = FALSE;
879     SECURITY_DESCRIPTOR AbsoluteSd;
880     PSECURITY_DESCRIPTOR RelativeSd = NULL;
881     PSID WinlogonSid = NULL, AdminsSid = NULL, InteractiveSid = NULL, NetworkServiceSid = NULL; /* NetworkServiceSid is a HACK, see the comment in CreateWinstaSecurity for information */
882     SECURITY_INFORMATION SecurityInformation;
883     DWORD DaclSize;
884     PACL Dacl;
885 
886     /* Create the Winlogon SID */
887     if (!AllocateAndInitializeSid(&NtAuthority,
888                                   1,
889                                   SECURITY_LOCAL_SYSTEM_RID,
890                                   0, 0, 0, 0, 0, 0, 0,
891                                   &WinlogonSid))
892     {
893         ERR("AllowWinstaAccessToUser(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
894         return FALSE;
895     }
896 
897     /* Create the admins SID */
898     if (!AllocateAndInitializeSid(&NtAuthority,
899                                   2,
900                                   SECURITY_BUILTIN_DOMAIN_RID,
901                                   DOMAIN_ALIAS_RID_ADMINS,
902                                   0, 0, 0, 0, 0, 0,
903                                   &AdminsSid))
904     {
905         ERR("AllowWinstaAccessToUser(): Failed to create the admins SID (error code %lu)\n", GetLastError());
906         goto Quit;
907     }
908 
909     /* Create the interactive logon SID */
910     if (!AllocateAndInitializeSid(&NtAuthority,
911                                   1,
912                                   SECURITY_INTERACTIVE_RID,
913                                   0, 0, 0, 0, 0, 0, 0,
914                                   &InteractiveSid))
915     {
916         ERR("AllowWinstaAccessToUser(): Failed to create the interactive SID (error code %lu)\n", GetLastError());
917         goto Quit;
918     }
919 
920     /* HACK: Create the network service SID */
921     if (!AllocateAndInitializeSid(&NtAuthority,
922                                   1,
923                                   SECURITY_NETWORK_SERVICE_RID,
924                                   0, 0, 0, 0, 0, 0, 0,
925                                   &NetworkServiceSid))
926     {
927         ERR("AllowWinstaAccessToUser(): Failed to create the network service SID (error code %lu)\n", GetLastError());
928         goto Quit;
929     }
930 
931     /*
932      * Build up the DACL size. This includes a number
933      * of eight ACEs of four different SIDs. The first ACE
934      * gives full winsta access to Winlogon, the second one gives
935      * generic access to Winlogon. Such approach is the same
936      * for both interactive logon users and logon user as well.
937      * Only admins are given limited powers.
938      */
939     DaclSize = sizeof(ACL) +
940                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
941                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
942                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
943                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
944                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(InteractiveSid) +
945                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(InteractiveSid) +
946                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(LogonSid) +
947                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(LogonSid) +
948                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(NetworkServiceSid) + /* HACK */
949                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(NetworkServiceSid);
950 
951     /* Allocate the DACL now */
952     Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
953                            HEAP_ZERO_MEMORY,
954                            DaclSize);
955     if (Dacl == NULL)
956     {
957         ERR("AllowWinstaAccessToUser(): Failed to allocate memory buffer for DACL!\n");
958         goto Quit;
959     }
960 
961     /* Initialize it */
962     if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
963     {
964         ERR("AllowWinstaAccessToUser(): Failed to initialize DACL (error code %lu)\n", GetLastError());
965         goto Quit;
966     }
967 
968     /* First ACE -- Give full winsta access to Winlogon */
969     if (!AddAccessAllowedAceEx(Dacl,
970                                ACL_REVISION,
971                                NO_PROPAGATE_INHERIT_ACE,
972                                WINSTA_ALL,
973                                WinlogonSid))
974     {
975         ERR("AllowWinstaAccessToUser(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
976         goto Quit;
977     }
978 
979     /* Second ACE -- Give generic access to Winlogon */
980     if (!AddAccessAllowedAceEx(Dacl,
981                                ACL_REVISION,
982                                INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
983                                GENERIC_ACCESS,
984                                WinlogonSid))
985     {
986         ERR("AllowWinstaAccessToUser(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
987         goto Quit;
988     }
989 
990     /* Third ACE -- Give limited winsta access to admins */
991     if (!AddAccessAllowedAceEx(Dacl,
992                                ACL_REVISION,
993                                NO_PROPAGATE_INHERIT_ACE,
994                                WINSTA_ADMINS_LIMITED,
995                                AdminsSid))
996     {
997         ERR("AllowWinstaAccessToUser(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
998         goto Quit;
999     }
1000 
1001     /* Fourth ACE -- Give limited desktop access to admins */
1002     if (!AddAccessAllowedAceEx(Dacl,
1003                                ACL_REVISION,
1004                                INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
1005                                DESKTOP_ADMINS_LIMITED,
1006                                AdminsSid))
1007     {
1008         ERR("AllowWinstaAccessToUser(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
1009         goto Quit;
1010     }
1011 
1012     /* Fifth ACE -- Give full winsta access to interactive logon users */
1013     if (!AddAccessAllowedAceEx(Dacl,
1014                                ACL_REVISION,
1015                                NO_PROPAGATE_INHERIT_ACE,
1016                                WINSTA_ALL,
1017                                InteractiveSid))
1018     {
1019         ERR("AllowWinstaAccessToUser(): Failed to set ACE for interactive SID (error code %lu)\n", GetLastError());
1020         goto Quit;
1021     }
1022 
1023     /* Sixth ACE -- Give generic access to interactive logon users */
1024     if (!AddAccessAllowedAceEx(Dacl,
1025                                ACL_REVISION,
1026                                INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
1027                                GENERIC_ACCESS,
1028                                InteractiveSid))
1029     {
1030         ERR("AllowWinstaAccessToUser(): Failed to set ACE for interactive SID (error code %lu)\n", GetLastError());
1031         goto Quit;
1032     }
1033 
1034     /* Seventh ACE -- Give full winsta access to logon user */
1035     if (!AddAccessAllowedAceEx(Dacl,
1036                                ACL_REVISION,
1037                                NO_PROPAGATE_INHERIT_ACE,
1038                                WINSTA_ALL,
1039                                LogonSid))
1040     {
1041         ERR("AllowWinstaAccessToUser(): Failed to set ACE for logon user SID (error code %lu)\n", GetLastError());
1042         goto Quit;
1043     }
1044 
1045     /* Eighth ACE -- Give generic access to logon user */
1046     if (!AddAccessAllowedAceEx(Dacl,
1047                                ACL_REVISION,
1048                                INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
1049                                GENERIC_ACCESS,
1050                                LogonSid))
1051     {
1052         ERR("AllowWinstaAccessToUser(): Failed to set ACE for logon user SID (error code %lu)\n", GetLastError());
1053         goto Quit;
1054     }
1055 
1056     /* HACK : Ninenth ACE -- Give full winsta access to network services */
1057     if (!AddAccessAllowedAceEx(Dacl,
1058                                ACL_REVISION,
1059                                NO_PROPAGATE_INHERIT_ACE,
1060                                WINSTA_ALL,
1061                                NetworkServiceSid))
1062     {
1063         ERR("AllowWinstaAccessToUser(): Failed to set ACE for logon network service SID (error code %lu)\n", GetLastError());
1064         goto Quit;
1065     }
1066 
1067     /* HACK: Tenth ACE -- Give generic access to network services */
1068     if (!AddAccessAllowedAceEx(Dacl,
1069                                ACL_REVISION,
1070                                INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
1071                                GENERIC_ACCESS,
1072                                NetworkServiceSid))
1073     {
1074         ERR("AllowWinstaAccessToUser(): Failed to set ACE for network service SID (error code %lu)\n", GetLastError());
1075         goto Quit;
1076     }
1077 
1078     /* Initialize the security descriptor */
1079     if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
1080     {
1081         ERR("AllowWinstaAccessToUser(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
1082         goto Quit;
1083     }
1084 
1085     /* Set the DACL to descriptor */
1086     if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
1087     {
1088         ERR("AllowWinstaAccessToUser(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
1089         goto Quit;
1090     }
1091 
1092     /* Convert it to self-relative format */
1093     RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
1094     if (RelativeSd == NULL)
1095     {
1096         ERR("AllowWinstaAccessToUser(): Failed to convert security descriptor to self relative format!\n");
1097         goto Quit;
1098     }
1099 
1100     /* Set new winsta security based on this descriptor */
1101     SecurityInformation = DACL_SECURITY_INFORMATION;
1102     if (!SetUserObjectSecurity(WinSta, &SecurityInformation, RelativeSd))
1103     {
1104         ERR("AllowWinstaAccessToUser(): Failed to set window station security descriptor (error code %lu)\n", GetLastError());
1105         goto Quit;
1106     }
1107 
1108     Success = TRUE;
1109 
1110 Quit:
1111     if (WinlogonSid != NULL)
1112     {
1113         FreeSid(WinlogonSid);
1114     }
1115 
1116     if (AdminsSid != NULL)
1117     {
1118         FreeSid(AdminsSid);
1119     }
1120 
1121     if (InteractiveSid != NULL)
1122     {
1123         FreeSid(InteractiveSid);
1124     }
1125 
1126     /* HACK */
1127     if (NetworkServiceSid != NULL)
1128     {
1129         FreeSid(NetworkServiceSid);
1130     }
1131     /* END HACK */
1132 
1133     if (Dacl != NULL)
1134     {
1135         RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
1136     }
1137 
1138     if (RelativeSd != NULL)
1139     {
1140         RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
1141     }
1142 
1143     return Success;
1144 }
1145 
1146 /**
1147  * @brief
1148  * Assigns access to the specific logon user to
1149  * the default desktop. Such access is given to
1150  * the user when it has logged in.
1151  *
1152  * @param[in] Desktop
1153  * A handle to a desktop where the user
1154  * is given access to it.
1155  *
1156  * @param[in] LogonSid
1157  * A pointer to a logon SID that represents
1158  * the logged in user in question.
1159  *
1160  * @return
1161  * Returns TRUE if the function has successfully
1162  * assigned access to the user, FALSE otherwise.
1163  */
1164 BOOL
1165 AllowDesktopAccessToUser(
1166     _In_ HDESK Desktop,
1167     _In_ PSID LogonSid)
1168 {
1169     BOOL Success = FALSE;
1170     SECURITY_DESCRIPTOR AbsoluteSd;
1171     PSECURITY_DESCRIPTOR RelativeSd = NULL;
1172     PSID WinlogonSid = NULL, AdminsSid = NULL, InteractiveSid = NULL, NetworkServiceSid = NULL; /* NetworkServiceSid is a HACK, see the comment in CreateWinstaSecurity for information */
1173     SECURITY_INFORMATION SecurityInformation;
1174     DWORD DaclSize;
1175     PACL Dacl;
1176 
1177     /* Create the Winlogon SID */
1178     if (!AllocateAndInitializeSid(&NtAuthority,
1179                                   1,
1180                                   SECURITY_LOCAL_SYSTEM_RID,
1181                                   0, 0, 0, 0, 0, 0, 0,
1182                                   &WinlogonSid))
1183     {
1184         ERR("AllowDesktopAccessToUser(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
1185         return FALSE;
1186     }
1187 
1188     /* Create the admins SID */
1189     if (!AllocateAndInitializeSid(&NtAuthority,
1190                                   2,
1191                                   SECURITY_BUILTIN_DOMAIN_RID,
1192                                   DOMAIN_ALIAS_RID_ADMINS,
1193                                   0, 0, 0, 0, 0, 0,
1194                                   &AdminsSid))
1195     {
1196         ERR("AllowDesktopAccessToUser(): Failed to create the admins SID (error code %lu)\n", GetLastError());
1197         goto Quit;
1198     }
1199 
1200     /* Create the interactive logon SID */
1201     if (!AllocateAndInitializeSid(&NtAuthority,
1202                                   1,
1203                                   SECURITY_INTERACTIVE_RID,
1204                                   0, 0, 0, 0, 0, 0, 0,
1205                                   &InteractiveSid))
1206     {
1207         ERR("AllowDesktopAccessToUser(): Failed to create the interactive SID (error code %lu)\n", GetLastError());
1208         goto Quit;
1209     }
1210 
1211     /* HACK: Create the network service SID */
1212     if (!AllocateAndInitializeSid(&NtAuthority,
1213                                   1,
1214                                   SECURITY_NETWORK_SERVICE_RID,
1215                                   0, 0, 0, 0, 0, 0, 0,
1216                                   &NetworkServiceSid))
1217     {
1218         ERR("AllowDesktopAccessToUser(): Failed to create the network service SID (error code %lu)\n", GetLastError());
1219         goto Quit;
1220     }
1221 
1222     /*
1223      * Build up the DACL size. This includes a number
1224      * of four ACEs of four different SIDs. The first ACE
1225      * gives full desktop access to Winlogon, the second one gives
1226      * generic limited desktop access to admins. The last two give
1227      * full power to both interactive logon users and logon user as
1228      * well.
1229      */
1230     DaclSize = sizeof(ACL) +
1231                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
1232                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
1233                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(InteractiveSid) +
1234                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(LogonSid) +
1235                sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(NetworkServiceSid); /* HACK */
1236 
1237     /* Allocate the DACL now */
1238     Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
1239                            HEAP_ZERO_MEMORY,
1240                            DaclSize);
1241     if (Dacl == NULL)
1242     {
1243         ERR("AllowDesktopAccessToUser(): Failed to allocate memory buffer for DACL!\n");
1244         goto Quit;
1245     }
1246 
1247     /* Initialize it */
1248     if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
1249     {
1250         ERR("AllowDesktopAccessToUser(): Failed to initialize DACL (error code %lu)\n", GetLastError());
1251         goto Quit;
1252     }
1253 
1254     /* First ACE -- Give full desktop access to Winlogon */
1255     if (!AddAccessAllowedAceEx(Dacl,
1256                                ACL_REVISION,
1257                                0,
1258                                DESKTOP_ALL,
1259                                WinlogonSid))
1260     {
1261         ERR("AllowDesktopAccessToUser(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
1262         goto Quit;
1263     }
1264 
1265     /* Second ACE -- Give limited desktop access to admins */
1266     if (!AddAccessAllowedAceEx(Dacl,
1267                                ACL_REVISION,
1268                                0,
1269                                DESKTOP_ADMINS_LIMITED,
1270                                AdminsSid))
1271     {
1272         ERR("AllowDesktopAccessToUser(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
1273         goto Quit;
1274     }
1275 
1276     /* Third ACE -- Give full desktop access to interactive logon users */
1277     if (!AddAccessAllowedAceEx(Dacl,
1278                                ACL_REVISION,
1279                                0,
1280                                DESKTOP_ALL,
1281                                InteractiveSid))
1282     {
1283         ERR("AllowDesktopAccessToUser(): Failed to set ACE for interactive SID (error code %lu)\n", GetLastError());
1284         goto Quit;
1285     }
1286 
1287     /* Fourth ACE -- Give full desktop access to logon user */
1288     if (!AddAccessAllowedAceEx(Dacl,
1289                                ACL_REVISION,
1290                                0,
1291                                DESKTOP_ALL,
1292                                LogonSid))
1293     {
1294         ERR("AllowDesktopAccessToUser(): Failed to set ACE for logon user SID (error code %lu)\n", GetLastError());
1295         goto Quit;
1296     }
1297 
1298     /* HACK: Fifth ACE -- Give full desktop to network services */
1299     if (!AddAccessAllowedAceEx(Dacl,
1300                                ACL_REVISION,
1301                                0,
1302                                DESKTOP_ALL,
1303                                NetworkServiceSid))
1304     {
1305         ERR("AllowDesktopAccessToUser(): Failed to set ACE for network service SID (error code %lu)\n", GetLastError());
1306         goto Quit;
1307     }
1308 
1309     /* Initialize the security descriptor */
1310     if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
1311     {
1312         ERR("AllowDesktopAccessToUser(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
1313         goto Quit;
1314     }
1315 
1316     /* Set the DACL to the descriptor */
1317     if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
1318     {
1319         ERR("AllowDesktopAccessToUser(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
1320         goto Quit;
1321     }
1322 
1323     /* Conver it to self-relative format */
1324     RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
1325     if (RelativeSd == NULL)
1326     {
1327         ERR("AllowDesktopAccessToUser(): Failed to convert security descriptor to self relative format!\n");
1328         goto Quit;
1329     }
1330 
1331     /* Assign new security to desktop based on this descriptor */
1332     SecurityInformation = DACL_SECURITY_INFORMATION;
1333     if (!SetUserObjectSecurity(Desktop, &SecurityInformation, RelativeSd))
1334     {
1335         ERR("AllowDesktopAccessToUser(): Failed to set desktop security descriptor (error code %lu)\n", GetLastError());
1336         goto Quit;
1337     }
1338 
1339     Success = TRUE;
1340 
1341 Quit:
1342     if (WinlogonSid != NULL)
1343     {
1344         FreeSid(WinlogonSid);
1345     }
1346 
1347     if (AdminsSid != NULL)
1348     {
1349         FreeSid(AdminsSid);
1350     }
1351 
1352     if (InteractiveSid != NULL)
1353     {
1354         FreeSid(InteractiveSid);
1355     }
1356 
1357     /* HACK */
1358     if (NetworkServiceSid != NULL)
1359     {
1360         FreeSid(NetworkServiceSid);
1361     }
1362     /* END HACK */
1363 
1364     if (Dacl != NULL)
1365     {
1366         RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
1367     }
1368 
1369     if (RelativeSd != NULL)
1370     {
1371         RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
1372     }
1373 
1374     return Success;
1375 }
1376 
1377 /**
1378  * @brief
1379  * Assigns both window station and desktop access
1380  * to the specific session currently active on the
1381  * system.
1382  *
1383  * @param[in] Session
1384  * A pointer to an active session.
1385  *
1386  * @return
1387  * Returns TRUE if the function has successfully
1388  * assigned access to the current session, FALSE otherwise.
1389  */
1390 BOOL
1391 AllowAccessOnSession(
1392     _In_ PWLSESSION Session)
1393 {
1394     BOOL Success = FALSE;
1395     DWORD Index, SidLength, GroupsLength = 0;
1396     PTOKEN_GROUPS TokenGroup = NULL;
1397     PSID LogonSid;
1398 
1399     /* Get required buffer size and allocate the TOKEN_GROUPS buffer */
1400     if (!GetTokenInformation(Session->UserToken,
1401                              TokenGroups,
1402                              TokenGroup,
1403                              0,
1404                              &GroupsLength))
1405     {
1406         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1407         {
1408             ERR("AllowAccessOnSession(): Unexpected error code returned, must be ERROR_INSUFFICIENT_BUFFER (error code %lu)\n", GetLastError());
1409             return FALSE;
1410         }
1411 
1412         TokenGroup = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, GroupsLength);
1413         if (TokenGroup == NULL)
1414         {
1415             ERR("AllowAccessOnSession(): Failed to allocate memory buffer for token group!\n");
1416             return FALSE;
1417         }
1418     }
1419 
1420     /* Get the token group information from the access token */
1421     if (!GetTokenInformation(Session->UserToken,
1422                              TokenGroups,
1423                              TokenGroup,
1424                              GroupsLength,
1425                              &GroupsLength))
1426     {
1427         ERR("AllowAccessOnSession(): Failed to retrieve the token group information (error code %lu)\n", GetLastError());
1428         goto Quit;
1429     }
1430 
1431     /* Loop through the groups to find the logon SID */
1432     for (Index = 0; Index < TokenGroup->GroupCount; Index++)
1433     {
1434         if ((TokenGroup->Groups[Index].Attributes & SE_GROUP_LOGON_ID)
1435             == SE_GROUP_LOGON_ID)
1436         {
1437             LogonSid = TokenGroup->Groups[Index].Sid;
1438             break;
1439         }
1440     }
1441 
1442     /* Allow window station access to this user within this session */
1443     if (!AllowWinstaAccessToUser(Session->InteractiveWindowStation, LogonSid))
1444     {
1445         ERR("AllowAccessOnSession(): Failed to allow winsta access to the logon user!\n");
1446         goto Quit;
1447     }
1448 
1449     /* Allow application desktop access to this user within this session */
1450     if (!AllowDesktopAccessToUser(Session->ApplicationDesktop, LogonSid))
1451     {
1452         ERR("AllowAccessOnSession(): Failed to allow application desktop access to the logon user!\n");
1453         goto Quit;
1454     }
1455 
1456     /* Get the length of this logon SID */
1457     SidLength = GetLengthSid(LogonSid);
1458 
1459     /* Assign the window station to this logged in user */
1460     if (!SetWindowStationUser(Session->InteractiveWindowStation,
1461                               &Session->LogonId,
1462                               LogonSid,
1463                               SidLength))
1464     {
1465         ERR("AllowAccessOnSession(): Failed to assign the window station to the logon user!\n");
1466         goto Quit;
1467     }
1468 
1469     Success = TRUE;
1470 
1471 Quit:
1472     if (TokenGroup != NULL)
1473     {
1474         RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroup);
1475     }
1476 
1477     return Success;
1478 }
1479 
1480 /* EOF */
1481