static DWORD MapBuiltinSidToName( PWSTR *ppwszName, PSID pSid ) { DWORD dwError = 0; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } Sid; ULONG SidSize = sizeof(Sid.buffer); PWSTR pwszEveryone = NULL; dwError = LwNtStatusToWin32Error( RtlCreateWellKnownSid( WinWorldSid, NULL, &Sid.sid, &SidSize)); BAIL_ON_LTNET_ERROR(dwError); if (RtlEqualSid(&Sid.sid, pSid)) { dwError = LwNtStatusToWin32Error( RtlWC16StringAllocateFromCString( &pwszEveryone, "Everyone")); BAIL_ON_LTNET_ERROR(dwError); } *ppwszName = pwszEveryone; cleanup: return dwError; error: LwNetWC16StringFree(pwszEveryone); goto cleanup; }
static DWORD MapBuiltinNameToSid( PSID *ppSid, PCWSTR pwszName ) { DWORD dwError = 0; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } Sid; ULONG SidSize = sizeof(Sid.buffer); PWSTR pwszEveryone = NULL; dwError = LwNtStatusToWin32Error( RtlWC16StringAllocateFromCString( &pwszEveryone, "Everyone")); BAIL_ON_SRVSVC_ERROR(dwError); if (LwRtlWC16StringIsEqual(pwszName, pwszEveryone, FALSE)) { dwError = LwNtStatusToWin32Error( RtlCreateWellKnownSid( WinWorldSid, NULL, &Sid.sid, &SidSize)); } BAIL_ON_SRVSVC_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlDuplicateSid(ppSid, &Sid.sid)); cleanup: LW_RTL_FREE(&pwszEveryone); return dwError; error: goto cleanup; }
NTSTATUS SrvShareSetDefaultSecurity( PSRV_SHARE_INFO pShareInfo ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSECURITY_DESCRIPTOR_RELATIVE pRelSecDesc = NULL; ULONG ulRelSecDescLen = 0; PSECURITY_DESCRIPTOR_ABSOLUTE pAbsSecDesc = NULL; DWORD dwAceCount = 0; PSID pOwnerSid = NULL; PSID pGroupSid = NULL; PACL pDacl = NULL; DWORD dwSizeDacl = 0; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } administratorsSid; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } powerUsersSid; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } everyoneSid; ULONG ulAdministratorsSidSize = sizeof(administratorsSid.buffer); ULONG ulPowerUsersSidSize = sizeof(powerUsersSid.buffer); ULONG ulEveryoneSidSize = sizeof(everyoneSid.buffer); ACCESS_MASK worldAccessMask = 0; /* Clear out any existing SecDesc's. This is not a normal use case, but be paranoid */ if (pShareInfo->ulSecDescLen) { SrvShareFreeSecurity(pShareInfo); } /* Build the new Absolute Security Descriptor */ ntStatus = RTL_ALLOCATE( &pAbsSecDesc, VOID, SECURITY_DESCRIPTOR_ABSOLUTE_MIN_SIZE); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlCreateSecurityDescriptorAbsolute( pAbsSecDesc, SECURITY_DESCRIPTOR_REVISION); BAIL_ON_NT_STATUS(ntStatus); /* Create some SIDs */ ntStatus = RtlCreateWellKnownSid( WinBuiltinAdministratorsSid, NULL, (PSID)administratorsSid.buffer, &ulAdministratorsSidSize); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlCreateWellKnownSid( WinBuiltinPowerUsersSid, NULL, (PSID)powerUsersSid.buffer, &ulPowerUsersSidSize); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlCreateWellKnownSid( WinWorldSid, NULL, (PSID)everyoneSid.buffer, &ulEveryoneSidSize); BAIL_ON_NT_STATUS(ntStatus); /* Owner: Administrators */ ntStatus = RtlDuplicateSid(&pOwnerSid, &administratorsSid.sid); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlSetOwnerSecurityDescriptor( pAbsSecDesc, pOwnerSid, FALSE); BAIL_ON_NT_STATUS(ntStatus); /* Group: Power Users */ ntStatus = RtlDuplicateSid(&pGroupSid, &powerUsersSid.sid); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlSetGroupSecurityDescriptor( pAbsSecDesc, pGroupSid, FALSE); BAIL_ON_NT_STATUS(ntStatus); /* DACL: Administrators - (Full Control) Everyone - (Read) for disk shares, (Read/Write) to IPC shares */ dwAceCount = 2; dwSizeDacl = ACL_HEADER_SIZE + dwAceCount * sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(&administratorsSid.sid) + RtlLengthSid(&everyoneSid.sid) - dwAceCount * sizeof(ULONG); ntStatus= RTL_ALLOCATE(&pDacl, VOID, dwSizeDacl); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlCreateAcl(pDacl, dwSizeDacl, ACL_REVISION); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlAddAccessAllowedAceEx( pDacl, ACL_REVISION, 0, FILE_ALL_ACCESS, &administratorsSid.sid); BAIL_ON_NT_STATUS(ntStatus); worldAccessMask = FILE_GENERIC_READ | FILE_GENERIC_EXECUTE; if (pShareInfo->service == SHARE_SERVICE_NAMED_PIPE) { worldAccessMask |= FILE_GENERIC_WRITE; } ntStatus = RtlAddAccessAllowedAceEx( pDacl, ACL_REVISION, 0, worldAccessMask, &everyoneSid.sid); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlSetDaclSecurityDescriptor( pAbsSecDesc, TRUE, pDacl, FALSE); BAIL_ON_NT_STATUS(ntStatus); /* Create the SelfRelative SD and assign them to the Share */ ntStatus = RtlAbsoluteToSelfRelativeSD( pAbsSecDesc, NULL, &ulRelSecDescLen); if (ntStatus == STATUS_BUFFER_TOO_SMALL) { ntStatus = SrvAllocateMemory(ulRelSecDescLen, (PVOID*)&pRelSecDesc); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlAbsoluteToSelfRelativeSD( pAbsSecDesc, pRelSecDesc, &ulRelSecDescLen); } BAIL_ON_NT_STATUS(ntStatus); pShareInfo->pSecDesc = pRelSecDesc; pShareInfo->ulSecDescLen = ulRelSecDescLen; pShareInfo->pAbsSecDesc = pAbsSecDesc; ntStatus = STATUS_SUCCESS; cleanup: return ntStatus; error: RTL_FREE(&pAbsSecDesc); RTL_FREE(&pOwnerSid); RTL_FREE(&pGroupSid); RTL_FREE(&pDacl); if (pRelSecDesc) { SrvFreeMemory(pRelSecDesc); } goto cleanup; }
static DWORD ConstructSecurityDescriptor( DWORD dwAllowUserCount, PWSTR* ppwszAllowUsers, DWORD dwDenyUserCount, PWSTR* ppwszDenyUsers, BOOLEAN bReadOnly, PSECURITY_DESCRIPTOR_RELATIVE* ppRelative, PDWORD pdwRelativeSize ) { DWORD dwError = 0; PSECURITY_DESCRIPTOR_ABSOLUTE pAbsolute = NULL; PSECURITY_DESCRIPTOR_RELATIVE pRelative = NULL; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } Owner; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } Group; ULONG OwnerSidSize = sizeof(Owner.buffer); ULONG GroupSidSize = sizeof(Group.buffer); DWORD dwDaclSize = 0; PACL pDacl = NULL; DWORD dwIndex = 0; PSID pSid = NULL; ULONG ulRelativeSize = 0; HANDLE hLsa = NULL; ACCESS_MASK mask = bReadOnly ? (FILE_GENERIC_READ|FILE_GENERIC_EXECUTE) : FILE_ALL_ACCESS; dwError = LsaOpenServer(&hLsa); BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlCreateWellKnownSid( WinBuiltinAdministratorsSid, NULL, &Owner.sid, &OwnerSidSize)); BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlCreateWellKnownSid( WinBuiltinPowerUsersSid, NULL, &Group.sid, &GroupSidSize)); BAIL_ON_LTNET_ERROR(dwError); dwDaclSize = ACL_HEADER_SIZE + dwAllowUserCount * (sizeof(ACCESS_ALLOWED_ACE) + SID_MAX_SIZE) + dwDenyUserCount * (sizeof(ACCESS_DENIED_ACE) + SID_MAX_SIZE) + RtlLengthSid(&Owner.sid) + RtlLengthSid(&Group.sid); dwError = LwNetAllocateMemory( dwDaclSize, OUT_PPVOID(&pDacl)); BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlCreateAcl(pDacl, dwDaclSize, ACL_REVISION)); BAIL_ON_LTNET_ERROR(dwError); for (dwIndex = 0; dwIndex < dwDenyUserCount; dwIndex++) { dwError = MapNameToSid(hLsa, ppwszDenyUsers[dwIndex], &pSid); if (dwError != LW_ERROR_SUCCESS) { dwError = MapBuiltinNameToSid(&pSid, ppwszDenyUsers[dwIndex]); } BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlAddAccessDeniedAceEx( pDacl, ACL_REVISION, 0, FILE_ALL_ACCESS, pSid)); BAIL_ON_LTNET_ERROR(dwError); RTL_FREE(&pSid); } for (dwIndex = 0; dwIndex < dwAllowUserCount; dwIndex++) { dwError = MapNameToSid(hLsa, ppwszAllowUsers[dwIndex], &pSid); if (dwError != LW_ERROR_SUCCESS) { dwError = MapBuiltinNameToSid(&pSid, ppwszAllowUsers[dwIndex]); } BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlAddAccessAllowedAceEx( pDacl, ACL_REVISION, 0, mask, pSid)); BAIL_ON_LTNET_ERROR(dwError); RTL_FREE(&pSid); } dwError = LwNetAllocateMemory( SECURITY_DESCRIPTOR_ABSOLUTE_MIN_SIZE, OUT_PPVOID(&pAbsolute)); BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlCreateSecurityDescriptorAbsolute( pAbsolute, SECURITY_DESCRIPTOR_REVISION)); BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlSetOwnerSecurityDescriptor( pAbsolute, &Owner.sid, FALSE)); BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlSetGroupSecurityDescriptor( pAbsolute, &Group.sid, FALSE)); BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlSetDaclSecurityDescriptor( pAbsolute, TRUE, pDacl, FALSE)); BAIL_ON_LTNET_ERROR(dwError); RtlAbsoluteToSelfRelativeSD( pAbsolute, NULL, &ulRelativeSize); dwError = LwNetAllocateMemory(ulRelativeSize, OUT_PPVOID(&pRelative)); BAIL_ON_LTNET_ERROR(dwError); dwError = LwNtStatusToWin32Error( RtlAbsoluteToSelfRelativeSD( pAbsolute, pRelative, &ulRelativeSize)); BAIL_ON_LTNET_ERROR(dwError); *ppRelative = pRelative; *pdwRelativeSize = ulRelativeSize; cleanup: if (hLsa) { LsaCloseServer(hLsa); } LTNET_SAFE_FREE_MEMORY(pSid); LTNET_SAFE_FREE_MEMORY(pDacl); LTNET_SAFE_FREE_MEMORY(pAbsolute); return dwError; error: *ppRelative = NULL; *pdwRelativeSize = 0; LTNET_SAFE_FREE_MEMORY(pRelative); goto cleanup; }
static NTSTATUS SrvBuildDefaultShareSID( PSECURITY_DESCRIPTOR_RELATIVE* ppSecDesc ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSECURITY_DESCRIPTOR_RELATIVE pRelSecDesc = NULL; ULONG ulRelSecDescLen = 0; PSECURITY_DESCRIPTOR_ABSOLUTE pAbsSecDesc = NULL; DWORD dwAceCount = 0; PSID pOwnerSid = NULL; PSID pGroupSid = NULL; PACL pDacl = NULL; DWORD dwSizeDacl = 0; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } localSystemSid; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } administratorsSid; union { SID sid; BYTE buffer[SID_MAX_SIZE]; } builtinUsersSid; ULONG ulLocalSystemSidSize = sizeof(localSystemSid.buffer); ULONG ulAdministratorsSidSize = sizeof(administratorsSid.buffer); ULONG ulBuiltinUsersSidSize = sizeof(builtinUsersSid.buffer); ACCESS_MASK builtinUsersAccessMask = 0; ULONG ulAceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; /* Build the new Absolute Security Descriptor */ ntStatus = RTL_ALLOCATE( &pAbsSecDesc, VOID, SECURITY_DESCRIPTOR_ABSOLUTE_MIN_SIZE); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlCreateSecurityDescriptorAbsolute( pAbsSecDesc, SECURITY_DESCRIPTOR_REVISION); BAIL_ON_NT_STATUS(ntStatus); /* Create some SIDs */ ntStatus = RtlCreateWellKnownSid( WinLocalSystemSid, NULL, (PSID)localSystemSid.buffer, &ulLocalSystemSidSize); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlCreateWellKnownSid( WinBuiltinAdministratorsSid, NULL, (PSID)administratorsSid.buffer, &ulAdministratorsSidSize); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlCreateWellKnownSid( WinBuiltinUsersSid, NULL, (PSID)builtinUsersSid.buffer, &ulBuiltinUsersSidSize); BAIL_ON_NT_STATUS(ntStatus); /* Owner: Local System */ ntStatus = RtlDuplicateSid(&pOwnerSid, &localSystemSid.sid); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlSetOwnerSecurityDescriptor( pAbsSecDesc, pOwnerSid, FALSE); BAIL_ON_NT_STATUS(ntStatus); /* Group: Administrators */ ntStatus = RtlDuplicateSid(&pGroupSid, &administratorsSid.sid); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlSetGroupSecurityDescriptor( pAbsSecDesc, pGroupSid, FALSE); BAIL_ON_NT_STATUS(ntStatus); /* DACL: Administrators - (Full Control) LocalSystem - (Full Control) Builtin Users - (Read && Execute && List Directory Contents) */ dwAceCount = 3; dwSizeDacl = ACL_HEADER_SIZE + dwAceCount * sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(&localSystemSid.sid) + RtlLengthSid(&administratorsSid.sid) + RtlLengthSid(&builtinUsersSid.sid) - dwAceCount * sizeof(ULONG); ntStatus= RTL_ALLOCATE(&pDacl, VOID, dwSizeDacl); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlCreateAcl(pDacl, dwSizeDacl, ACL_REVISION); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlAddAccessAllowedAceEx( pDacl, ACL_REVISION, ulAceFlags, FILE_ALL_ACCESS, &localSystemSid.sid); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlAddAccessAllowedAceEx( pDacl, ACL_REVISION, ulAceFlags, FILE_ALL_ACCESS, &administratorsSid.sid); BAIL_ON_NT_STATUS(ntStatus); builtinUsersAccessMask = FILE_GENERIC_READ | FILE_GENERIC_EXECUTE; ntStatus = RtlAddAccessAllowedAceEx( pDacl, ACL_REVISION, ulAceFlags, builtinUsersAccessMask, &builtinUsersSid.sid); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlSetDaclSecurityDescriptor( pAbsSecDesc, TRUE, pDacl, FALSE); BAIL_ON_NT_STATUS(ntStatus); /* Create the SelfRelative SD */ ntStatus = RtlAbsoluteToSelfRelativeSD( pAbsSecDesc, NULL, &ulRelSecDescLen); if (ntStatus == STATUS_BUFFER_TOO_SMALL) { ntStatus = SrvAllocateMemory(ulRelSecDescLen, (PVOID*)&pRelSecDesc); BAIL_ON_NT_STATUS(ntStatus); ntStatus = RtlAbsoluteToSelfRelativeSD( pAbsSecDesc, pRelSecDesc, &ulRelSecDescLen); } BAIL_ON_NT_STATUS(ntStatus); *ppSecDesc = pRelSecDesc; cleanup: RTL_FREE(&pAbsSecDesc); RTL_FREE(&pOwnerSid); RTL_FREE(&pGroupSid); RTL_FREE(&pDacl); return ntStatus; error: *ppSecDesc = NULL; if (pRelSecDesc) { SrvFreeMemory(pRelSecDesc); } goto cleanup; }
BOOLEAN RtlAccessCheckEx( IN PSECURITY_DESCRIPTOR_ABSOLUTE SecurityDescriptor, IN PACCESS_TOKEN AccessToken, IN ACCESS_MASK DesiredAccess, IN ACCESS_MASK PreviouslyGrantedAccess, IN PGENERIC_MAPPING GenericMapping, OUT PACCESS_MASK RemainingDesiredAccess, OUT PACCESS_MASK GrantedAccess, OUT PNTSTATUS AccessStatus ) { NTSTATUS status = STATUS_ACCESS_DENIED; BOOLEAN isLocked = FALSE; ACCESS_MASK grantedAccess = PreviouslyGrantedAccess; ACCESS_MASK deniedAccess = 0; ACCESS_MASK desiredAccess = DesiredAccess; BOOLEAN wantMaxAllowed = FALSE; USHORT aclSizeUsed = 0; USHORT aceOffset = 0; PACE_HEADER aceHeader = NULL; union { SID Sid; BYTE Buffer[SID_MAX_SIZE]; } sidBuffer; ULONG ulSidSize = sizeof(sidBuffer); if (!SecurityDescriptor || !AccessToken || !GenericMapping) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } if (!LW_IS_VALID_FLAGS(DesiredAccess, VALID_DESIRED_ACCESS_MASK)) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } if (!LW_IS_VALID_FLAGS(PreviouslyGrantedAccess, VALID_GRANTED_ACCESS_MASK)) { status = STATUS_INVALID_PARAMETER; GOTO_CLEANUP(); } if ((SecurityDescriptor->Owner == NULL) || (SecurityDescriptor->Group == NULL)) { status = STATUS_INVALID_SECURITY_DESCR; GOTO_CLEANUP(); } wantMaxAllowed = IsSetFlag(desiredAccess, MAXIMUM_ALLOWED); ClearFlag(desiredAccess, MAXIMUM_ALLOWED); RtlMapGenericMask(&desiredAccess, GenericMapping); // // NT AUTHORITY\SYSTEM is always allowed an access // status = RtlCreateWellKnownSid(WinLocalSystemSid, NULL, &sidBuffer.Sid, &ulSidSize); GOTO_CLEANUP_ON_STATUS(status); SHARED_LOCK_RWLOCK(&AccessToken->RwLock, isLocked); if (RtlIsSidMemberOfToken(AccessToken, &sidBuffer.Sid)) { if (wantMaxAllowed) { SetFlag(desiredAccess, STANDARD_RIGHTS_ALL); SetFlag(desiredAccess, GENERIC_ALL); RtlMapGenericMask(&desiredAccess, GenericMapping); } SetFlag(grantedAccess, desiredAccess); desiredAccess = 0; status = STATUS_SUCCESS; GOTO_CLEANUP(); } if (wantMaxAllowed || IsSetFlag(desiredAccess, ACCESS_SYSTEM_SECURITY)) { // TODO-Handle ACCESS_SYSTEM_SECURITY by checking SE_SECURITY_NAME // privilege. For now, requesting ACCESS_SYSTEM_SECURITY is not // allowed. ulSidSize = sizeof(sidBuffer); status = RtlCreateWellKnownSid( WinBuiltinAdministratorsSid, NULL, &sidBuffer.Sid, &ulSidSize); GOTO_CLEANUP_ON_STATUS(status); if (RtlIsSidMemberOfToken(AccessToken, &sidBuffer.Sid)) { SetFlag(grantedAccess, ACCESS_SYSTEM_SECURITY); ClearFlag(desiredAccess, ACCESS_SYSTEM_SECURITY); } else if (IsSetFlag(desiredAccess, ACCESS_SYSTEM_SECURITY)) { status = STATUS_PRIVILEGE_NOT_HELD; GOTO_CLEANUP(); } } if (wantMaxAllowed || IsSetFlag(desiredAccess, WRITE_OWNER)) { // TODO-Allow WRITE_OWNER if have SE_TAKE_OWNERSHIP_NAME regardless // of DACL. // // BUILTIN\Administrators are always allowed WRITE_OWNER // ulSidSize = sizeof(sidBuffer); status = RtlCreateWellKnownSid( WinBuiltinAdministratorsSid, NULL, &sidBuffer.Sid, &ulSidSize); GOTO_CLEANUP_ON_STATUS(status); if (RtlIsSidMemberOfToken(AccessToken, &sidBuffer.Sid)) { SetFlag(grantedAccess, WRITE_OWNER); ClearFlag(desiredAccess, WRITE_OWNER); } } // // Owner can always read the SD and write the DACL. // if (wantMaxAllowed || IsSetFlag(desiredAccess, READ_CONTROL | WRITE_DAC)) { if (RtlIsSidMemberOfToken(AccessToken, SecurityDescriptor->Owner)) { if (wantMaxAllowed) { desiredAccess |= (READ_CONTROL | WRITE_DAC); } SetFlag(grantedAccess, (READ_CONTROL | WRITE_DAC) & desiredAccess); ClearFlag(desiredAccess, grantedAccess); } } // TODO-MAXIMUM_ALLOWED wrt privileges and WRITE_OWNER and // ACCESS_SYSTEM_SECURITY above. if (!SecurityDescriptor->Dacl) { // TODO-Interplay with special bits above? if (wantMaxAllowed) { SetFlag(desiredAccess, STANDARD_RIGHTS_ALL); SetFlag(desiredAccess, GENERIC_ALL); RtlMapGenericMask(&desiredAccess, GenericMapping); } SetFlag(grantedAccess, desiredAccess); desiredAccess = 0; status = STATUS_SUCCESS; GOTO_CLEANUP(); } if (!RtlValidAcl(SecurityDescriptor->Dacl, &aclSizeUsed)) { status = STATUS_INVALID_ACL; GOTO_CLEANUP(); } while (wantMaxAllowed || desiredAccess) { status = RtlIterateAce(SecurityDescriptor->Dacl, aclSizeUsed, &aceOffset, &aceHeader); if (STATUS_NO_MORE_ENTRIES == status) { break; } GOTO_CLEANUP_ON_STATUS(status); // Check ACE switch (aceHeader->AceType) { case ACCESS_ALLOWED_ACE_TYPE: { PACCESS_ALLOWED_ACE ace = (PACCESS_ALLOWED_ACE) aceHeader; ACCESS_MASK mask = ace->Mask; RtlMapGenericMask(&mask, GenericMapping); if (wantMaxAllowed || IsSetFlag(desiredAccess, mask)) { // SID in token => add bits to granted bits PSID sid = RtlpGetSidAccessAllowedAce(ace); if (RtlIsSidMemberOfToken(AccessToken, sid)) { if (wantMaxAllowed) { SetFlag(grantedAccess, mask & ~deniedAccess); } else { SetFlag(grantedAccess, mask & desiredAccess); } ClearFlag(desiredAccess, grantedAccess); } } break; } case ACCESS_DENIED_ACE_TYPE: { // Allowed and deny ACEs are isomorphic. PACCESS_ALLOWED_ACE ace = (PACCESS_ALLOWED_ACE) aceHeader; ACCESS_MASK mask = ace->Mask; RtlMapGenericMask(&mask, GenericMapping); if (wantMaxAllowed || IsSetFlag(desiredAccess, mask)) { // SID in token => exit with STATUS_ACCESS_DENIED PSID sid = RtlpGetSidAccessAllowedAce(ace); if (RtlIsSidMemberOfToken(AccessToken, sid)) { if (wantMaxAllowed) { SetFlag(deniedAccess, mask); } else { status = STATUS_ACCESS_DENIED; GOTO_CLEANUP(); } ClearFlag(desiredAccess, deniedAccess); } } break; } default: // ignore break; } } status = desiredAccess ? STATUS_ACCESS_DENIED : STATUS_SUCCESS; cleanup: UNLOCK_RWLOCK(&AccessToken->RwLock, isLocked); if (NT_SUCCESS(status) && !LW_IS_VALID_FLAGS(grantedAccess, VALID_GRANTED_ACCESS_MASK)) { status = STATUS_ASSERTION_FAILURE; } if (!NT_SUCCESS(status)) { grantedAccess = PreviouslyGrantedAccess; } if (RemainingDesiredAccess) { *RemainingDesiredAccess = desiredAccess; } *GrantedAccess = grantedAccess; *AccessStatus = status; return NT_SUCCESS(status) ? TRUE : FALSE; }
NTSTATUS PvfsSetSecurityDescriptorFile( IN PPVFS_CCB pCcb, IN SECURITY_INFORMATION SecInfo, IN PSECURITY_DESCRIPTOR_RELATIVE pSecDesc, IN ULONG SecDescLength ) { NTSTATUS ntError = STATUS_ACCESS_DENIED; PSECURITY_DESCRIPTOR_RELATIVE pFinalSecDesc = NULL; ULONG ulFinalSecDescLength = 0; SECURITY_INFORMATION SecInfoAll = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION); BYTE pCurrentSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE]; ULONG ulCurrentSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE; BYTE pNewSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE]; ULONG ulNewSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE; PSECURITY_DESCRIPTOR_ABSOLUTE pIncAbsSecDesc = NULL; union { TOKEN_OWNER TokenOwnerInfo; BYTE Buffer[SID_MAX_SIZE]; } TokenOwnerBuffer; PTOKEN_OWNER pTokenOwnerInformation = (PTOKEN_OWNER)&TokenOwnerBuffer; ULONG ulTokenOwnerLength = 0; union { SID Sid; BYTE Buffer[SID_MAX_SIZE]; } LocalSystemSidBuffer; PSID pLocalSystemSid = (PSID)&LocalSystemSidBuffer; ULONG ulLocalSystemSidLength = sizeof(LocalSystemSidBuffer); memset(pCurrentSecDescBuffer, 0, SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE); memset(pNewSecDescBuffer, 0, SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE); memset(TokenOwnerBuffer.Buffer, 0, SID_MAX_SIZE); /* Sanity checks */ if (SecInfo == 0) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } /* If the new Security Descriptor contains owner or group SID information, berify that the user's ACCESS_TOKEN contains the SID as a member */ if (SecInfo & (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION)) { PSID pOwner = NULL; PSID pGroup = NULL; BOOLEAN bDefaulted = FALSE; ntError = PvfsSecurityAclSelfRelativeToAbsoluteSD( &pIncAbsSecDesc, pSecDesc); BAIL_ON_NT_STATUS(ntError); ntError = RtlQueryAccessTokenInformation( pCcb->pUserToken, TokenOwner, (PVOID)pTokenOwnerInformation, sizeof(TokenOwnerBuffer), &ulTokenOwnerLength); BAIL_ON_NT_STATUS(ntError); ntError = RtlCreateWellKnownSid( WinLocalSystemSid, NULL, pLocalSystemSid, &ulLocalSystemSidLength); BAIL_ON_NT_STATUS(ntError); if (SecInfo & OWNER_SECURITY_INFORMATION) { ntError = RtlGetOwnerSecurityDescriptor( pIncAbsSecDesc, &pOwner, &bDefaulted); BAIL_ON_NT_STATUS(ntError); if (!RtlIsSidMemberOfToken(pCcb->pUserToken, pOwner) && !RtlEqualSid(pLocalSystemSid, pTokenOwnerInformation->Owner)) { ntError = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(ntError); } } if (SecInfo & GROUP_SECURITY_INFORMATION) { ntError = RtlGetGroupSecurityDescriptor( pIncAbsSecDesc, &pGroup, &bDefaulted); BAIL_ON_NT_STATUS(ntError); if (!RtlIsSidMemberOfToken(pCcb->pUserToken, pGroup) && !RtlEqualSid(pLocalSystemSid, pTokenOwnerInformation->Owner)) { ntError = STATUS_ACCESS_DENIED; BAIL_ON_NT_STATUS(ntError); } } } if (SecInfo == SecInfoAll) { /* We already have a fully formed Security Descriptor */ pFinalSecDesc = pSecDesc; ulFinalSecDescLength = SecDescLength; } else { /* Retrieve the existing SD and merge with the incoming one */ ntError = PvfsGetSecurityDescriptorFile( pCcb, SecInfoAll, (PSECURITY_DESCRIPTOR_RELATIVE)pCurrentSecDescBuffer, &ulCurrentSecDescLength); BAIL_ON_NT_STATUS(ntError); /* Assume that the new SD is <= the combined size of the current SD and the incoming one */ ntError = RtlSetSecurityDescriptorInfo( SecInfo, pSecDesc, (PSECURITY_DESCRIPTOR_RELATIVE)pCurrentSecDescBuffer, (PSECURITY_DESCRIPTOR_RELATIVE)pNewSecDescBuffer, &ulNewSecDescLength, &gPvfsFileGenericMapping); BAIL_ON_NT_STATUS(ntError); pFinalSecDesc = (PSECURITY_DESCRIPTOR_RELATIVE)pNewSecDescBuffer; ulFinalSecDescLength = ulNewSecDescLength; } /* Save the combined SD */ #ifdef HAVE_EA_SUPPORT ntError = PvfsSetSecurityDescriptorFileXattr( pCcb, pFinalSecDesc, ulFinalSecDescLength); #else ntError = PvfsSetSecurityDescriptorPosix( pCcb, pFinalSecDesc, ulFinalSecDescLength); #endif BAIL_ON_NT_STATUS(ntError); PvfsNotifyScheduleFullReport( pCcb->pFcb, FILE_NOTIFY_CHANGE_SECURITY, FILE_ACTION_MODIFIED, pCcb->pszFilename); cleanup: if (pIncAbsSecDesc) { PvfsFreeAbsoluteSecurityDescriptor(&pIncAbsSecDesc); } return ntError; error: goto cleanup; }