/* 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 #include #include #define _ACCESS_LOCALS #include #include #include #include #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