reactos/base/system/winlogon/security.c
George Bișoc f96c39f6b0
[WINLOGON] Refactor the security management part
Refactor the security related code of Winlogon and move it to its own dedicated place, security.c. This includes code for preparation of security descriptors for window station and desktop objects when their created, helper functions which give allow access to such objects for the logged in user and whatnot.

==== DO NOTE ====
Currently new desktop security assignment fails because for whatever reason the system thinks the application desktop has no prior security even though a descriptor has been created for it before. See the FIXME comment on code for information.
2022-05-06 10:09:49 +02:00

1315 lines
43 KiB
C

/*
* PROJECT: ReactOS Winlogon
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Security utility infrastructure implementation of Winlogon
* COPYRIGHT: Copyright 2022 George Bișoc <george.bisoc@reactos.org>
*/
/* INCLUDES *****************************************************************/
#include "winlogon.h"
/* DEFINES ******************************************************************/
#define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \
DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | \
DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \
DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)
#define DESKTOP_ADMINS_LIMITED (DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS | \
DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_ENUMERATE)
#define DESKTOP_INTERACTIVE_LIMITED (STANDARD_RIGHTS_READ | DESKTOP_ENUMERATE | \
DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW)
#define DESKTOP_WINLOGON_ADMINS_LIMITED (STANDARD_RIGHTS_REQUIRED | DESKTOP_ENUMERATE)
#define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \
WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \
WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \
WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | \
STANDARD_RIGHTS_REQUIRED)
#define WINSTA_ADMINS_LIMITED (WINSTA_READATTRIBUTES | WINSTA_ENUMERATE)
#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | \
GENERIC_EXECUTE | GENERIC_ALL)
/* GLOBALS ******************************************************************/
static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY};
/* FUNCTIONS ****************************************************************/
/**
* @brief
* Converts an absolute security descriptor to a self-relative
* format.
*
* @param[in] AbsoluteSd
* A pointer to an absolute security descriptor to be
* converted.
*
* @return
* Returns a pointer to a converted security descriptor in
* self-relative format. If the function fails, NULL is returned
* otherwise.
*
* @remarks
* The function allocates the security descriptor buffer in memory
* heap, the caller is entirely responsible for freeing such buffer
* from when it's no longer needed.
*/
PSECURITY_DESCRIPTOR
ConvertToSelfRelative(
_In_ PSECURITY_DESCRIPTOR AbsoluteSd)
{
PSECURITY_DESCRIPTOR RelativeSd;
DWORD DescriptorLength = 0;
/* Determine the size for our buffer to allocate */
if (!MakeSelfRelativeSD(AbsoluteSd, NULL, &DescriptorLength) && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
ERR("ConvertToSelfRelative(): Unexpected error code (error code %lu -- must be ERROR_INSUFFICIENT_BUFFER)\n", GetLastError());
return NULL;
}
/* Allocate the buffer now */
RelativeSd = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
DescriptorLength);
if (RelativeSd == NULL)
{
ERR("ConvertToSelfRelative(): Failed to allocate buffer for relative SD!\n");
return NULL;
}
/* Convert the security descriptor now */
if (!MakeSelfRelativeSD(AbsoluteSd, RelativeSd, &DescriptorLength))
{
ERR("ConvertToSelfRelative(): Failed to convert the security descriptor to a self relative format (error code %lu)\n", GetLastError());
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
return NULL;
}
return RelativeSd;
}
/**
* @brief
* Creates a security descriptor for the default
* window station upon its creation.
*
* @param[out] WinstaSd
* A pointer to a created security descriptor for
* the window station.
*
* @return
* Returns TRUE if the function has successfully
* created the security descriptor, FALSE otherwise.
*/
BOOL
CreateWinstaSecurity(
_Out_ PSECURITY_DESCRIPTOR *WinstaSd)
{
BOOL Success = FALSE;
SECURITY_DESCRIPTOR AbsoluteSd;
PSECURITY_DESCRIPTOR RelativeSd = NULL;
PSID WinlogonSid = NULL, AdminsSid = NULL;
DWORD DaclSize;
PACL Dacl;
/* Create the Winlogon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&WinlogonSid))
{
ERR("CreateWinstaSecurity(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
return FALSE;
}
/* Create the admins SID */
if (!AllocateAndInitializeSid(&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdminsSid))
{
ERR("CreateWinstaSecurity(): Failed to create the admins SID (error code %lu)\n", GetLastError());
goto Quit;
}
/*
* Build up the DACL size. This includes a number
* of four ACEs of two different SIDs. The first two
* ACEs give both window station and generic access
* to Winlogon, the last two give limited window station
* and desktop access to admins.
*/
DaclSize = sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid);
/* Allocate the DACL now */
Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
DaclSize);
if (Dacl == NULL)
{
ERR("CreateWinstaSecurity(): Failed to allocate memory buffer for DACL!\n");
goto Quit;
}
/* Initialize it */
if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
{
ERR("CreateWinstaSecurity(): Failed to initialize DACL (error code %lu)\n", GetLastError());
goto Quit;
}
/* First ACE -- give full winsta access to Winlogon */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
NO_PROPAGATE_INHERIT_ACE,
WINSTA_ALL,
WinlogonSid))
{
ERR("CreateWinstaSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
goto Quit;
}
/* Second ACE -- give full generic access to Winlogon */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
GENERIC_ACCESS,
WinlogonSid))
{
ERR("CreateWinstaSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
goto Quit;
}
/* Third ACE -- give limited winsta access to admins */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
NO_PROPAGATE_INHERIT_ACE,
WINSTA_ADMINS_LIMITED,
AdminsSid))
{
ERR("CreateWinstaSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
goto Quit;
}
/* Fourth ACE -- give limited desktop access to admins */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
DESKTOP_ADMINS_LIMITED,
AdminsSid))
{
ERR("CreateWinstaSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
goto Quit;
}
/* Initialize the security descriptor */
if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
{
ERR("CreateWinstaSecurity(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Set the DACL to the descriptor */
if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
{
ERR("CreateWinstaSecurity(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Convert it to self-relative format */
RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
if (RelativeSd == NULL)
{
ERR("CreateWinstaSecurity(): Failed to convert security descriptor to self relative format!\n");
goto Quit;
}
/* Give the descriptor to the caller */
*WinstaSd = RelativeSd;
Success = TRUE;
Quit:
if (WinlogonSid != NULL)
{
FreeSid(WinlogonSid);
}
if (AdminsSid != NULL)
{
FreeSid(AdminsSid);
}
if (Dacl != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
}
if (Success == FALSE)
{
if (RelativeSd != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
}
}
return Success;
}
/**
* @brief
* Creates a security descriptor for the default
* application desktop upon its creation.
*
* @param[out] ApplicationDesktopSd
* A pointer to a created security descriptor for
* the application desktop.
*
* @return
* Returns TRUE if the function has successfully
* created the security descriptor, FALSE otherwise.
*/
BOOL
CreateApplicationDesktopSecurity(
_Out_ PSECURITY_DESCRIPTOR *ApplicationDesktopSd)
{
BOOL Success = FALSE;
SECURITY_DESCRIPTOR AbsoluteSd;
PSECURITY_DESCRIPTOR RelativeSd = NULL;
PSID WinlogonSid = NULL, AdminsSid = NULL;
DWORD DaclSize;
PACL Dacl;
/* Create the Winlogon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&WinlogonSid))
{
ERR("CreateApplicationDesktopSecurity(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
return FALSE;
}
/* Create the admins SID */
if (!AllocateAndInitializeSid(&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdminsSid))
{
ERR("CreateApplicationDesktopSecurity(): Failed to create the admins SID (error code %lu)\n", GetLastError());
goto Quit;
}
/*
* Build up the DACL size. This includes a number
* of two ACEs of two different SIDs. The first ACE
* gives full access to Winlogon, the last one gives
* limited desktop access to admins.
*/
DaclSize = sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid);
/* Allocate the DACL now */
Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
DaclSize);
if (Dacl == NULL)
{
ERR("CreateApplicationDesktopSecurity(): Failed to allocate memory buffer for DACL!\n");
goto Quit;
}
/* Initialize it */
if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
{
ERR("CreateApplicationDesktopSecurity(): Failed to initialize DACL (error code %lu)\n", GetLastError());
goto Quit;
}
/* First ACE -- Give full desktop power to Winlogon */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_ALL,
WinlogonSid))
{
ERR("CreateApplicationDesktopSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
goto Quit;
}
/* Second ACE -- Give limited desktop power to admins */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_ADMINS_LIMITED,
AdminsSid))
{
ERR("CreateApplicationDesktopSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
goto Quit;
}
/* Initialize the security descriptor */
if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
{
ERR("CreateApplicationDesktopSecurity(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Set the DACL to the descriptor */
if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
{
ERR("CreateApplicationDesktopSecurity(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Conver it to self-relative format */
RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
if (RelativeSd == NULL)
{
ERR("CreateApplicationDesktopSecurity(): Failed to convert security descriptor to self relative format!\n");
goto Quit;
}
/* Give the descriptor to the caller */
*ApplicationDesktopSd = RelativeSd;
Success = TRUE;
Quit:
if (WinlogonSid != NULL)
{
FreeSid(WinlogonSid);
}
if (AdminsSid != NULL)
{
FreeSid(AdminsSid);
}
if (Dacl != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
}
if (Success == FALSE)
{
if (RelativeSd != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
}
}
return Success;
}
/**
* @brief
* Creates a security descriptor for the default
* Winlogon desktop. This descriptor serves as a
* security measure for the winlogon desktop so
* that only Winlogon itself (and admins) can
* interact with it.
*
* @param[out] WinlogonDesktopSd
* A pointer to a created security descriptor for
* the Winlogon desktop.
*
* @return
* Returns TRUE if the function has successfully
* created the security descriptor, FALSE otherwise.
*/
BOOL
CreateWinlogonDesktopSecurity(
_Out_ PSECURITY_DESCRIPTOR *WinlogonDesktopSd)
{
BOOL Success = FALSE;
SECURITY_DESCRIPTOR AbsoluteSd;
PSECURITY_DESCRIPTOR RelativeSd = NULL;
PSID WinlogonSid = NULL, AdminsSid = NULL;
DWORD DaclSize;
PACL Dacl;
/* Create the Winlogon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&WinlogonSid))
{
ERR("CreateWinlogonDesktopSecurity(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
return FALSE;
}
/* Create the admins SID */
if (!AllocateAndInitializeSid(&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdminsSid))
{
ERR("CreateWinlogonDesktopSecurity(): Failed to create the admins SID (error code %lu)\n", GetLastError());
goto Quit;
}
/*
* Build up the DACL size. This includes a number
* of two ACEs of two different SIDs. The first ACE
* gives full access to Winlogon, the last one gives
* limited desktop access to admins.
*/
DaclSize = sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid);
/* Allocate the DACL now */
Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
DaclSize);
if (Dacl == NULL)
{
ERR("CreateWinlogonDesktopSecurity(): Failed to allocate memory buffer for DACL!\n");
goto Quit;
}
/* Initialize it */
if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
{
ERR("CreateWinlogonDesktopSecurity(): Failed to initialize DACL (error code %lu)\n", GetLastError());
goto Quit;
}
/* First ACE -- Give full desktop access to Winlogon */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_ALL,
WinlogonSid))
{
ERR("CreateWinlogonDesktopSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
goto Quit;
}
/* Second ACE -- Give limited desktop access to admins */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_WINLOGON_ADMINS_LIMITED,
AdminsSid))
{
ERR("CreateWinlogonDesktopSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
goto Quit;
}
/* Initialize the security descriptor */
if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
{
ERR("CreateWinlogonDesktopSecurity(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Set the DACL to the descriptor */
if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
{
ERR("CreateWinlogonDesktopSecurity(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Conver it to self-relative format */
RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
if (RelativeSd == NULL)
{
ERR("CreateWinlogonDesktopSecurity(): Failed to convert security descriptor to self relative format!\n");
goto Quit;
}
/* Give the descriptor to the caller */
*WinlogonDesktopSd = RelativeSd;
Success = TRUE;
Quit:
if (WinlogonSid != NULL)
{
FreeSid(WinlogonSid);
}
if (AdminsSid != NULL)
{
FreeSid(AdminsSid);
}
if (Dacl != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
}
if (Success == FALSE)
{
if (RelativeSd != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
}
}
return Success;
}
/**
* @brief
* Creates a security descriptor for the screen
* saver desktop.
*
* @param[out] ScreenSaverDesktopSd
* A pointer to a created security descriptor for
* the screen-saver desktop.
*
* @return
* Returns TRUE if the function has successfully
* created the security descriptor, FALSE otherwise.
*/
BOOL
CreateScreenSaverSecurity(
_Out_ PSECURITY_DESCRIPTOR *ScreenSaverDesktopSd)
{
BOOL Success = FALSE;
SECURITY_DESCRIPTOR AbsoluteSd;
PSECURITY_DESCRIPTOR RelativeSd = NULL;
PSID WinlogonSid = NULL, AdminsSid = NULL, InteractiveSid = NULL;
DWORD DaclSize;
PACL Dacl;
/* Create the Winlogon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&WinlogonSid))
{
ERR("CreateScreenSaverSecurity(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
return FALSE;
}
/* Create the admins SID */
if (!AllocateAndInitializeSid(&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdminsSid))
{
ERR("CreateScreenSaverSecurity(): Failed to create the admins SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Create the interactive logon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_INTERACTIVE_RID,
0, 0, 0, 0, 0, 0, 0,
&InteractiveSid))
{
ERR("CreateScreenSaverSecurity(): Failed to create the interactive SID (error code %lu)\n", GetLastError());
goto Quit;
}
/*
* Build up the DACL size. This includes a number
* of three ACEs of three different SIDs. The first ACE
* gives full access to Winlogon, the second one gives
* limited desktop access to admins and the last one
* gives full desktop access to users who have logged in
* interactively.
*/
DaclSize = sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(InteractiveSid);
/* Allocate the DACL now */
Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
DaclSize);
if (Dacl == NULL)
{
ERR("CreateScreenSaverSecurity(): Failed to allocate memory buffer for DACL!\n");
goto Quit;
}
/* Initialize it */
if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
{
ERR("CreateScreenSaverSecurity(): Failed to initialize DACL (error code %lu)\n", GetLastError());
goto Quit;
}
/* First ACE -- Give full desktop access to Winlogon */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_ALL,
WinlogonSid))
{
ERR("CreateScreenSaverSecurity(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
goto Quit;
}
/* Second ACE -- Give limited desktop access to admins */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
NO_PROPAGATE_INHERIT_ACE,
DESKTOP_ADMINS_LIMITED,
AdminsSid))
{
ERR("CreateScreenSaverSecurity(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
goto Quit;
}
/* Third ACE -- Give full desktop access to interactive logon users */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
NO_PROPAGATE_INHERIT_ACE,
DESKTOP_INTERACTIVE_LIMITED,
InteractiveSid))
{
ERR("CreateScreenSaverSecurity(): Failed to set ACE for interactive SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Initialize the security descriptor */
if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
{
ERR("CreateScreenSaverSecurity(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Set the DACL to the descriptor */
if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
{
ERR("CreateScreenSaverSecurity(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Conver it to self-relative format */
RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
if (RelativeSd == NULL)
{
ERR("CreateScreenSaverSecurity(): Failed to convert security descriptor to self relative format!\n");
goto Quit;
}
/* Give the descriptor to the caller */
*ScreenSaverDesktopSd = RelativeSd;
Success = TRUE;
Quit:
if (WinlogonSid != NULL)
{
FreeSid(WinlogonSid);
}
if (AdminsSid != NULL)
{
FreeSid(AdminsSid);
}
if (InteractiveSid != NULL)
{
FreeSid(InteractiveSid);
}
if (Dacl != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
}
if (Success == FALSE)
{
if (RelativeSd != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
}
}
return Success;
}
/**
* @brief
* Assigns access to the specific logon user to
* the default window station. Such access is
* given to the user when it has logged in.
*
* @param[in] WinSta
* A handle to a window station where the
* user is given access to it.
*
* @param[in] LogonSid
* A pointer to a logon SID that represents
* the logged in user in question.
*
* @return
* Returns TRUE if the function has successfully
* assigned access to the user, FALSE otherwise.
*/
BOOL
AllowWinstaAccessToUser(
_In_ HWINSTA WinSta,
_In_ PSID LogonSid)
{
BOOL Success = FALSE;
SECURITY_DESCRIPTOR AbsoluteSd;
PSECURITY_DESCRIPTOR RelativeSd = NULL;
PSID WinlogonSid = NULL, AdminsSid = NULL, InteractiveSid = NULL;
SECURITY_INFORMATION SecurityInformation;
DWORD DaclSize;
PACL Dacl;
/* Create the Winlogon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&WinlogonSid))
{
ERR("AllowWinstaAccessToUser(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
return FALSE;
}
/* Create the admins SID */
if (!AllocateAndInitializeSid(&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdminsSid))
{
ERR("AllowWinstaAccessToUser(): Failed to create the admins SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Create the interactive logon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_INTERACTIVE_RID,
0, 0, 0, 0, 0, 0, 0,
&InteractiveSid))
{
ERR("AllowWinstaAccessToUser(): Failed to create the interactive SID (error code %lu)\n", GetLastError());
goto Quit;
}
/*
* Build up the DACL size. This includes a number
* of eight ACEs of four different SIDs. The first ACE
* gives full winsta access to Winlogon, the second one gives
* generic access to Winlogon. Such approach is the same
* for both interactive logon users and logon user as well.
* Only admins are given limited powers.
*/
DaclSize = sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(InteractiveSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(InteractiveSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(LogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(LogonSid);
/* Allocate the DACL now */
Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
DaclSize);
if (Dacl == NULL)
{
ERR("AllowWinstaAccessToUser(): Failed to allocate memory buffer for DACL!\n");
goto Quit;
}
/* Initialize it */
if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
{
ERR("AllowWinstaAccessToUser(): Failed to initialize DACL (error code %lu)\n", GetLastError());
goto Quit;
}
/* First ACE -- Give full winsta access to Winlogon */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
NO_PROPAGATE_INHERIT_ACE,
WINSTA_ALL,
WinlogonSid))
{
ERR("AllowWinstaAccessToUser(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
goto Quit;
}
/* Second ACE -- Give generic access to Winlogon */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
GENERIC_ACCESS,
WinlogonSid))
{
ERR("AllowWinstaAccessToUser(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
goto Quit;
}
/* Third ACE -- Give limited winsta access to admins */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
NO_PROPAGATE_INHERIT_ACE,
WINSTA_ADMINS_LIMITED,
AdminsSid))
{
ERR("AllowWinstaAccessToUser(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
goto Quit;
}
/* Fourth ACE -- Give limited desktop access to admins */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
DESKTOP_ADMINS_LIMITED,
AdminsSid))
{
ERR("AllowWinstaAccessToUser(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
goto Quit;
}
/* Fifth ACE -- Give full winsta access to interactive logon users */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
NO_PROPAGATE_INHERIT_ACE,
WINSTA_ALL,
InteractiveSid))
{
ERR("AllowWinstaAccessToUser(): Failed to set ACE for interactive SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Sixth ACE -- Give generic access to interactive logon users */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
GENERIC_ACCESS,
InteractiveSid))
{
ERR("AllowWinstaAccessToUser(): Failed to set ACE for interactive SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Seventh ACE -- Give full winsta access to logon user */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
NO_PROPAGATE_INHERIT_ACE,
WINSTA_ALL,
LogonSid))
{
ERR("AllowWinstaAccessToUser(): Failed to set ACE for logon user SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Eighth ACE -- Give generic access to logon user */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
GENERIC_ACCESS,
LogonSid))
{
ERR("AllowWinstaAccessToUser(): Failed to set ACE for logon user SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Initialize the security descriptor */
if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
{
ERR("AllowWinstaAccessToUser(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Set the DACL to descriptor */
if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
{
ERR("AllowWinstaAccessToUser(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Convert it to self-relative format */
RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
if (RelativeSd == NULL)
{
ERR("AllowWinstaAccessToUser(): Failed to convert security descriptor to self relative format!\n");
goto Quit;
}
/* Set new winsta security based on this descriptor */
SecurityInformation = DACL_SECURITY_INFORMATION;
if (!SetUserObjectSecurity(WinSta, &SecurityInformation, RelativeSd))
{
ERR("AllowWinstaAccessToUser(): Failed to set window station security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
Success = TRUE;
Quit:
if (WinlogonSid != NULL)
{
FreeSid(WinlogonSid);
}
if (AdminsSid != NULL)
{
FreeSid(AdminsSid);
}
if (InteractiveSid != NULL)
{
FreeSid(InteractiveSid);
}
if (Dacl != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
}
if (RelativeSd != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
}
return Success;
}
/**
* @brief
* Assigns access to the specific logon user to
* the default desktop. Such access is given to
* the user when it has logged in.
*
* @param[in] Desktop
* A handle to a desktop where the user
* is given access to it.
*
* @param[in] LogonSid
* A pointer to a logon SID that represents
* the logged in user in question.
*
* @return
* Returns TRUE if the function has successfully
* assigned access to the user, FALSE otherwise.
*/
BOOL
AllowDesktopAccessToUser(
_In_ HDESK Desktop,
_In_ PSID LogonSid)
{
BOOL Success = FALSE;
SECURITY_DESCRIPTOR AbsoluteSd;
PSECURITY_DESCRIPTOR RelativeSd = NULL;
PSID WinlogonSid = NULL, AdminsSid = NULL, InteractiveSid = NULL;
SECURITY_INFORMATION SecurityInformation;
DWORD DaclSize;
PACL Dacl;
/* Create the Winlogon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&WinlogonSid))
{
ERR("AllowDesktopAccessToUser(): Failed to create the Winlogon SID (error code %lu)\n", GetLastError());
return FALSE;
}
/* Create the admins SID */
if (!AllocateAndInitializeSid(&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdminsSid))
{
ERR("AllowDesktopAccessToUser(): Failed to create the admins SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Create the interactive logon SID */
if (!AllocateAndInitializeSid(&NtAuthority,
1,
SECURITY_INTERACTIVE_RID,
0, 0, 0, 0, 0, 0, 0,
&InteractiveSid))
{
ERR("AllowDesktopAccessToUser(): Failed to create the interactive SID (error code %lu)\n", GetLastError());
goto Quit;
}
/*
* Build up the DACL size. This includes a number
* of four ACEs of four different SIDs. The first ACE
* gives full desktop access to Winlogon, the second one gives
* generic limited desktop access to admins. The last two give
* full power to both interactive logon users and logon user as
* well.
*/
DaclSize = sizeof(ACL) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(WinlogonSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(AdminsSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(InteractiveSid) +
sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + GetLengthSid(LogonSid);
/* Allocate the DACL now */
Dacl = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
DaclSize);
if (Dacl == NULL)
{
ERR("AllowDesktopAccessToUser(): Failed to allocate memory buffer for DACL!\n");
goto Quit;
}
/* Initialize it */
if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION))
{
ERR("AllowDesktopAccessToUser(): Failed to initialize DACL (error code %lu)\n", GetLastError());
goto Quit;
}
/* First ACE -- Give full desktop access to Winlogon */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_ALL,
WinlogonSid))
{
ERR("AllowDesktopAccessToUser(): Failed to set ACE for Winlogon (error code %lu)\n", GetLastError());
goto Quit;
}
/* Second ACE -- Give limited desktop access to admins */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_ADMINS_LIMITED,
AdminsSid))
{
ERR("AllowDesktopAccessToUser(): Failed to set ACE for admins (error code %lu)\n", GetLastError());
goto Quit;
}
/* Third ACE -- Give full desktop access to interactive logon users */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_ALL,
InteractiveSid))
{
ERR("AllowDesktopAccessToUser(): Failed to set ACE for interactive SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Fourth ACE -- Give full desktop access to logon user */
if (!AddAccessAllowedAceEx(Dacl,
ACL_REVISION,
0,
DESKTOP_ALL,
LogonSid))
{
ERR("AllowDesktopAccessToUser(): Failed to set ACE for logon user SID (error code %lu)\n", GetLastError());
goto Quit;
}
/* Initialize the security descriptor */
if (!InitializeSecurityDescriptor(&AbsoluteSd, SECURITY_DESCRIPTOR_REVISION))
{
ERR("AllowDesktopAccessToUser(): Failed to initialize absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Set the DACL to the descriptor */
if (!SetSecurityDescriptorDacl(&AbsoluteSd, TRUE, Dacl, FALSE))
{
ERR("AllowDesktopAccessToUser(): Failed to set up DACL to absolute security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
/* Conver it to self-relative format */
RelativeSd = ConvertToSelfRelative(&AbsoluteSd);
if (RelativeSd == NULL)
{
ERR("AllowDesktopAccessToUser(): Failed to convert security descriptor to self relative format!\n");
goto Quit;
}
/* Assign new security to desktop based on this descriptor */
SecurityInformation = DACL_SECURITY_INFORMATION;
if (!SetUserObjectSecurity(Desktop, &SecurityInformation, RelativeSd))
{
ERR("AllowDesktopAccessToUser(): Failed to set desktop security descriptor (error code %lu)\n", GetLastError());
goto Quit;
}
Success = TRUE;
Quit:
if (WinlogonSid != NULL)
{
FreeSid(WinlogonSid);
}
if (AdminsSid != NULL)
{
FreeSid(AdminsSid);
}
if (InteractiveSid != NULL)
{
FreeSid(InteractiveSid);
}
if (Dacl != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl);
}
if (RelativeSd != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, RelativeSd);
}
return Success;
}
/**
* @brief
* Assigns both window station and desktop access
* to the specific session currently active on the
* system.
*
* @param[in] Session
* A pointer to an active session.
*
* @return
* Returns TRUE if the function has successfully
* assigned access to the current session, FALSE otherwise.
*/
BOOL
AllowAccessOnSession(
_In_ PWLSESSION Session)
{
BOOL Success = FALSE;
DWORD Index, SidLength, GroupsLength = 0;
PTOKEN_GROUPS TokenGroup = NULL;
PSID LogonSid;
/* Get required buffer size and allocate the TOKEN_GROUPS buffer */
if (!GetTokenInformation(Session->UserToken,
TokenGroups,
TokenGroup,
0,
&GroupsLength))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
ERR("AllowAccessOnSession(): Unexpected error code returned, must be ERROR_INSUFFICIENT_BUFFER (error code %lu)\n", GetLastError());
return FALSE;
}
TokenGroup = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, GroupsLength);
if (TokenGroup == NULL)
{
ERR("AllowAccessOnSession(): Failed to allocate memory buffer for token group!\n");
return FALSE;
}
}
/* Get the token group information from the access token */
if (!GetTokenInformation(Session->UserToken,
TokenGroups,
TokenGroup,
GroupsLength,
&GroupsLength))
{
ERR("AllowAccessOnSession(): Failed to retrieve the token group information (error code %lu)\n", GetLastError());
goto Quit;
}
/* Loop through the groups to find the logon SID */
for (Index = 0; Index < TokenGroup->GroupCount; Index++)
{
if ((TokenGroup->Groups[Index].Attributes & SE_GROUP_LOGON_ID)
== SE_GROUP_LOGON_ID)
{
LogonSid = TokenGroup->Groups[Index].Sid;
break;
}
}
/* Allow window station access to this user within this session */
if (!AllowWinstaAccessToUser(Session->InteractiveWindowStation, LogonSid))
{
ERR("AllowAccessOnSession(): Failed to allow winsta access to the logon user!\n");
goto Quit;
}
/*
* FIXME: Desktop security management is broken. The application desktop gets created
* with CreateDesktopW() API call with an initial and defined security descriptor for it yet
* when we are giving access to the logged in user, SetUserObjectSecurity() API call fails to set
* new security because the desktop in question has no prior security descriptor (when it's
* been assigned even before!!!). This chunk of code must be enabled when this gets fixed.
*/
#if 0
/* Allow application desktop access to this user within this session */
if (!AllowDesktopAccessToUser(Session->ApplicationDesktop, LogonSid))
{
ERR("AllowAccessOnSession(): Failed to allow application desktop access to the logon user!\n");
goto Quit;
}
#endif
/* Get the length of this logon SID */
SidLength = GetLengthSid(LogonSid);
/* Assign the window station to this logged in user */
if (!SetWindowStationUser(Session->InteractiveWindowStation,
&Session->LogonId,
LogonSid,
SidLength))
{
ERR("AllowAccessOnSession(): Failed to assign the window station to the logon user!\n");
goto Quit;
}
Success = TRUE;
Quit:
if (TokenGroup != NULL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, TokenGroup);
}
return Success;
}
/* EOF */