Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1650 lines
46 KiB

/*
Copyright (c) 1992 Microsoft Corporation
Module Name:
access.c
Abstract:
This module contains the routines for handling access related stuff.
Author:
Jameel Hyder (microsoft!jameelh)
Revision History:
20 Sep 1992 Initial Version
Notes: Tab stop: 4
--*/
#define FILENUM FILE_ACCESS
#include <afp.h>
#include <fdparm.h>
#include <pathmap.h>
#define _ACCESS_LOCALS
#include <access.h>
#include <client.h>
#include <secutil.h>
#include <seposix.h>
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, AfpGetUserAndPrimaryGroupSids)
#pragma alloc_text( PAGE, AfpMakeSecurityDescriptorForUser)
#pragma alloc_text( PAGE, AfpGetAfpPermissions)
#pragma alloc_text( PAGE, afpMoveAces)
#pragma alloc_text( PAGE, AfpSetAfpPermissions)
#pragma alloc_text( PAGE, afpPermissions2NtMask)
#pragma alloc_text( PAGE, afpAddAceToAcl)
#if DBG
#pragma alloc_text( PAGE, AfpDumpSid)
#pragma alloc_text( PAGE, AfpDumpSidnMask)
#endif
#endif
#define ACCESS_CHECK_ACCESS_MASK 0x01
#define GRPS_BUFFER_SIZE 1024
/*** AfpMakeSecDescForAccessCheck
*
* Create a security descriptor for a SID. The security descriptor has the
* Aces for the User alone.
*/
AFPSTATUS
AfpMakeSecDescForAccessCheck(
IN PSID OwnerSid,
OUT PISECURITY_DESCRIPTOR * ppSecDesc
)
{
AFPSTATUS Status = AFP_ERR_MISC;
PISECURITY_DESCRIPTOR pSecDesc;
int DaclSize;
PACCESS_ALLOWED_ACE pAce;
PAGED_CODE( );
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpMakeSecDescForAccessCheck: Entered\n"));
do
{
// Allocate a security descriptor
pSecDesc = (PISECURITY_DESCRIPTOR)ALLOC_ACCESS_MEM(sizeof(SECURITY_DESCRIPTOR));
*ppSecDesc = pSecDesc;
if (pSecDesc == NULL)
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
("ALLOC_ACCESS_MEM error for pSecDesc\n"));
break;
}
// Initialize the security descriptor
RtlCreateSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION);
pSecDesc->Control = SE_DACL_PRESENT;
// Set the owner and group Ids in the descriptor
pSecDesc->Owner = OwnerSid;
// Determine the size of the Dacl needed. The sizeof(DWORD) offsets the
// SidStart field in the ACE.
//
// 2 ACEs for the owner (owner+inherit for owner)
DaclSize = sizeof(ACL) + 2*(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) +
RtlLengthSid(OwnerSid));
if ((pSecDesc->Dacl = (PACL)ALLOC_ACCESS_MEM(DaclSize)) == NULL)
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
("ALLOC_ACCESS_MEM error for pSecDesc->Dacl\n"));
break;
}
// Initialize the ACL with one ACE corres. to Owner getting all the
// privileges. Add another ace which is identical to the first ace but is
// a inheritance ACE.
RtlCreateAcl(pSecDesc->Dacl, DaclSize, ACL_REVISION);
// we will be adding to this as we add aces, so set it to the min here
pSecDesc->Dacl->AclSize = sizeof(ACL);
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pSecDesc->Dacl + sizeof(ACL));
// Add the ALLOWED_ACE and the corres. inherit Ace for owner
pAce = afpAddAceToAcl(pSecDesc->Dacl,
pAce,
ACCESS_CHECK_ACCESS_MASK,
OwnerSid,
True);
Status = AFP_ERR_NONE;
} while (False);
// Do any cleanup on error
if (!NT_SUCCESS(Status) && (pSecDesc != NULL))
{
if (pSecDesc->Dacl != NULL)
AfpFreeMemory(pSecDesc->Dacl);
AfpFreeMemory(pSecDesc);
pSecDesc = NULL;
}
return Status;
}
/*** afpCheckUserMemberOfGroup
*
* Determine if the User is member of the given group, if it is a group.
*/
LOCAL BOOLEAN
afpCheckUserMemberOfGroup(
IN PSDA pSda,
IN PSID pSidGroup
)
{
DWORD i;
BOOLEAN IsAMember = False;
PISECURITY_DESCRIPTOR pSecDesc = NULL;
SECURITY_SUBJECT_CONTEXT SecSubjectContext = {0};
ACCESS_MASK CheckAccessMaskIn = 0, CheckAccessMaskOut = 0;
BOOLEAN fAccessCheckSuccess = False;
BOOLEAN fRevertImpersonation = False;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PAGED_CODE( );
ASSERT ((pSda != NULL) && (pSidGroup != NULL));
AfpDumpSid("afpCheckUserMemberOfGroup: Checking", pSidGroup);
do
{
// Create SecurityDescriptor out of the Sid provided
Status = AfpMakeSecDescForAccessCheck(pSidGroup, &pSecDesc);
if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
("AfpMakeSecDescForAccessCheck failed error (%0xld)\n", Status));
break;
}
AfpImpersonateClient(pSda);
fRevertImpersonation = True;
SeCaptureSubjectContext(&SecSubjectContext);
CheckAccessMaskIn = ACCESS_CHECK_ACCESS_MASK;
fAccessCheckSuccess = SeAccessCheck (
pSecDesc,
&SecSubjectContext,
FALSE,
CheckAccessMaskIn,
0,
NULL,
IoGetFileObjectGenericMapping(),
UserMode,
&CheckAccessMaskOut,
&Status
);
if (fAccessCheckSuccess && NT_SUCCESS(Status))
{
IsAMember = True;
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("SeAccessCheck good : Status= (%0x), RetCode= (%ld), AccessOut= (%ld)\n", Status, fAccessCheckSuccess, CheckAccessMaskOut));
}
else
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("SeAccessCheck failed: Status = (%0x), RetCode= (%ld)\n", Status, fAccessCheckSuccess));
}
SeReleaseSubjectContext(&SecSubjectContext);
}
while (FALSE);
if (fRevertImpersonation)
AfpRevertBack();
if (pSecDesc != NULL)
{
if (pSecDesc->Dacl != NULL)
AfpFreeMemory(pSecDesc->Dacl);
AfpFreeMemory(pSecDesc);
}
return IsAMember;
}
/*** afpGetUserAccess
*
* Determine the Access that is permitted for the user
*/
LOCAL NTSTATUS
afpGetUserAccess(
IN PSDA pSda,
IN PISECURITY_DESCRIPTOR pSecDesc,
OUT PACCESS_MASK pGrantedAccess
)
{
DWORD i;
SECURITY_SUBJECT_CONTEXT SecSubjectContext = {0};
ACCESS_MASK DesiredAccess = 0;
BOOLEAN fAccessCheckSuccess = False;
BOOLEAN fRevertImpersonation = False;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PAGED_CODE( );
ASSERT ((pSda != NULL) && (pSecDesc != NULL));
do
{
AfpImpersonateClient(pSda);
fRevertImpersonation = True;
SeCaptureSubjectContext(&SecSubjectContext);
DesiredAccess = MAXIMUM_ALLOWED;
fAccessCheckSuccess = SeAccessCheck (
pSecDesc,
&SecSubjectContext,
FALSE,
DesiredAccess,
0,
NULL,
IoGetFileObjectGenericMapping(),
UserMode,
pGrantedAccess,
&Status
);
if (fAccessCheckSuccess && NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("SeAccessCheck good : Status= (%0x), RetCode= (%ld), AccessOut= (%0x)\n", Status, fAccessCheckSuccess, *pGrantedAccess));
}
else
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("SeAccessCheck failed: Status = (%0x), RetCode= (%0x)\n", Status, fAccessCheckSuccess));
}
SeReleaseSubjectContext(&SecSubjectContext);
}
while (FALSE);
if (fRevertImpersonation)
AfpRevertBack();
return Status;
}
/*** AfpGetUserAndPrimaryGroupSids
*
* Get the Sids corres. to the user and his primary group.
*/
NTSTATUS
AfpGetUserAndPrimaryGroupSids(
IN PSDA pSda
)
{
DWORD i, j;
NTSTATUS Status = STATUS_SUCCESS;
DWORD SidLength, SizeNeeded, ExtraSpace, Offset;
PSID_AND_ATTRIBUTES pSidnAttr;
PTOKEN_GROUPS pGroups = NULL;
PBYTE pGrpsBuffer = NULL;
BYTE Buffer[256]; // We should not need a buffer larger
// than this for User SID_AND_ATTRIBUTES
PAGED_CODE( );
do
{
pGrpsBuffer = (PBYTE)ALLOC_ACCESS_MEM(GRPS_BUFFER_SIZE);
if (pGrpsBuffer == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
pGroups = (PTOKEN_GROUPS)pGrpsBuffer;
pSda->sda_pGroups = NULL;
if (pSda->sda_ClientType == SDA_CLIENT_GUEST)
{
pSda->sda_UserSid = &AfpSidWorld;
pSda->sda_GroupSid = &AfpSidWorld; // Primary group of Guest is also 'World'
break;
}
pSidnAttr = (PSID_AND_ATTRIBUTES)Buffer;
// Get the Owner Sid out of the User token and copy it into the Sda
Status = NtQueryInformationToken(pSda->sda_UserToken,
TokenOwner,
pSidnAttr,
sizeof(Buffer),
&SizeNeeded);
ASSERT (NT_SUCCESS(Status));
if (!NT_SUCCESS(Status))
{
break;
}
AfpDumpSid("AfpGetUserAndPrimaryGroupSids: LOGON Owner Sid", pSidnAttr->Sid);
SidLength = RtlLengthSid(pSidnAttr->Sid);
pSda->sda_UserSid = (PSID)ALLOC_ACCESS_MEM(SidLength);
if (pSda->sda_UserSid == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory(pSda->sda_UserSid, pSidnAttr->Sid, SidLength);
// Get the primary group of this user
Status = NtQueryInformationToken(pSda->sda_UserToken,
TokenPrimaryGroup,
pSidnAttr,
sizeof(Buffer),
&SizeNeeded);
ASSERT (NT_SUCCESS(Status));
if (!NT_SUCCESS(Status))
{
break;
}
AfpDumpSid("AfpGetUserAndPrimaryGroupSids: LOGON Group Sid", pSidnAttr->Sid);
SidLength = RtlLengthSid(pSidnAttr->Sid);
pSda->sda_GroupSid = (PSID)ALLOC_ACCESS_MEM(SidLength);
if (pSda->sda_GroupSid == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
RtlCopyMemory(pSda->sda_GroupSid, pSidnAttr->Sid, SidLength);
// Get the User Sid out of the User token. This will be added to the
// list of groups that we query later, if this is different from
// the Owner Sid (which is now in sda_UserSid).
Status = NtQueryInformationToken(pSda->sda_UserToken,
TokenUser,
pSidnAttr,
sizeof(Buffer),
&SizeNeeded);
ASSERT (NT_SUCCESS(Status));
if (!NT_SUCCESS(Status))
{
break;
}
AfpDumpSid("AfpGetUserAndPrimaryGroupSids: LOGON User Sid", pSidnAttr->Sid);
// Get the list of groups this user is member of
SizeNeeded = GRPS_BUFFER_SIZE;
do
{
if (Status != STATUS_SUCCESS)
{
if (pGroups != (PTOKEN_GROUPS)pGrpsBuffer)
AfpFreeMemory(pGroups);
if ((pGroups = (PTOKEN_GROUPS)ALLOC_ACCESS_MEM(SizeNeeded)) == NULL)
{
Status = AFP_ERR_MISC;
if (pSda->sda_ClientType == SDA_CLIENT_ADMIN)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
break;
}
}
Status = NtQueryInformationToken(pSda->sda_UserToken,
TokenGroups,
pGroups,
SizeNeeded,
&SizeNeeded);
} while ((Status != STATUS_SUCCESS) &&
((Status == STATUS_BUFFER_TOO_SMALL) ||
(Status == STATUS_BUFFER_OVERFLOW) ||
(Status == STATUS_MORE_ENTRIES)));
if (!NT_SUCCESS(Status))
{
AFPLOG_ERROR(AFPSRVMSG_USER_GROUPS, Status, NULL, 0, NULL);
break;
}
// Allocate enough memory to copy the group information in the sda. If
// the User and Owner Sids in the user token are not the same then we
// want to add the user sid to the list of groups. This is especially
// the case where an ADMIN logs on but his Owner Sid is Administrators.
// Also fix up the pointers appropriately !!!
ExtraSpace = 0; Offset = 0; j = 0;
if (!RtlEqualSid(pSidnAttr->Sid, pSda->sda_UserSid))
{
ExtraSpace = (RtlLengthSid(pSidnAttr->Sid) + sizeof(pSidnAttr->Attributes));
Offset = sizeof(SID_AND_ATTRIBUTES);
j = 1;
}
if ((pSda->sda_pGroups = (PTOKEN_GROUPS)AfpAllocPagedMemory(2*SizeNeeded+2*ExtraSpace)) == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
// If we are not copying the User Sid in sda_pGroups, then copy pGroups to sda_pGroups
// directly and then fixup the individual pSid pointers. If we are then make the User
// Sid as the first one in the list and copy the actual sid at the tail end of the
// buffer.
pSda->sda_pGroups->GroupCount = pGroups->GroupCount;
RtlCopyMemory(&pSda->sda_pGroups->Groups[j],
&pGroups->Groups[0],
SizeNeeded - sizeof(DWORD)); // DWORD accounts for GroupCount
if (ExtraSpace > 0)
{
pSda->sda_pGroups->Groups[0].Sid = (PSID)((PBYTE)(pSda->sda_pGroups) + SizeNeeded);
RtlCopyMemory(pSda->sda_pGroups->Groups[0].Sid,
pSidnAttr->Sid,
RtlLengthSid(pSidnAttr->Sid));
pSda->sda_pGroups->Groups[0].Attributes = pSidnAttr->Attributes;
pSda->sda_pGroups->GroupCount ++;
AfpDumpSid("AfpGetUserAndPrimaryGroupSids: Member of ",
pSda->sda_pGroups->Groups[0].Sid);
}
for (i = 0; i < pGroups->GroupCount; i++, j++)
{
pSda->sda_pGroups->Groups[j].Sid = (PSID)((PBYTE)(pGroups->Groups[i].Sid) -
(PBYTE)pGroups +
(PBYTE)(pSda->sda_pGroups) +
Offset);
AfpDumpSid("AfpGetUserAndPrimaryGroupSids: Member of ",
pSda->sda_pGroups->Groups[j].Sid);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpGetUserAndPrimaryGroupSids: Attributes %lx\n",
pSda->sda_pGroups->Groups[j].Attributes));
}
} while (False);
if (pGroups != (PTOKEN_GROUPS)pGrpsBuffer)
if (pGroups)
AfpFreeMemory(pGroups);
if (pGrpsBuffer != NULL)
AfpFreeMemory(pGrpsBuffer);
return Status;
}
/*** AfpMakeSecurityDescriptorForUser
*
* Create a security descriptor for a user. The security descriptor has the
* Owner Sid, Primary Group Sid and Aces for the User alone.
*/
AFPSTATUS
AfpMakeSecurityDescriptorForUser(
IN PSID OwnerSid,
IN PSID GroupSid,
OUT PISECURITY_DESCRIPTOR * ppSecDesc
)
{
AFPSTATUS Status = AFP_ERR_MISC;
PISECURITY_DESCRIPTOR pSecDesc;
int DaclSize;
PACCESS_ALLOWED_ACE pAce;
PAGED_CODE( );
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpMakeSecurityDescriptorForUser: Entered\n"));
do
{
// Allocate a security descriptor
pSecDesc = (PISECURITY_DESCRIPTOR)ALLOC_ACCESS_MEM(sizeof(SECURITY_DESCRIPTOR));
*ppSecDesc = pSecDesc;
if (pSecDesc == NULL)
break;
// Initialize the security descriptor
RtlCreateSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION);
pSecDesc->Control = SE_DACL_PRESENT;
// Set the owner and group Ids in the descriptor
pSecDesc->Owner = OwnerSid;
pSecDesc->Group = GroupSid;
// Determine the size of the Dacl needed. The sizeof(DWORD) offsets the
// SidStart field in the ACE. There are 7 aces in this security descriptor:
//
// 2 for the owner (owner+inherit for owner)
// 2 for world (1 for world and 1 inherit for world).
// 2 for system
DaclSize = sizeof(ACL) + 2*(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) +
RtlLengthSid(OwnerSid)) +
2*(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) +
sizeof(AfpSidWorld)) +
2*(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) +
AfpSizeSidAdmins) +
2*(sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) +
RtlLengthSid(&AfpSidSystem));
if ((pSecDesc->Dacl = (PACL)ALLOC_ACCESS_MEM(DaclSize)) == NULL)
break;
// Initialize the ACL with one ACE corres. to Owner getting all the
// privileges. Add another ace which is identical to the first ace but is
// a inheritance ACE.
// JH - Add another ace for world with minumum permissions and for administrators
// with FullControl
RtlCreateAcl(pSecDesc->Dacl, DaclSize, ACL_REVISION);
// we will be adding to this as we add aces, so set it to the min here
pSecDesc->Dacl->AclSize = sizeof(ACL);
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pSecDesc->Dacl + sizeof(ACL));
// Add the ALLOWED_ACE and the corres. inherit Ace for owner
pAce = afpAddAceToAcl(pSecDesc->Dacl,
pAce,
(AFP_READ_ACCESS | AFP_WRITE_ACCESS | AFP_OWNER_ACCESS | FILE_DELETE_CHILD),
OwnerSid,
True);
if (AfpSidAdmins != NULL)
{
// Add the ALLOWED_ACE and the corres. inherit Ace for 'Administrators'
pAce = afpAddAceToAcl(pSecDesc->Dacl,
pAce,
(AFP_READ_ACCESS | AFP_WRITE_ACCESS | AFP_OWNER_ACCESS | FILE_DELETE_CHILD),
AfpSidAdmins,
True);
}
// Add a min. permission ace for world, but only if the owner is
// not world already
if (!RtlEqualSid(OwnerSid, &AfpSidWorld))
{
pAce = afpAddAceToAcl(pSecDesc->Dacl,
pAce,
(AFP_MIN_ACCESS),
&AfpSidWorld,
True);
}
// Now add Aces for System
pAce = afpAddAceToAcl(pSecDesc->Dacl,
pAce,
AFP_READ_ACCESS | AFP_WRITE_ACCESS | AFP_OWNER_ACCESS,
&AfpSidSystem,
True);
Status = AFP_ERR_NONE;
} while (False);
// Do any cleanup on error
if (!NT_SUCCESS(Status) && (pSecDesc != NULL))
{
if (pSecDesc->Dacl != NULL)
AfpFreeMemory(pSecDesc->Dacl);
AfpFreeMemory(pSecDesc);
}
return Status;
}
/*** AfpGetAfpPermissions
*
* Read the security descriptor for this directory and obtain the SIDs for
* Owner and Primary group. Determine if this user is a member of the directory
* primary group. Finally obtain Owner,Group and World permissions.
*
* OwnerId, GroupId and permissions will always be valid if this call succeeds.
*/
NTSTATUS
AfpGetAfpPermissions(
IN PSDA pSda,
IN HANDLE DirHandle,
IN OUT PFILEDIRPARM pFDParm
)
{
NTSTATUS Status = STATUS_SUCCESS;
DWORD SizeNeeded;
PISECURITY_DESCRIPTOR pSecDesc = NULL;
PBYTE pAbsSecDesc = NULL; // Used in conversion of
// sec descriptor to
// absolute format
BOOLEAN SawOwnerAce = False,
SawGroupAce = False,
SawWorldAce = False,
CheckUserRights = False;
ACCESS_MASK OwnerGranted = 0, OwnerDenied = 0,
GroupGranted = 0, GroupDenied = 0,
WorldGranted = 0, WorldDenied = 0,
UserGranted = 0, UserDenied = 0,
UserAccess = 0;
#ifdef PROFILING
TIME TimeS, TimeE, TimeD;
#endif
PAGED_CODE( );
#ifdef PROFILING
INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_GetPermsCount);
AfpGetPerfCounter(&TimeS);
#endif
// Read the security descriptor for this directory and determine the
// rights for owner/group/world.We want to optimize on how much memory
// we need to read this in. Its a pain to make a call just to get that.
// So just make a guess. If that turns out to be short then do the exact
// allocation.
do
{
// 4096 has been emperically chosen
SizeNeeded = 4096 - POOL_OVERHEAD;
do
{
if (pSecDesc != NULL)
{
AfpFreeMemory(pSecDesc);
}
if ((pSecDesc = (PSECURITY_DESCRIPTOR)ALLOC_ACCESS_MEM(SizeNeeded)) == NULL)
{
Status = AFP_ERR_MISC;
if (pSda->sda_ClientType == SDA_CLIENT_ADMIN)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
break;
}
Status = NtQuerySecurityObject(DirHandle,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
pSecDesc,
SizeNeeded,
&SizeNeeded);
} while ((Status != STATUS_SUCCESS) &&
((Status == STATUS_BUFFER_TOO_SMALL) ||
(Status == STATUS_BUFFER_OVERFLOW) ||
(Status == STATUS_MORE_ENTRIES)));
if (!NT_SUCCESS(Status))
{
break;
}
// If the security descriptor is in self-relative form, convert to absolute
pSecDesc = (PISECURITY_DESCRIPTOR)((PBYTE)pSecDesc);
if (pSecDesc->Control & SE_SELF_RELATIVE)
{
DWORD AbsoluteSizeNeeded;
// An absolute SD is not necessarily the same size as a relative
// SD, so an in-place conversion may not be possible.
AbsoluteSizeNeeded = SizeNeeded;
Status = RtlSelfRelativeToAbsoluteSD2(pSecDesc, &AbsoluteSizeNeeded);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
// Allocate a new buffer in which to store the absolute
// security descriptor, copy the contents of the relative
// descriptor in and try again
pAbsSecDesc = (PBYTE)ALLOC_ACCESS_MEM(AbsoluteSizeNeeded);
if (pAbsSecDesc == NULL)
{
Status = STATUS_NO_MEMORY;
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
("AfpGetAfpPermissions: ALLOC_ACCESS_MEM error\n"));
}
else
{
RtlCopyMemory(pAbsSecDesc, pSecDesc, SizeNeeded);
Status = RtlSelfRelativeToAbsoluteSD2 (pAbsSecDesc,
&AbsoluteSizeNeeded);
if (NT_SUCCESS(Status))
{
// We don't need relative form anymore,
// we will work with the Absolute form
if (pSecDesc != NULL)
{
AfpFreeMemory(pSecDesc);
}
pSecDesc = (PISECURITY_DESCRIPTOR)pAbsSecDesc;
}
else
{
// We cannot use Absolute Form, throw it away
AfpFreeMemory(pAbsSecDesc);
pAbsSecDesc = NULL;
}
}
}
if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
("AfpGetAfpPermissions: RtlSelfRelativeToAbsoluteSD2: returned error %lx\n", Status));
break;
}
}
// Now determine if the user is a member of the directories primary group.
pFDParm->_fdp_OwnerId = 0;
pFDParm->_fdp_GroupId = 0;
pFDParm->_fdp_UserIsOwner = False;
pFDParm->_fdp_UserIsMemberOfDirGroup = False;
if (pSecDesc->Owner != NULL)
{
AfpDumpSid("AfpGetAfpPermissions: OwnerSid", pSecDesc->Owner);
pFDParm->_fdp_UserIsOwner =
(RtlEqualSid(pSecDesc->Owner, pSda->sda_UserSid) ||
((pSda->sda_ClientType != SDA_CLIENT_GUEST) &&
(pSda->sda_ClientType != SDA_CLIENT_ADMIN) &&
afpCheckUserMemberOfGroup(pSda,
pSecDesc->Owner)));
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpGetAfpPermissions: User %s Owner\n",
pFDParm->_fdp_UserIsOwner ? "is" : "isnt"));
if (!NT_SUCCESS(Status = AfpSidToMacId(pSecDesc->Owner,
&pFDParm->_fdp_OwnerId)))
{
// If we cant map the Sid, return Id SE_NULL_POSIX_ID
pFDParm->_fdp_OwnerId = SE_NULL_POSIX_ID;
Status = AFP_ERR_NONE;
}
}
if (pSecDesc->Group != NULL)
{
AfpDumpSid("AfpGetAfpPermissions: GroupSid", pSecDesc->Group);
if (!pFDParm->_fdp_UserIsOwner)
pFDParm->_fdp_UserIsMemberOfDirGroup =
(RtlEqualSid(pSecDesc->Group, pSda->sda_UserSid) ||
((pSda->sda_ClientType != SDA_CLIENT_GUEST) &&
(pSda->sda_ClientType != SDA_CLIENT_ADMIN) &&
afpCheckUserMemberOfGroup(pSda,
pSecDesc->Group)));
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpGetAfpPermissions: Group %s member of PrimaryGroup\n",
pFDParm->_fdp_UserIsMemberOfDirGroup ? "is" : "isnt"));
if (!NT_SUCCESS(Status = AfpSidToMacId(pSecDesc->Group,
&pFDParm->_fdp_GroupId)))
{
// If we cant map the Sid, return Id SE_NULL_POSIX_ID
pFDParm->_fdp_GroupId = SE_NULL_POSIX_ID;
Status = AFP_ERR_NONE;
}
}
// Walk through the ACL list and determine Owner/Group/World and User
// permissions. For Owner/Group and User, if the specific ace's are
// not present then they inherit the world permissions.
//
// A NULL Acl => All rights to everyone. An empty Acl on the other
// hand => no access for anyone.
pFDParm->_fdp_UserRights = 0;
pFDParm->_fdp_WorldRights = 0;
if ((pSecDesc->Control & SE_DACL_PRESENT) &&
(pSecDesc->Dacl != NULL))
{
USHORT i;
PSID pSid;
PACL pAcl;
PACCESS_ALLOWED_ACE pAce;
pAcl = pSecDesc->Dacl;
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAcl + sizeof(ACL));
CheckUserRights = ((pSda->sda_ClientType != SDA_CLIENT_GUEST) &&
(pSda->sda_ClientType != SDA_CLIENT_ADMIN));
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpGetAfpPermissions: # of aces %d\n", pSecDesc->Dacl->AceCount));
for (i = 0; i < pSecDesc->Dacl->AceCount; i++)
{
if ((pAce->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) &&
(pAce->Header.AceType != ACCESS_DENIED_ACE_TYPE))
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpGetAfpPermissions: Skipping ACE of type (%ld)\n", pAce->Header.AceType));
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize);
continue;
}
pSid = (PSID)(&pAce->SidStart);
// Ignore inherit-only aces, & system
if (pAce->Header.AceFlags & INHERIT_ONLY_ACE)
{
AfpDumpSidnMask("AfpGetAfpPermissions: Skipping",
pSid,
pAce->Mask,
pAce->Header.AceType,
pAce->Header.AceFlags);
}
else
{
AfpDumpSidnMask("AfpGetAfpPermissions: ACE",
pSid,
pAce->Mask,
pAce->Header.AceType,
pAce->Header.AceFlags);
if ((pSecDesc->Owner != NULL) &&
RtlEqualSid(pSid, pSecDesc->Owner))
{
if (pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
{
OwnerGranted |= (pAce->Mask & ~OwnerDenied);
}
else
{
OwnerDenied |= (pAce->Mask & ~OwnerGranted);
}
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("Owner: %s Ace Mask %lx\n",
(pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) ?
"Allow" : "Deny",
pAce->Mask));
SawOwnerAce = True;
}
if ((pSecDesc->Group != NULL) &&
RtlEqualSid(pSid, pSecDesc->Group))
{
if (pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
{
GroupGranted |= (pAce->Mask & ~GroupDenied);
}
else
{
GroupDenied |= (pAce->Mask & ~GroupGranted);
}
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("Group: %s Ace Mask %lx\n",
(pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) ?
"Allow" : "Deny",
pAce->Mask));
SawGroupAce = True;
}
if ((RtlEqualSid(pSid, (PSID)&AfpSidWorld)))
{
if (pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
{
WorldGranted |= (pAce->Mask & ~WorldDenied);
}
else
{
WorldDenied |= (pAce->Mask & ~WorldGranted);
}
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("World: %s Ace Mask %lx\n",
(pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) ?
"Allow" : "Deny",
pAce->Mask));
SawWorldAce = True;
}
}
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize);
}
}
else // Security descriptor not present, party time
{
pFDParm->_fdp_WorldRights = DIR_ACCESS_ALL;
pFDParm->_fdp_UserRights = DIR_ACCESS_ALL | DIR_ACCESS_OWNER;
}
if (!SawGroupAce)
pFDParm->_fdp_GroupRights = pFDParm->_fdp_WorldRights;
if (SawOwnerAce)
{
AfpAccessMask2AfpPermissions(pFDParm->_fdp_OwnerRights,
OwnerGranted,
ACCESS_ALLOWED_ACE_TYPE);
}
if (SawGroupAce)
{
AfpAccessMask2AfpPermissions(pFDParm->_fdp_GroupRights,
GroupGranted,
ACCESS_ALLOWED_ACE_TYPE);
}
if (SawWorldAce)
{
AfpAccessMask2AfpPermissions(pFDParm->_fdp_WorldRights,
WorldGranted,
ACCESS_ALLOWED_ACE_TYPE);
}
// Get the ACCESS_MASK allowed for the user
Status = afpGetUserAccess(
pSda,
pSecDesc,
&UserAccess);
if (NT_SUCCESS(Status))
{
UserGranted = UserAccess;
}
else
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
("afpGetUserAccess failed with error %0x\n",
Status));
Status = AFP_ERR_NONE;
}
AfpAccessMask2AfpPermissions(pFDParm->_fdp_UserRights,
UserGranted,
ACCESS_ALLOWED_ACE_TYPE);
// If this is a standalone server and the primary group of the
// directory is MACHINE\None, do not return this information to
// the caller.
if (AfpServerIsStandalone &&
(pSecDesc->Group != NULL) &&
RtlEqualSid(pSecDesc->Group, AfpSidNone))
{
pFDParm->_fdp_GroupRights = 0;
pFDParm->_fdp_GroupId = 0;
}
if (pSda->sda_ClientType == SDA_CLIENT_GUEST)
pFDParm->_fdp_UserRights = pFDParm->_fdp_WorldRights;
} while (False);
if (pSecDesc != NULL)
AfpFreeMemory(pSecDesc);
#ifdef PROFILING
AfpGetPerfCounter(&TimeE);
TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_GetPermsTime,
TimeD,
&AfpStatisticsLock);
#endif
return Status;
}
/*** afpMoveAces
*
* Move a bunch of aces from the old security descriptor to the new security
* descriptor.
*/
LOCAL PACCESS_ALLOWED_ACE
afpMoveAces(
IN PACL pOldDacl,
IN PACCESS_ALLOWED_ACE pAceStart,
IN PSID pSidOldOwner,
IN PSID pSidNewOwner,
IN PSID pSidOldGroup,
IN PSID pSidNewGroup,
IN BOOLEAN DenyAces,
IN BOOLEAN InheritedAces,
IN OUT PACL pNewDacl
)
{
USHORT i;
PACCESS_ALLOWED_ACE pAceOld;
PSID pSidAce;
PAGED_CODE( );
for (i = 0, pAceOld = (PACCESS_ALLOWED_ACE)((PBYTE)pOldDacl + sizeof(ACL));
i < pOldDacl->AceCount;
i++, pAceOld = (PACCESS_ALLOWED_ACE)((PBYTE)pAceOld + pAceOld->Header.AceSize))
{
if (InheritedAces && ((pAceOld->Header.AceFlags & INHERITED_ACE) != INHERITED_ACE))
continue;
if ((!InheritedAces) && ((pAceOld->Header.AceFlags & INHERITED_ACE) == INHERITED_ACE))
continue;
// Note: All deny aces are ahead of the grant aces.
if (DenyAces && (pAceOld->Header.AceType != ACCESS_DENIED_ACE_TYPE))
break;
if (!DenyAces && (pAceOld->Header.AceType == ACCESS_DENIED_ACE_TYPE))
continue;
pSidAce = (PSID)(&pAceOld->SidStart);
if (!RtlEqualSid(pSidAce, &AfpSidWorld) &&
!RtlEqualSid(pSidAce, &AfpSidSystem) &&
!RtlEqualSid(pSidAce, pSidOldOwner) &&
!RtlEqualSid(pSidAce, pSidNewOwner) &&
!RtlEqualSid(pSidAce, pSidOldGroup) &&
!RtlEqualSid(pSidAce, pSidNewGroup))
{
RtlCopyMemory(pAceStart, pAceOld, pAceOld->Header.AceSize);
pNewDacl->AclSize += pAceOld->Header.AceSize;
pNewDacl->AceCount ++;
pAceStart = (PACCESS_ALLOWED_ACE)((PBYTE)pAceStart +
pAceStart->Header.AceSize);
}
}
return pAceStart;
}
/*** AfpSetAfpPermissions
*
* Set the permissions on this directory. Also optionally set the owner and
* group ids. For setting the owner and group ids verify if the user has the
* needed access. This access is however not good enough. We check for this
* access but do the actual setting of the permissions in the special server
* context (RESTORE privilege is needed).
*/
AFPSTATUS
AfpSetAfpPermissions(
IN HANDLE DirHandle,
IN DWORD Bitmap,
IN PFILEDIRPARM pFDParm
)
{
AFPSTATUS Status = STATUS_SUCCESS;
DWORD SizeNeeded;
PISECURITY_DESCRIPTOR pSecDesc;
PBYTE pAbsSecDesc = NULL; // Used in conversion of
// sec descriptor to
// absolute format
SECURITY_INFORMATION SecInfo = DACL_SECURITY_INFORMATION;
PSID pSidOwner = NULL, pSidGroup = NULL;
PSID pSidOldOwner, pSidOldGroup;
BOOLEAN SawOwnerAce = False, SawGroupAce = False;
BOOLEAN OwnerIsWorld = False, GroupIsWorld = False;
BOOLEAN fDir = IsDir(pFDParm);
PACL pDaclNew = NULL;
PACCESS_ALLOWED_ACE pAce;
LONG SizeNewDacl;
#ifdef PROFILING
TIME TimeS, TimeE, TimeD;
#endif
PAGED_CODE( );
#ifdef PROFILING
INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_SetPermsCount);
AfpGetPerfCounter(&TimeS);
#endif
do
{
// Read the security descriptor for this directory
SizeNeeded = 4096 - POOL_OVERHEAD;
pSecDesc = NULL;
do
{
if (pSecDesc != NULL)
{
AfpFreeMemory(pSecDesc);
}
SizeNewDacl = SizeNeeded;
if ((pSecDesc = (PSECURITY_DESCRIPTOR)ALLOC_ACCESS_MEM(SizeNeeded)) == NULL)
{
Status = AFP_ERR_MISC;
break;
}
Status = NtQuerySecurityObject(DirHandle,
OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION,
pSecDesc,
SizeNeeded,
&SizeNeeded);
} while ((Status != STATUS_SUCCESS) &&
((Status == STATUS_BUFFER_TOO_SMALL) ||
(Status == STATUS_BUFFER_OVERFLOW) ||
(Status == STATUS_MORE_ENTRIES)));
if (!NT_SUCCESS(Status))
{
Status = AfpIoConvertNTStatusToAfpStatus(Status);
break;
}
pSecDesc = (PISECURITY_DESCRIPTOR)((PBYTE)pSecDesc);
// If the security descriptor is in self-relative form, convert to absolute
if (pSecDesc->Control & SE_SELF_RELATIVE)
{
DWORD AbsoluteSizeNeeded;
// An absolute SD is not necessarily the same size as a relative
// SD, so an in-place conversion may not be possible.
AbsoluteSizeNeeded = SizeNeeded;
Status = RtlSelfRelativeToAbsoluteSD2(pSecDesc, &AbsoluteSizeNeeded);
if (Status == STATUS_BUFFER_TOO_SMALL)
{
// Allocate a new buffer in which to store the absolute
// security descriptor, copy the contents of the relative
// descriptor in and try again
pAbsSecDesc = (PBYTE)ALLOC_ACCESS_MEM(AbsoluteSizeNeeded);
if (pAbsSecDesc == NULL)
{
Status = STATUS_NO_MEMORY;
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
("AfpSetAfpPermissions: ALLOC_ACCESS_MEM 2 error\n"));
}
else
{
RtlCopyMemory(pAbsSecDesc, pSecDesc, SizeNeeded);
Status = RtlSelfRelativeToAbsoluteSD2 (pAbsSecDesc,
&AbsoluteSizeNeeded);
if (NT_SUCCESS(Status))
{
// We don't need relative form anymore,
// we will work with the Absolute form
if (pSecDesc != NULL)
{
AfpFreeMemory(pSecDesc);
}
pSecDesc = (PISECURITY_DESCRIPTOR)pAbsSecDesc;
}
else
{
// We cannot use Absolute Form, throw it away
AfpFreeMemory(pAbsSecDesc);
pAbsSecDesc = NULL;
}
}
}
if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
("AfpSetAfpPermissions: RtlSelfRelativeToAbsoluteSD2: returned error %lx\n", Status));
break;
}
SizeNeeded = AbsoluteSizeNeeded;
}
SizeNewDacl = SizeNeeded;
// Add SE_DACL_AUTO_INHERIT_REQ
pSecDesc->Control |= SE_DACL_AUTO_INHERIT_REQ;
// Save the old Owner and Group Sids
pSidOldOwner = pSecDesc->Owner;
pSidOldGroup = pSecDesc->Group;
// Convert the owner/group ids, if any to be set to their corres. sids
if (Bitmap & DIR_BITMAP_OWNERID)
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Setting Owner to ID %lx\n",
pFDParm->_fdp_OwnerId));
if (AfpMacIdToSid(pFDParm->_fdp_OwnerId, &pSidOwner) != STATUS_SUCCESS)
{
Status = AFP_ERR_MISC;
break;
}
// Don't allow owner sid to be set as the NULL sid, or
// to what it is presently set to
if (!RtlEqualSid(pSecDesc->Owner, pSidOwner) &&
!RtlEqualSid(&AfpSidNull, pSidOwner))
{
AfpDumpSid("AfpSetAfpPermissions: Setting Owner Sid to ", pSidOwner);
pSecDesc->Owner = pSidOwner;
SecInfo |= OWNER_SECURITY_INFORMATION;
}
}
if (Bitmap & DIR_BITMAP_GROUPID)
{
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Setting Group to ID %lx\n",
pFDParm->_fdp_GroupId));
if (AfpMacIdToSid(pFDParm->_fdp_GroupId, &pSidGroup) != STATUS_SUCCESS)
{
Status = AFP_ERR_MISC;
break;
}
// Don't allow group sid to be set as the NULL or None sid, or
// to what it is presently set to
if (!RtlEqualSid(pSecDesc->Group, pSidGroup) &&
!RtlEqualSid(&AfpSidNull, pSidGroup) &&
(!AfpServerIsStandalone || !RtlEqualSid(AfpSidNone, pSidGroup)))
{
AfpDumpSid("AfpSetAfpPermissions: Setting Group Sid to ", pSidGroup);
pSecDesc->Group = pSidGroup;
SecInfo |= GROUP_SECURITY_INFORMATION;
}
}
// If either the owner or group or both is 'EveryOne' then coalesce the
// permissions
if (RtlEqualSid(pSecDesc->Owner, pSecDesc->Group))
{
pFDParm->_fdp_OwnerRights |= pFDParm->_fdp_GroupRights;
pFDParm->_fdp_GroupRights |= pFDParm->_fdp_OwnerRights;
}
if (RtlEqualSid(pSecDesc->Owner, &AfpSidWorld))
{
pFDParm->_fdp_WorldRights |= (pFDParm->_fdp_OwnerRights | DIR_ACCESS_OWNER);
OwnerIsWorld = True;
}
if (RtlEqualSid(pSecDesc->Group, &AfpSidWorld))
{
pFDParm->_fdp_WorldRights |= pFDParm->_fdp_GroupRights;
GroupIsWorld = True;
}
// Construct the new Dacl. This consists of Aces for World, Owner and Group
// followed by Old Aces for everybody else, but with Aces for World, OldOwner
// and OldGroup stripped out. First determine space for the new Dacl and
// allocated space for the new Dacl. Lets be exteremely conservative. We
// have two aces each for owner/group/world.
SizeNewDacl +=
(RtlLengthSid(pSecDesc->Owner) + sizeof(ACCESS_ALLOWED_ACE) +
RtlLengthSid(pSecDesc->Group) + sizeof(ACCESS_ALLOWED_ACE) +
sizeof(AfpSidSystem) + sizeof(ACCESS_ALLOWED_ACE) +
sizeof(AfpSidWorld) + sizeof(ACCESS_ALLOWED_ACE)) * 2;
if ((pDaclNew = (PACL)ALLOC_ACCESS_MEM(SizeNewDacl)) == NULL)
{
Status = AFP_ERR_MISC;
break;
}
RtlCreateAcl(pDaclNew, SizeNewDacl, ACL_REVISION);
// we will be adding to this as we add aces, so set it to the min here
pDaclNew->AclSize = sizeof(ACL);
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pDaclNew + sizeof(ACL));
// At this time the Acl list is empty, i.e. no access for anybody
// Start off by copying the Explicit/Non-inherited Deny Aces from
// the original Dacl list
// weeding out the Aces for World, old and new owner, new and old
// group, creator owner and creator group
if (pSecDesc->Dacl != NULL)
{
pAce = afpMoveAces(pSecDesc->Dacl,
pAce,
pSidOldOwner,
pSecDesc->Owner,
pSidOldGroup,
pSecDesc->Group,
True,
False,
pDaclNew);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Added (%d) old Non-inherited Deny Aces\n",
pDaclNew->AceCount));
ASSERT(((PBYTE)pAce - (PBYTE)pDaclNew) < SizeNewDacl);
}
// Now add Allowed Aces for System, World, Group & Owner - in that order
pAce = afpAddAceToAcl(pDaclNew,
pAce,
AFP_READ_ACCESS | AFP_WRITE_ACCESS | AFP_OWNER_ACCESS,
&AfpSidSystem,
fDir);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Added Aces for System (%d)\n",
pDaclNew->AceCount));
ASSERT(((PBYTE)pAce - (PBYTE)pDaclNew) < SizeNewDacl);
// Now add Ace for World
pAce = afpAddAceToAcl(pDaclNew,
pAce,
afpPermissions2NtMask(pFDParm->_fdp_WorldRights),
&AfpSidWorld,
fDir);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Added Aces for World (%d)\n",
pDaclNew->AceCount));
ASSERT(((PBYTE)pAce - (PBYTE)pDaclNew) < SizeNewDacl);
// Now add Ace for Group
if (!GroupIsWorld &&
!RtlEqualSid(pSecDesc->Group, &AfpSidNull) &&
(!AfpServerIsStandalone || !RtlEqualSid(pSecDesc->Group, AfpSidNone)))
{
pAce = afpAddAceToAcl(pDaclNew,
pAce,
afpPermissions2NtMask(pFDParm->_fdp_GroupRights),
pSecDesc->Group,
fDir);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Added Aces for Group (%d)\n",
pDaclNew->AceCount));
ASSERT(((PBYTE)pAce - (PBYTE)pDaclNew) < SizeNewDacl);
}
if (!OwnerIsWorld && !RtlEqualSid(pSecDesc->Owner, &AfpSidNull))
{
pFDParm->_fdp_OwnerRights |= DIR_ACCESS_OWNER;
pAce = afpAddAceToAcl(pDaclNew,
pAce,
afpPermissions2NtMask(pFDParm->_fdp_OwnerRights),
pSecDesc->Owner,
fDir);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Added Aces for Owner (%d)\n",
pDaclNew->AceCount));
ASSERT(((PBYTE)pAce - (PBYTE)pDaclNew) < SizeNewDacl);
}
// Now add in the Explicit/Non-inherited Grant Aces from the
// original Dacl list weeding out
// the Aces for World, old and new owner, new and old group, creator
// owner and creator group
if (pSecDesc->Dacl != NULL)
{
pAce = afpMoveAces(pSecDesc->Dacl,
pAce,
pSidOldOwner,
pSecDesc->Owner,
pSidOldGroup,
pSecDesc->Group,
False,
False,
pDaclNew);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Added (%d) old Non-inherited Grant Aces\n",
pDaclNew->AceCount));
ASSERT(((PBYTE)pAce - (PBYTE)pDaclNew) < SizeNewDacl);
}
// Now add in the Non-explicit/Inherited Deny Aces from
// the original Dacl list
// weeding out the Aces for World, old and new owner, new and old
// group, creator owner and creator group
if (pSecDesc->Dacl != NULL)
{
pAce = afpMoveAces(pSecDesc->Dacl,
pAce,
pSidOldOwner,
pSecDesc->Owner,
pSidOldGroup,
pSecDesc->Group,
True,
True,
pDaclNew);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Added (%d) old Inherited Deny Aces\n",
pDaclNew->AceCount));
ASSERT(((PBYTE)pAce - (PBYTE)pDaclNew) < SizeNewDacl);
}
// Now add in the Explicit/Non-inherited Grant Aces from the
// original Dacl list weeding out
// the Aces for World, old and new owner, new and old group, creator
// owner and creator group
if (pSecDesc->Dacl != NULL)
{
pAce = afpMoveAces(pSecDesc->Dacl,
pAce,
pSidOldOwner,
pSecDesc->Owner,
pSidOldGroup,
pSecDesc->Group,
False,
True,
pDaclNew);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("AfpSetAfpPermissions: Added (%d) old Inherited Grant Aces (%d)\n",
pDaclNew->AceCount));
ASSERT(((PBYTE)pAce - (PBYTE)pDaclNew) < SizeNewDacl);
}
// Now set the new security descriptor
pSecDesc->Dacl = pDaclNew;
// We need to impersonate the FspToken while we do this
AfpImpersonateClient(NULL);
Status = NtSetSecurityObject(DirHandle, SecInfo, pSecDesc);
if (!NT_SUCCESS(Status))
Status = AfpIoConvertNTStatusToAfpStatus(Status);
AfpRevertBack();
} while (False);
// Free the allocated buffers before we return
if (pSecDesc != NULL)
AfpFreeMemory(pSecDesc);
if (pDaclNew != NULL)
AfpFreeMemory(pDaclNew);
#ifdef PROFILING
AfpGetPerfCounter(&TimeE);
TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_SetPermsTime,
TimeD,
&AfpStatisticsLock);
#endif
return Status;
}
/*** afpPermissions2NtMask
*
* Map Afp permissions to Nt access mask. FILE_DELETE_CHILD is added ONLY
* when all the Afp bits are set. This is in line with the FileManager
* which only sets this bit if "Full Control" is specified. Also under
* NT security model, FILE_DELETE_CHILD overrides any child access control
* as far as the ability to delete that entity goes.
*/
LOCAL ACCESS_MASK
afpPermissions2NtMask(
IN BYTE AfpPermissions
)
{
ACCESS_MASK NtAccess = 0;
PAGED_CODE( );
if (AfpPermissions & DIR_ACCESS_OWNER)
NtAccess |= AFP_OWNER_ACCESS;
if ((AfpPermissions & DIR_ACCESS_ALL) == DIR_ACCESS_ALL)
NtAccess |= AFP_READ_ACCESS | AFP_WRITE_ACCESS | FILE_DELETE_CHILD;
else
{
if (AfpPermissions & (DIR_ACCESS_READ | DIR_ACCESS_SEARCH))
NtAccess |= AFP_READ_ACCESS;
if (AfpPermissions & DIR_ACCESS_WRITE)
NtAccess |= AFP_WRITE_ACCESS;
}
return NtAccess;
}
/*** afpAddAceToAcl
*
* Build an Ace corres. to the Sid(s) and mask and add these to the Acl. It is
* assumed that the Acl has space for the Aces. If the mask is 0 i.e. no access
* we give AFP_MIN_ACCESS. This is so that the file/dir permissions can be
* queried and a belted icon is generated instead of nothing.
*/
LOCAL PACCESS_ALLOWED_ACE
afpAddAceToAcl(
IN PACL pAcl,
IN PACCESS_ALLOWED_ACE pAce,
IN ACCESS_MASK Mask,
IN PSID pSid,
IN BOOLEAN fInherit
)
{
USHORT SidLen;
PAGED_CODE( );
SidLen = (USHORT)RtlLengthSid(pSid);
// Add a vanilla ace
pAcl->AceCount ++;
pAce->Mask = Mask | SYNCHRONIZE | AFP_MIN_ACCESS;
pAce->Header.AceFlags = 0;
pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pAce->Header.AceSize = (USHORT)(sizeof(ACE_HEADER) +
sizeof(ACCESS_MASK) +
SidLen);
RtlCopyMemory((PSID)(&pAce->SidStart), pSid, SidLen);
pAcl->AclSize += pAce->Header.AceSize;
AfpDumpSidnMask("afpAddAceToAcl ",
pSid,
pAce->Mask,
ACCESS_ALLOWED_ACE_TYPE,
pAce->Header.AceFlags);
// Now add an inherit ace
if (fInherit)
{
pAce = (PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize);
pAcl->AceCount ++;
pAce->Mask = Mask | SYNCHRONIZE | AFP_MIN_ACCESS;
pAce->Header.AceFlags = CONTAINER_INHERIT_ACE |
OBJECT_INHERIT_ACE |
INHERIT_ONLY_ACE;
pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
pAce->Header.AceSize = (USHORT)(sizeof(ACE_HEADER) +
sizeof(ACCESS_MASK) +
SidLen);
RtlCopyMemory((PSID)(&pAce->SidStart), pSid, SidLen);
pAcl->AclSize += pAce->Header.AceSize;
AfpDumpSidnMask("afpAddAceToAcl (Inherit) ",
pSid,
pAce->Mask,
ACCESS_ALLOWED_ACE_TYPE,
pAce->Header.AceFlags);
}
return ((PACCESS_ALLOWED_ACE)((PBYTE)pAce + pAce->Header.AceSize));
}
#if DBG
/*** AfpDumpSid
*
*/
VOID
AfpDumpSid(
IN PBYTE pString,
IN PISID pSid
)
{
WCHAR Buffer[128];
UNICODE_STRING SidStr;
PAGED_CODE( );
AfpSetEmptyUnicodeString(&SidStr, sizeof(Buffer), Buffer);
if ((AfpDebugComponent & DBG_COMP_SECURITY) && (DBG_LEVEL_INFO >= AfpDebugLevel))
{
RtlConvertSidToUnicodeString(&SidStr, pSid, False);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("%s %ws\n", pString, SidStr.Buffer));
}
}
/*** AfpDumpSidnMask
*
*/
VOID
AfpDumpSidnMask(
IN PBYTE pString,
IN PISID pSid,
IN DWORD Mask,
IN UCHAR Type,
IN UCHAR Flags
)
{
WCHAR Buffer[128];
UNICODE_STRING SidStr;
PAGED_CODE( );
AfpSetEmptyUnicodeString(&SidStr, sizeof(Buffer), Buffer);
if ((AfpDebugComponent & DBG_COMP_SECURITY) && (DBG_LEVEL_INFO >= AfpDebugLevel))
{
RtlConvertSidToUnicodeString(&SidStr, pSid, False);
DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
("%s Sid %ws, Mask %lx, Type %x, Flags %x\n",
pString, SidStr.Buffer, Mask, Type, Flags));
}
}
#endif