|
|
/*
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
|