/* * Security functions * * Copyright 1996-1998 Marcus Meissner * Copyright 2003 CodeWeavers Inc. (Ulrich Czekalla) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <ctype.h> #include <math.h> #ifdef HAVE_UNISTD_H # include <unistd.h> #endif #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" #include "ntdll_misc.h" #include "wine/exception.h" #include "wine/library.h" #include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ntdll); #define NT_SUCCESS(status) (status == STATUS_SUCCESS) #define SELF_RELATIVE_FIELD(sd,field) ((BYTE *)(sd) + ((SECURITY_DESCRIPTOR_RELATIVE *)(sd))->field) /* helper function to retrieve active length of an ACL */ static size_t acl_bytesInUse(PACL pAcl) { int i; size_t bytesInUse = sizeof(ACL); PACE_HEADER ace = (PACE_HEADER) (pAcl + 1); for (i = 0; i < pAcl->AceCount; i++) { bytesInUse += ace->AceSize; ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize); } return bytesInUse; } /* helper function to copy an ACL */ static BOOLEAN copy_acl(DWORD nDestinationAclLength, PACL pDestinationAcl, PACL pSourceAcl) { DWORD size; if (!pSourceAcl || !RtlValidAcl(pSourceAcl)) return FALSE; size = pSourceAcl->AclSize; if (nDestinationAclLength < size) return FALSE; memmove(pDestinationAcl, pSourceAcl, size); return TRUE; } /* generically adds an ACE to an ACL */ static NTSTATUS add_access_ace(PACL pAcl, DWORD dwAceRevision, DWORD dwAceFlags, DWORD dwAccessMask, PSID pSid, DWORD dwAceType) { ACE_HEADER *pAceHeader; DWORD dwLengthSid; DWORD dwAceSize; DWORD *pAccessMask; DWORD *pSidStart; if (!RtlValidSid(pSid)) return STATUS_INVALID_SID; if (pAcl->AclRevision > MAX_ACL_REVISION || dwAceRevision > MAX_ACL_REVISION) return STATUS_REVISION_MISMATCH; if (!RtlValidAcl(pAcl)) return STATUS_INVALID_ACL; if (!RtlFirstFreeAce(pAcl, &pAceHeader)) return STATUS_INVALID_ACL; if (!pAceHeader) return STATUS_ALLOTTED_SPACE_EXCEEDED; /* calculate generic size of the ACE */ dwLengthSid = RtlLengthSid(pSid); dwAceSize = sizeof(ACE_HEADER) + sizeof(DWORD) + dwLengthSid; if ((char *)pAceHeader + dwAceSize > (char *)pAcl + pAcl->AclSize) return STATUS_ALLOTTED_SPACE_EXCEEDED; /* fill the new ACE */ pAceHeader->AceType = dwAceType; pAceHeader->AceFlags = dwAceFlags; pAceHeader->AceSize = dwAceSize; /* skip past the ACE_HEADER of the ACE */ pAccessMask = (DWORD *)(pAceHeader + 1); *pAccessMask = dwAccessMask; /* skip past ACE->Mask */ pSidStart = pAccessMask + 1; RtlCopySid(dwLengthSid, pSidStart, pSid); pAcl->AclRevision = max(pAcl->AclRevision, dwAceRevision); pAcl->AceCount++; return STATUS_SUCCESS; } /* * SID FUNCTIONS */ /****************************************************************************** * RtlAllocateAndInitializeSid [NTDLL.@] * */ NTSTATUS WINAPI RtlAllocateAndInitializeSid ( PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount, DWORD nSubAuthority0, DWORD nSubAuthority1, DWORD nSubAuthority2, DWORD nSubAuthority3, DWORD nSubAuthority4, DWORD nSubAuthority5, DWORD nSubAuthority6, DWORD nSubAuthority7, PSID *pSid ) { SID *tmp_sid; TRACE("(%p, 0x%04x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,0x%08x,%p)\n", pIdentifierAuthority,nSubAuthorityCount, nSubAuthority0, nSubAuthority1, nSubAuthority2, nSubAuthority3, nSubAuthority4, nSubAuthority5, nSubAuthority6, nSubAuthority7, pSid); if (nSubAuthorityCount > 8) return STATUS_INVALID_SID; if (!(tmp_sid= RtlAllocateHeap( GetProcessHeap(), 0, RtlLengthRequiredSid(nSubAuthorityCount)))) return STATUS_NO_MEMORY; tmp_sid->Revision = SID_REVISION; if (pIdentifierAuthority) tmp_sid->IdentifierAuthority = *pIdentifierAuthority; tmp_sid->SubAuthorityCount = nSubAuthorityCount; switch( nSubAuthorityCount ) { case 8: tmp_sid->SubAuthority[7]= nSubAuthority7; case 7: tmp_sid->SubAuthority[6]= nSubAuthority6; case 6: tmp_sid->SubAuthority[5]= nSubAuthority5; case 5: tmp_sid->SubAuthority[4]= nSubAuthority4; case 4: tmp_sid->SubAuthority[3]= nSubAuthority3; case 3: tmp_sid->SubAuthority[2]= nSubAuthority2; case 2: tmp_sid->SubAuthority[1]= nSubAuthority1; case 1: tmp_sid->SubAuthority[0]= nSubAuthority0; break; } *pSid = tmp_sid; return STATUS_SUCCESS; } /****************************************************************************** * RtlEqualSid [NTDLL.@] * * Determine if two SIDs are equal. * * PARAMS * pSid1 [I] Source SID * pSid2 [I] SID to compare with * * RETURNS * TRUE, if pSid1 is equal to pSid2, * FALSE otherwise. */ BOOL WINAPI RtlEqualSid( PSID pSid1, PSID pSid2 ) { if (!RtlValidSid(pSid1) || !RtlValidSid(pSid2)) return FALSE; if (*RtlSubAuthorityCountSid(pSid1) != *RtlSubAuthorityCountSid(pSid2)) return FALSE; if (memcmp(pSid1, pSid2, RtlLengthSid(pSid1)) != 0) return FALSE; return TRUE; } /****************************************************************************** * RtlEqualPrefixSid [NTDLL.@] */ BOOL WINAPI RtlEqualPrefixSid (PSID pSid1, PSID pSid2) { if (!RtlValidSid(pSid1) || !RtlValidSid(pSid2)) return FALSE; if (*RtlSubAuthorityCountSid(pSid1) != *RtlSubAuthorityCountSid(pSid2)) return FALSE; if (memcmp(pSid1, pSid2, RtlLengthRequiredSid(((SID*)pSid1)->SubAuthorityCount - 1)) != 0) return FALSE; return TRUE; } /****************************************************************************** * RtlFreeSid [NTDLL.@] * * Free the resources used by a SID. * * PARAMS * pSid [I] SID to Free. * * RETURNS * STATUS_SUCCESS. */ DWORD WINAPI RtlFreeSid(PSID pSid) { TRACE("(%p)\n", pSid); RtlFreeHeap( GetProcessHeap(), 0, pSid ); return STATUS_SUCCESS; } /************************************************************************** * RtlLengthRequiredSid [NTDLL.@] * * Determine the amount of memory a SID will use * * PARAMS * nrofsubauths [I] Number of Sub Authorities in the SID. * * RETURNS * The size, in bytes, of a SID with nrofsubauths Sub Authorities. */ DWORD WINAPI RtlLengthRequiredSid(DWORD nrofsubauths) { return (nrofsubauths-1)*sizeof(DWORD) + sizeof(SID); } /************************************************************************** * RtlLengthSid [NTDLL.@] * * Determine the amount of memory a SID is using * * PARAMS * pSid [I] SID to get the size of. * * RETURNS * The size, in bytes, of pSid. */ DWORD WINAPI RtlLengthSid(PSID pSid) { TRACE("sid=%p\n",pSid); if (!pSid) return 0; return RtlLengthRequiredSid(*RtlSubAuthorityCountSid(pSid)); } /************************************************************************** * RtlInitializeSid [NTDLL.@] * * Initialise a SID. * * PARAMS * pSid [I] SID to initialise * pIdentifierAuthority [I] Identifier Authority * nSubAuthorityCount [I] Number of Sub Authorities * * RETURNS * Success: TRUE. pSid is initialised with the details given. * Failure: FALSE, if nSubAuthorityCount is >= SID_MAX_SUB_AUTHORITIES. */ BOOL WINAPI RtlInitializeSid( PSID pSid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount) { int i; SID* pisid=pSid; if (nSubAuthorityCount >= SID_MAX_SUB_AUTHORITIES) return FALSE; pisid->Revision = SID_REVISION; pisid->SubAuthorityCount = nSubAuthorityCount; if (pIdentifierAuthority) pisid->IdentifierAuthority = *pIdentifierAuthority; for (i = 0; i < nSubAuthorityCount; i++) *RtlSubAuthoritySid(pSid, i) = 0; return TRUE; } /************************************************************************** * RtlSubAuthoritySid [NTDLL.@] * * Return the Sub Authority of a SID * * PARAMS * pSid [I] SID to get the Sub Authority from. * nSubAuthority [I] Sub Authority number. * * RETURNS * A pointer to The Sub Authority value of pSid. */ LPDWORD WINAPI RtlSubAuthoritySid( PSID pSid, DWORD nSubAuthority ) { return &(((SID*)pSid)->SubAuthority[nSubAuthority]); } /************************************************************************** * RtlIdentifierAuthoritySid [NTDLL.@] * * Return the Identifier Authority of a SID. * * PARAMS * pSid [I] SID to get the Identifier Authority from. * * RETURNS * A pointer to the Identifier Authority value of pSid. */ PSID_IDENTIFIER_AUTHORITY WINAPI RtlIdentifierAuthoritySid( PSID pSid ) { return &(((SID*)pSid)->IdentifierAuthority); } /************************************************************************** * RtlSubAuthorityCountSid [NTDLL.@] * * Get the number of Sub Authorities in a SID. * * PARAMS * pSid [I] SID to get the count from. * * RETURNS * A pointer to the Sub Authority count of pSid. */ LPBYTE WINAPI RtlSubAuthorityCountSid(PSID pSid) { return &(((SID*)pSid)->SubAuthorityCount); } /************************************************************************** * RtlCopySid [NTDLL.@] */ BOOLEAN WINAPI RtlCopySid( DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid ) { if (!pSourceSid || !RtlValidSid(pSourceSid) || (nDestinationSidLength < RtlLengthSid(pSourceSid))) return FALSE; if (nDestinationSidLength < (((SID*)pSourceSid)->SubAuthorityCount*4+8)) return FALSE; memmove(pDestinationSid, pSourceSid, ((SID*)pSourceSid)->SubAuthorityCount*4+8); return TRUE; } /****************************************************************************** * RtlValidSid [NTDLL.@] * * Determine if a SID is valid. * * PARAMS * pSid [I] SID to check * * RETURNS * TRUE if pSid is valid, * FALSE otherwise. */ BOOLEAN WINAPI RtlValidSid( PSID pSid ) { BOOL ret; __TRY { ret = TRUE; if (!pSid || ((SID*)pSid)->Revision != SID_REVISION || ((SID*)pSid)->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) { ret = FALSE; } } __EXCEPT_PAGE_FAULT { WARN("(%p): invalid pointer!\n", pSid); return FALSE; } __ENDTRY return ret; } /* * security descriptor functions */ /************************************************************************** * RtlCreateSecurityDescriptor [NTDLL.@] * * Initialise a SECURITY_DESCRIPTOR. * * PARAMS * lpsd [O] Descriptor to initialise. * rev [I] Revision, must be set to SECURITY_DESCRIPTOR_REVISION. * * RETURNS * Success: STATUS_SUCCESS. * Failure: STATUS_UNKNOWN_REVISION if rev is incorrect. */ NTSTATUS WINAPI RtlCreateSecurityDescriptor( PSECURITY_DESCRIPTOR lpsd, DWORD rev) { if (rev!=SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; memset(lpsd,'\0',sizeof(SECURITY_DESCRIPTOR)); ((SECURITY_DESCRIPTOR*)lpsd)->Revision = SECURITY_DESCRIPTOR_REVISION; return STATUS_SUCCESS; } /************************************************************************** * RtlCopySecurityDescriptor [NTDLL.@] * * Copies an absolute or sefl-relative SECURITY_DESCRIPTOR. * * PARAMS * pSourceSD [O] SD to copy from. * pDestinationSD [I] Destination SD. * * RETURNS * Success: STATUS_SUCCESS. * Failure: STATUS_UNKNOWN_REVISION if rev is incorrect. */ NTSTATUS WINAPI RtlCopySecurityDescriptor(PSECURITY_DESCRIPTOR pSourceSD, PSECURITY_DESCRIPTOR pDestinationSD) { PSID Owner, Group; PACL Dacl, Sacl; DWORD length; if (((SECURITY_DESCRIPTOR *)pSourceSD)->Control & SE_SELF_RELATIVE) { SECURITY_DESCRIPTOR_RELATIVE *src = pSourceSD; SECURITY_DESCRIPTOR_RELATIVE *dst = pDestinationSD; if (src->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; *dst = *src; if (src->Owner) { Owner = (PSID)SELF_RELATIVE_FIELD( src, Owner ); length = RtlLengthSid( Owner ); RtlCopySid(length, SELF_RELATIVE_FIELD( dst, Owner ), Owner); } if (src->Group) { Group = (PSID)SELF_RELATIVE_FIELD( src, Group ); length = RtlLengthSid( Group ); RtlCopySid(length, SELF_RELATIVE_FIELD( dst, Group ), Group); } if (src->Control & SE_SACL_PRESENT) { Sacl = (PACL)SELF_RELATIVE_FIELD( src, Sacl ); copy_acl(Sacl->AclSize, (PACL)SELF_RELATIVE_FIELD( dst, Sacl ), Sacl); } if (src->Control & SE_DACL_PRESENT) { Dacl = (PACL)SELF_RELATIVE_FIELD( src, Dacl ); copy_acl(Dacl->AclSize, (PACL)SELF_RELATIVE_FIELD( dst, Dacl ), Dacl); } } else { SECURITY_DESCRIPTOR *src = pSourceSD; SECURITY_DESCRIPTOR *dst = pDestinationSD; if (src->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; *dst = *src; if (src->Owner) { length = RtlLengthSid( src->Owner ); dst->Owner = RtlAllocateHeap(GetProcessHeap(), 0, length); RtlCopySid(length, dst->Owner, src->Owner); } if (src->Group) { length = RtlLengthSid( src->Group ); dst->Group = RtlAllocateHeap(GetProcessHeap(), 0, length); RtlCopySid(length, dst->Group, src->Group); } if (src->Control & SE_SACL_PRESENT) { length = src->Sacl->AclSize; dst->Sacl = RtlAllocateHeap(GetProcessHeap(), 0, length); copy_acl(length, dst->Sacl, src->Sacl); } if (src->Control & SE_DACL_PRESENT) { length = src->Dacl->AclSize; dst->Dacl = RtlAllocateHeap(GetProcessHeap(), 0, length); copy_acl(length, dst->Dacl, src->Dacl); } } return STATUS_SUCCESS; } /************************************************************************** * RtlValidSecurityDescriptor [NTDLL.@] * * Determine if a SECURITY_DESCRIPTOR is valid. * * PARAMS * SecurityDescriptor [I] Descriptor to check. * * RETURNS * Success: STATUS_SUCCESS. * Failure: STATUS_INVALID_SECURITY_DESCR or STATUS_UNKNOWN_REVISION. */ NTSTATUS WINAPI RtlValidSecurityDescriptor( PSECURITY_DESCRIPTOR SecurityDescriptor) { if ( ! SecurityDescriptor ) return STATUS_INVALID_SECURITY_DESCR; if ( ((SECURITY_DESCRIPTOR*)SecurityDescriptor)->Revision != SECURITY_DESCRIPTOR_REVISION ) return STATUS_UNKNOWN_REVISION; return STATUS_SUCCESS; } /************************************************************************** * RtlLengthSecurityDescriptor [NTDLL.@] */ ULONG WINAPI RtlLengthSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor) { ULONG size; if ( pSecurityDescriptor == NULL ) return 0; if (((SECURITY_DESCRIPTOR *)pSecurityDescriptor)->Control & SE_SELF_RELATIVE) { SECURITY_DESCRIPTOR_RELATIVE *sd = pSecurityDescriptor; size = sizeof(*sd); if (sd->Owner) size += RtlLengthSid((PSID)SELF_RELATIVE_FIELD(sd,Owner)); if (sd->Group) size += RtlLengthSid((PSID)SELF_RELATIVE_FIELD(sd,Group)); if ((sd->Control & SE_SACL_PRESENT) && sd->Sacl) size += ((PACL)SELF_RELATIVE_FIELD(sd,Sacl))->AclSize; if ((sd->Control & SE_DACL_PRESENT) && sd->Dacl) size += ((PACL)SELF_RELATIVE_FIELD(sd,Dacl))->AclSize; } else { SECURITY_DESCRIPTOR *sd = pSecurityDescriptor; size = sizeof(*sd); if (sd->Owner) size += RtlLengthSid( sd->Owner ); if (sd->Group) size += RtlLengthSid( sd->Group ); if ((sd->Control & SE_SACL_PRESENT) && sd->Sacl) size += sd->Sacl->AclSize; if ((sd->Control & SE_DACL_PRESENT) && sd->Dacl) size += sd->Dacl->AclSize; } return size; } /****************************************************************************** * RtlGetDaclSecurityDescriptor [NTDLL.@] * */ NTSTATUS WINAPI RtlGetDaclSecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecurityDescriptor, OUT PBOOLEAN lpbDaclPresent, OUT PACL *pDacl, OUT PBOOLEAN lpbDaclDefaulted) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor; TRACE("(%p,%p,%p,%p)\n", pSecurityDescriptor, lpbDaclPresent, pDacl, lpbDaclDefaulted); if (lpsd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION ; if ( (*lpbDaclPresent = (SE_DACL_PRESENT & lpsd->Control) ? 1 : 0) ) { if ( SE_SELF_RELATIVE & lpsd->Control) *pDacl = (PACL)SELF_RELATIVE_FIELD( lpsd, Dacl ); else *pDacl = lpsd->Dacl; *lpbDaclDefaulted = (( SE_DACL_DEFAULTED & lpsd->Control ) ? 1 : 0); } else { *pDacl = NULL; *lpbDaclDefaulted = 0; } return STATUS_SUCCESS; } /************************************************************************** * RtlSetDaclSecurityDescriptor [NTDLL.@] */ NTSTATUS WINAPI RtlSetDaclSecurityDescriptor ( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOLEAN daclpresent, PACL dacl, BOOLEAN dacldefaulted ) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor; if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; if (lpsd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR; if (!daclpresent) { lpsd->Control &= ~SE_DACL_PRESENT; return STATUS_SUCCESS; } lpsd->Control |= SE_DACL_PRESENT; lpsd->Dacl = dacl; if (dacldefaulted) lpsd->Control |= SE_DACL_DEFAULTED; else lpsd->Control &= ~SE_DACL_DEFAULTED; return STATUS_SUCCESS; } /****************************************************************************** * RtlGetSaclSecurityDescriptor [NTDLL.@] * */ NTSTATUS WINAPI RtlGetSaclSecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecurityDescriptor, OUT PBOOLEAN lpbSaclPresent, OUT PACL *pSacl, OUT PBOOLEAN lpbSaclDefaulted) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor; TRACE("(%p,%p,%p,%p)\n", pSecurityDescriptor, lpbSaclPresent, pSacl, lpbSaclDefaulted); if (lpsd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; if ( (*lpbSaclPresent = (SE_SACL_PRESENT & lpsd->Control) ? 1 : 0) ) { if (SE_SELF_RELATIVE & lpsd->Control) *pSacl = (PACL)SELF_RELATIVE_FIELD( lpsd, Sacl ); else *pSacl = lpsd->Sacl; *lpbSaclDefaulted = (( SE_SACL_DEFAULTED & lpsd->Control ) ? 1 : 0); } return STATUS_SUCCESS; } /************************************************************************** * RtlSetSaclSecurityDescriptor [NTDLL.@] */ NTSTATUS WINAPI RtlSetSaclSecurityDescriptor ( PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOLEAN saclpresent, PACL sacl, BOOLEAN sacldefaulted) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor; if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; if (lpsd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR; if (!saclpresent) { lpsd->Control &= ~SE_SACL_PRESENT; return 0; } lpsd->Control |= SE_SACL_PRESENT; lpsd->Sacl = sacl; if (sacldefaulted) lpsd->Control |= SE_SACL_DEFAULTED; else lpsd->Control &= ~SE_SACL_DEFAULTED; return STATUS_SUCCESS; } /************************************************************************** * RtlGetOwnerSecurityDescriptor [NTDLL.@] */ NTSTATUS WINAPI RtlGetOwnerSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *Owner, PBOOLEAN OwnerDefaulted) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor; if ( !lpsd || !Owner || !OwnerDefaulted ) return STATUS_INVALID_PARAMETER; if ( lpsd->Control & SE_OWNER_DEFAULTED ) *OwnerDefaulted = TRUE; else *OwnerDefaulted = FALSE; if (lpsd->Control & SE_SELF_RELATIVE) { SECURITY_DESCRIPTOR_RELATIVE *sd = pSecurityDescriptor; if (sd->Owner) *Owner = (PSID)SELF_RELATIVE_FIELD( sd, Owner ); else *Owner = NULL; } else *Owner = lpsd->Owner; return STATUS_SUCCESS; } /************************************************************************** * RtlSetOwnerSecurityDescriptor [NTDLL.@] */ NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID owner, BOOLEAN ownerdefaulted) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor; if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; if (lpsd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR; lpsd->Owner = owner; if (ownerdefaulted) lpsd->Control |= SE_OWNER_DEFAULTED; else lpsd->Control &= ~SE_OWNER_DEFAULTED; return STATUS_SUCCESS; } /************************************************************************** * RtlSetGroupSecurityDescriptor [NTDLL.@] */ NTSTATUS WINAPI RtlSetGroupSecurityDescriptor ( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID group, BOOLEAN groupdefaulted) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor; if (lpsd->Revision!=SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; if (lpsd->Control & SE_SELF_RELATIVE) return STATUS_INVALID_SECURITY_DESCR; lpsd->Group = group; if (groupdefaulted) lpsd->Control |= SE_GROUP_DEFAULTED; else lpsd->Control &= ~SE_GROUP_DEFAULTED; return STATUS_SUCCESS; } /************************************************************************** * RtlGetGroupSecurityDescriptor [NTDLL.@] */ NTSTATUS WINAPI RtlGetGroupSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSID *Group, PBOOLEAN GroupDefaulted) { SECURITY_DESCRIPTOR* lpsd=pSecurityDescriptor; if ( !lpsd || !Group || !GroupDefaulted ) return STATUS_INVALID_PARAMETER; if ( lpsd->Control & SE_GROUP_DEFAULTED ) *GroupDefaulted = TRUE; else *GroupDefaulted = FALSE; if (lpsd->Control & SE_SELF_RELATIVE) { SECURITY_DESCRIPTOR_RELATIVE *sd = pSecurityDescriptor; if (sd->Group) *Group = (PSID)SELF_RELATIVE_FIELD( sd, Group ); else *Group = NULL; } else *Group = lpsd->Group; return STATUS_SUCCESS; } /************************************************************************** * RtlMakeSelfRelativeSD [NTDLL.@] */ NTSTATUS WINAPI RtlMakeSelfRelativeSD( IN PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, IN PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, IN OUT LPDWORD lpdwBufferLength) { DWORD offsetRel; ULONG length; SECURITY_DESCRIPTOR* pAbs = pAbsoluteSecurityDescriptor; SECURITY_DESCRIPTOR_RELATIVE *pRel = pSelfRelativeSecurityDescriptor; TRACE(" %p %p %p(%d)\n", pAbs, pRel, lpdwBufferLength, lpdwBufferLength ? *lpdwBufferLength: -1); if (!lpdwBufferLength || !pAbs) return STATUS_INVALID_PARAMETER; length = RtlLengthSecurityDescriptor(pAbs); if (*lpdwBufferLength < length) { *lpdwBufferLength = length; return STATUS_BUFFER_TOO_SMALL; } if (!pRel) return STATUS_INVALID_PARAMETER; if (pAbs->Control & SE_SELF_RELATIVE) { memcpy(pRel, pAbs, length); return STATUS_SUCCESS; } pRel->Revision = pAbs->Revision; pRel->Sbz1 = pAbs->Sbz1; pRel->Control = pAbs->Control | SE_SELF_RELATIVE; offsetRel = sizeof(SECURITY_DESCRIPTOR_RELATIVE); if (pAbs->Owner) { pRel->Owner = offsetRel; length = RtlLengthSid(pAbs->Owner); memcpy((LPBYTE)pRel + offsetRel, pAbs->Owner, length); offsetRel += length; } else { pRel->Owner = 0; } if (pAbs->Group) { pRel->Group = offsetRel; length = RtlLengthSid(pAbs->Group); memcpy((LPBYTE)pRel + offsetRel, pAbs->Group, length); offsetRel += length; } else { pRel->Group = 0; } if (pAbs->Sacl) { pRel->Sacl = offsetRel; length = pAbs->Sacl->AclSize; memcpy((LPBYTE)pRel + offsetRel, pAbs->Sacl, length); offsetRel += length; } else { pRel->Sacl = 0; } if (pAbs->Dacl) { pRel->Dacl = offsetRel; length = pAbs->Dacl->AclSize; memcpy((LPBYTE)pRel + offsetRel, pAbs->Dacl, length); } else { pRel->Dacl = 0; } return STATUS_SUCCESS; } /************************************************************************** * RtlSelfRelativeToAbsoluteSD [NTDLL.@] */ NTSTATUS WINAPI RtlSelfRelativeToAbsoluteSD( IN PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor, OUT PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor, OUT LPDWORD lpdwAbsoluteSecurityDescriptorSize, OUT PACL pDacl, OUT LPDWORD lpdwDaclSize, OUT PACL pSacl, OUT LPDWORD lpdwSaclSize, OUT PSID pOwner, OUT LPDWORD lpdwOwnerSize, OUT PSID pPrimaryGroup, OUT LPDWORD lpdwPrimaryGroupSize) { NTSTATUS status = STATUS_SUCCESS; SECURITY_DESCRIPTOR* pAbs = pAbsoluteSecurityDescriptor; SECURITY_DESCRIPTOR_RELATIVE* pRel = pSelfRelativeSecurityDescriptor; if (!pRel || !lpdwAbsoluteSecurityDescriptorSize || !lpdwDaclSize || !lpdwSaclSize || !lpdwOwnerSize || !lpdwPrimaryGroupSize || ~pRel->Control & SE_SELF_RELATIVE) return STATUS_INVALID_PARAMETER; /* Confirm buffers are sufficiently large */ if (*lpdwAbsoluteSecurityDescriptorSize < sizeof(SECURITY_DESCRIPTOR)) { *lpdwAbsoluteSecurityDescriptorSize = sizeof(SECURITY_DESCRIPTOR); status = STATUS_BUFFER_TOO_SMALL; } if (pRel->Control & SE_DACL_PRESENT && *lpdwDaclSize < ((PACL)SELF_RELATIVE_FIELD(pRel,Dacl))->AclSize) { *lpdwDaclSize = ((PACL)SELF_RELATIVE_FIELD(pRel,Dacl))->AclSize; status = STATUS_BUFFER_TOO_SMALL; } if (pRel->Control & SE_SACL_PRESENT && *lpdwSaclSize < ((PACL)SELF_RELATIVE_FIELD(pRel,Sacl))->AclSize) { *lpdwSaclSize = ((PACL)SELF_RELATIVE_FIELD(pRel,Sacl))->AclSize; status = STATUS_BUFFER_TOO_SMALL; } if (pRel->Owner && *lpdwOwnerSize < RtlLengthSid((PSID)SELF_RELATIVE_FIELD(pRel,Owner))) { *lpdwOwnerSize = RtlLengthSid((PSID)SELF_RELATIVE_FIELD(pRel,Owner)); status = STATUS_BUFFER_TOO_SMALL; } if (pRel->Group && *lpdwPrimaryGroupSize < RtlLengthSid((PSID)SELF_RELATIVE_FIELD(pRel,Group))) { *lpdwPrimaryGroupSize = RtlLengthSid((PSID)SELF_RELATIVE_FIELD(pRel,Group)); status = STATUS_BUFFER_TOO_SMALL; } if (status != STATUS_SUCCESS) return status; /* Copy structures, and clear the ones we don't set */ pAbs->Revision = pRel->Revision; pAbs->Control = pRel->Control & ~SE_SELF_RELATIVE; pAbs->Sacl = NULL; pAbs->Dacl = NULL; pAbs->Owner = NULL; pAbs->Group = NULL; if (pRel->Control & SE_SACL_PRESENT) { PACL pAcl = (PACL)SELF_RELATIVE_FIELD( pRel, Sacl ); memcpy(pSacl, pAcl, pAcl->AclSize); pAbs->Sacl = pSacl; } if (pRel->Control & SE_DACL_PRESENT) { PACL pAcl = (PACL)SELF_RELATIVE_FIELD( pRel, Dacl ); memcpy(pDacl, pAcl, pAcl->AclSize); pAbs->Dacl = pDacl; } if (pRel->Owner) { PSID psid = (PSID)SELF_RELATIVE_FIELD( pRel, Owner ); memcpy(pOwner, psid, RtlLengthSid(psid)); pAbs->Owner = pOwner; } if (pRel->Group) { PSID psid = (PSID)SELF_RELATIVE_FIELD( pRel, Group ); memcpy(pPrimaryGroup, psid, RtlLengthSid(psid)); pAbs->Group = pPrimaryGroup; } return status; } /****************************************************************************** * RtlGetControlSecurityDescriptor (NTDLL.@) */ NTSTATUS WINAPI RtlGetControlSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, PSECURITY_DESCRIPTOR_CONTROL pControl, LPDWORD lpdwRevision) { SECURITY_DESCRIPTOR *lpsd = pSecurityDescriptor; TRACE("(%p,%p,%p)\n",pSecurityDescriptor,pControl,lpdwRevision); *lpdwRevision = lpsd->Revision; if (*lpdwRevision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION; *pControl = lpsd->Control; return STATUS_SUCCESS; } /****************************************************************************** * RtlSetControlSecurityDescriptor (NTDLL.@) */ NTSTATUS WINAPI RtlSetControlSecurityDescriptor( PSECURITY_DESCRIPTOR SecurityDescriptor, SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet) { SECURITY_DESCRIPTOR_CONTROL const immutable = SE_OWNER_DEFAULTED | SE_GROUP_DEFAULTED | SE_DACL_PRESENT | SE_DACL_DEFAULTED | SE_SACL_PRESENT | SE_SACL_DEFAULTED | SE_RM_CONTROL_VALID | SE_SELF_RELATIVE ; SECURITY_DESCRIPTOR *lpsd = SecurityDescriptor; TRACE("(%p 0x%04x 0x%04x)\n", SecurityDescriptor, ControlBitsOfInterest, ControlBitsToSet); if ((ControlBitsOfInterest | ControlBitsToSet) & immutable) return STATUS_INVALID_PARAMETER; lpsd->Control |= (ControlBitsOfInterest & ControlBitsToSet); lpsd->Control &= ~(ControlBitsOfInterest & ~ControlBitsToSet); return STATUS_SUCCESS; } /************************************************************************** * RtlAbsoluteToSelfRelativeSD [NTDLL.@] */ NTSTATUS WINAPI RtlAbsoluteToSelfRelativeSD( PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, PULONG BufferLength) { SECURITY_DESCRIPTOR *abs = AbsoluteSecurityDescriptor; TRACE("%p %p %p\n", AbsoluteSecurityDescriptor, SelfRelativeSecurityDescriptor, BufferLength); if (abs->Control & SE_SELF_RELATIVE) return STATUS_BAD_DESCRIPTOR_FORMAT; return RtlMakeSelfRelativeSD(AbsoluteSecurityDescriptor, SelfRelativeSecurityDescriptor, BufferLength); } /* * access control list's */ /************************************************************************** * RtlCreateAcl [NTDLL.@] * * NOTES * This should return NTSTATUS */ NTSTATUS WINAPI RtlCreateAcl(PACL acl,DWORD size,DWORD rev) { TRACE("%p 0x%08x 0x%08x\n", acl, size, rev); if (rev < MIN_ACL_REVISION || rev > MAX_ACL_REVISION) return STATUS_INVALID_PARAMETER; if (size<sizeof(ACL)) return STATUS_BUFFER_TOO_SMALL; if (size>0xFFFF) return STATUS_INVALID_PARAMETER; memset(acl,'\0',sizeof(ACL)); acl->AclRevision = rev; acl->AclSize = size; acl->AceCount = 0; return STATUS_SUCCESS; } /************************************************************************** * RtlFirstFreeAce [NTDLL.@] * looks for the AceCount+1 ACE, and if it is still within the alloced * ACL, return a pointer to it */ BOOLEAN WINAPI RtlFirstFreeAce( PACL acl, PACE_HEADER *x) { PACE_HEADER ace; int i; *x = 0; ace = (PACE_HEADER)(acl+1); for (i=0;i<acl->AceCount;i++) { if ((BYTE *)ace >= (BYTE *)acl + acl->AclSize) return 0; ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize); } if ((BYTE *)ace >= (BYTE *)acl + acl->AclSize) return 0; *x = ace; return 1; } /************************************************************************** * RtlAddAce [NTDLL.@] */ NTSTATUS WINAPI RtlAddAce( PACL acl, DWORD rev, DWORD xnrofaces, PACE_HEADER acestart, DWORD acelen) { PACE_HEADER ace,targetace; int nrofaces; if (acl->AclRevision != ACL_REVISION) return STATUS_INVALID_PARAMETER; if (!RtlFirstFreeAce(acl,&targetace)) return STATUS_INVALID_PARAMETER; nrofaces=0;ace=acestart; while (((BYTE *)ace - (BYTE *)acestart) < acelen) { nrofaces++; ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize); } if ((BYTE *)targetace + acelen > (BYTE *)acl + acl->AclSize) /* too much aces */ return STATUS_INVALID_PARAMETER; memcpy(targetace,acestart,acelen); acl->AceCount+=nrofaces; return STATUS_SUCCESS; } /************************************************************************** * RtlDeleteAce [NTDLL.@] */ NTSTATUS WINAPI RtlDeleteAce(PACL pAcl, DWORD dwAceIndex) { NTSTATUS status; PACE_HEADER pAce; status = RtlGetAce(pAcl,dwAceIndex,(LPVOID*)&pAce); if (STATUS_SUCCESS == status) { PACE_HEADER pcAce; DWORD len = 0; /* skip over the ACE we are deleting */ pcAce = (PACE_HEADER)(((BYTE*)pAce)+pAce->AceSize); dwAceIndex++; /* calculate the length of the rest */ for (; dwAceIndex < pAcl->AceCount; dwAceIndex++) { len += pcAce->AceSize; pcAce = (PACE_HEADER)(((BYTE*)pcAce) + pcAce->AceSize); } /* slide them all backwards */ memmove(pAce, ((BYTE*)pAce)+pAce->AceSize, len); pAcl->AceCount--; } TRACE("pAcl=%p dwAceIndex=%d status=0x%08x\n", pAcl, dwAceIndex, status); return status; } /****************************************************************************** * RtlAddAccessAllowedAce [NTDLL.@] */ NTSTATUS WINAPI RtlAddAccessAllowedAce( IN OUT PACL pAcl, IN DWORD dwAceRevision, IN DWORD AccessMask, IN PSID pSid) { return RtlAddAccessAllowedAceEx( pAcl, dwAceRevision, 0, AccessMask, pSid); } /****************************************************************************** * RtlAddAccessAllowedAceEx [NTDLL.@] */ NTSTATUS WINAPI RtlAddAccessAllowedAceEx( IN OUT PACL pAcl, IN DWORD dwAceRevision, IN DWORD AceFlags, IN DWORD AccessMask, IN PSID pSid) { TRACE("(%p,0x%08x,0x%08x,%p)\n", pAcl, dwAceRevision, AccessMask, pSid); return add_access_ace(pAcl, dwAceRevision, AceFlags, AccessMask, pSid, ACCESS_ALLOWED_ACE_TYPE); } /****************************************************************************** * RtlAddAccessDeniedAce [NTDLL.@] */ NTSTATUS WINAPI RtlAddAccessDeniedAce( IN OUT PACL pAcl, IN DWORD dwAceRevision, IN DWORD AccessMask, IN PSID pSid) { return RtlAddAccessDeniedAceEx( pAcl, dwAceRevision, 0, AccessMask, pSid); } /****************************************************************************** * RtlAddAccessDeniedAceEx [NTDLL.@] */ NTSTATUS WINAPI RtlAddAccessDeniedAceEx( IN OUT PACL pAcl, IN DWORD dwAceRevision, IN DWORD AceFlags, IN DWORD AccessMask, IN PSID pSid) { TRACE("(%p,0x%08x,0x%08x,%p)\n", pAcl, dwAceRevision, AccessMask, pSid); return add_access_ace(pAcl, dwAceRevision, AceFlags, AccessMask, pSid, ACCESS_DENIED_ACE_TYPE); } /************************************************************************** * RtlAddAuditAccessAce [NTDLL.@] */ NTSTATUS WINAPI RtlAddAuditAccessAceEx( IN OUT PACL pAcl, IN DWORD dwAceRevision, IN DWORD dwAceFlags, IN DWORD dwAccessMask, IN PSID pSid, IN BOOL bAuditSuccess, IN BOOL bAuditFailure) { TRACE("(%p,%d,0x%08x,0x%08x,%p,%u,%u)\n",pAcl,dwAceRevision,dwAceFlags,dwAccessMask, pSid,bAuditSuccess,bAuditFailure); if (bAuditSuccess) dwAceFlags |= SUCCESSFUL_ACCESS_ACE_FLAG; if (bAuditFailure) dwAceFlags |= FAILED_ACCESS_ACE_FLAG; return add_access_ace(pAcl, dwAceRevision, dwAceFlags, dwAccessMask, pSid, SYSTEM_AUDIT_ACE_TYPE); } /************************************************************************** * RtlAddAuditAccessAce [NTDLL.@] */ NTSTATUS WINAPI RtlAddAuditAccessAce( IN OUT PACL pAcl, IN DWORD dwAceRevision, IN DWORD dwAccessMask, IN PSID pSid, IN BOOL bAuditSuccess, IN BOOL bAuditFailure) { return RtlAddAuditAccessAceEx(pAcl, dwAceRevision, 0, dwAccessMask, pSid, bAuditSuccess, bAuditFailure); } /****************************************************************************** * RtlValidAcl [NTDLL.@] */ BOOLEAN WINAPI RtlValidAcl(PACL pAcl) { BOOLEAN ret; TRACE("(%p)\n", pAcl); __TRY { PACE_HEADER ace; int i; if (pAcl->AclRevision < MIN_ACL_REVISION || pAcl->AclRevision > MAX_ACL_REVISION) ret = FALSE; else { ace = (PACE_HEADER)(pAcl+1); ret = TRUE; for (i=0;i<=pAcl->AceCount;i++) { if ((char *)ace > (char *)pAcl + pAcl->AclSize) { ret = FALSE; break; } ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize); } } } __EXCEPT_PAGE_FAULT { WARN("(%p): invalid pointer!\n", pAcl); return 0; } __ENDTRY return ret; } /****************************************************************************** * RtlGetAce [NTDLL.@] */ NTSTATUS WINAPI RtlGetAce(PACL pAcl,DWORD dwAceIndex,LPVOID *pAce ) { PACE_HEADER ace; TRACE("(%p,%d,%p)\n",pAcl,dwAceIndex,pAce); if (dwAceIndex >= pAcl->AceCount) return STATUS_INVALID_PARAMETER; ace = (PACE_HEADER)(pAcl + 1); for (;dwAceIndex;dwAceIndex--) ace = (PACE_HEADER)(((BYTE*)ace)+ace->AceSize); *pAce = ace; return STATUS_SUCCESS; } /* * misc */ /****************************************************************************** * RtlAdjustPrivilege [NTDLL.@] * * Enables or disables a privilege from the calling thread or process. * * PARAMS * Privilege [I] Privilege index to change. * Enable [I] If TRUE, then enable the privilege otherwise disable. * CurrentThread [I] If TRUE, then enable in calling thread, otherwise process. * Enabled [O] Whether privilege was previously enabled or disabled. * * RETURNS * Success: STATUS_SUCCESS. * Failure: NTSTATUS code. * * SEE ALSO * NtAdjustPrivilegesToken, NtOpenThreadToken, NtOpenProcessToken. * */ NTSTATUS WINAPI RtlAdjustPrivilege(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN Enabled) { TOKEN_PRIVILEGES NewState; TOKEN_PRIVILEGES OldState; ULONG ReturnLength; HANDLE TokenHandle; NTSTATUS Status; TRACE("(%d, %s, %s, %p)\n", Privilege, Enable ? "TRUE" : "FALSE", CurrentThread ? "TRUE" : "FALSE", Enabled); if (CurrentThread) { Status = NtOpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &TokenHandle); } else { Status = NtOpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle); } if (!NT_SUCCESS(Status)) { WARN("Retrieving token handle failed (Status %x)\n", Status); return Status; } OldState.PrivilegeCount = 1; NewState.PrivilegeCount = 1; NewState.Privileges[0].Luid.LowPart = Privilege; NewState.Privileges[0].Luid.HighPart = 0; NewState.Privileges[0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0; Status = NtAdjustPrivilegesToken(TokenHandle, FALSE, &NewState, sizeof(TOKEN_PRIVILEGES), &OldState, &ReturnLength); NtClose (TokenHandle); if (Status == STATUS_NOT_ALL_ASSIGNED) { TRACE("Failed to assign all privileges\n"); return STATUS_PRIVILEGE_NOT_HELD; } if (!NT_SUCCESS(Status)) { WARN("NtAdjustPrivilegesToken() failed (Status %x)\n", Status); return Status; } if (OldState.PrivilegeCount == 0) *Enabled = Enable; else *Enabled = (OldState.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED); return STATUS_SUCCESS; } /****************************************************************************** * RtlImpersonateSelf [NTDLL.@] * * Makes an impersonation token that represents the process user and assigns * to the current thread. * * PARAMS * ImpersonationLevel [I] Level at which to impersonate. * * RETURNS * Success: STATUS_SUCCESS. * Failure: NTSTATUS code. */ NTSTATUS WINAPI RtlImpersonateSelf(SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE ProcessToken; HANDLE ImpersonationToken; TRACE("(%08x)\n", ImpersonationLevel); Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken); if (Status != STATUS_SUCCESS) return Status; InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); Status = NtDuplicateToken( ProcessToken, TOKEN_IMPERSONATE, &ObjectAttributes, ImpersonationLevel, TokenImpersonation, &ImpersonationToken ); if (Status != STATUS_SUCCESS) { NtClose( ProcessToken ); return Status; } Status = NtSetInformationThread( GetCurrentThread(), ThreadImpersonationToken, &ImpersonationToken, sizeof(ImpersonationToken) ); NtClose( ImpersonationToken ); NtClose( ProcessToken ); return Status; } /****************************************************************************** * NtAccessCheck [NTDLL.@] * ZwAccessCheck [NTDLL.@] * * Checks that a user represented by a token is allowed to access an object * represented by a security descriptor. * * PARAMS * SecurityDescriptor [I] The security descriptor of the object to check. * ClientToken [I] Token of the user accessing the object. * DesiredAccess [I] The desired access to the object. * GenericMapping [I] Mapping used to transform access rights in the SD to their specific forms. * PrivilegeSet [I/O] Privileges used during the access check. * ReturnLength [O] Number of bytes stored into PrivilegeSet. * GrantedAccess [O] The actual access rights granted. * AccessStatus [O] The status of the access check. * * RETURNS * NTSTATUS code. * * NOTES * DesiredAccess may be MAXIMUM_ALLOWED, in which case the function determines * the maximum access rights allowed by the SD and returns them in * GrantedAccess. * The SecurityDescriptor must have a valid owner and groups present, * otherwise the function will fail. */ NTSTATUS WINAPI NtAccessCheck( PSECURITY_DESCRIPTOR SecurityDescriptor, HANDLE ClientToken, ACCESS_MASK DesiredAccess, PGENERIC_MAPPING GenericMapping, PPRIVILEGE_SET PrivilegeSet, PULONG ReturnLength, PULONG GrantedAccess, NTSTATUS *AccessStatus) { NTSTATUS status; TRACE("(%p, %p, %08x, %p, %p, %p, %p, %p)\n", SecurityDescriptor, ClientToken, DesiredAccess, GenericMapping, PrivilegeSet, ReturnLength, GrantedAccess, AccessStatus); if (!PrivilegeSet || !ReturnLength) return STATUS_ACCESS_VIOLATION; SERVER_START_REQ( access_check ) { struct security_descriptor sd; PSID owner; PSID group; PACL sacl; PACL dacl; BOOLEAN defaulted, present; DWORD revision; SECURITY_DESCRIPTOR_CONTROL control; req->handle = wine_server_obj_handle( ClientToken ); req->desired_access = DesiredAccess; req->mapping_read = GenericMapping->GenericRead; req->mapping_write = GenericMapping->GenericWrite; req->mapping_execute = GenericMapping->GenericExecute; req->mapping_all = GenericMapping->GenericAll; /* marshal security descriptor */ RtlGetControlSecurityDescriptor( SecurityDescriptor, &control, &revision ); sd.control = control & ~SE_SELF_RELATIVE; RtlGetOwnerSecurityDescriptor( SecurityDescriptor, &owner, &defaulted ); sd.owner_len = RtlLengthSid( owner ); RtlGetGroupSecurityDescriptor( SecurityDescriptor, &group, &defaulted ); sd.group_len = RtlLengthSid( group ); RtlGetSaclSecurityDescriptor( SecurityDescriptor, &present, &sacl, &defaulted ); sd.sacl_len = ((present && sacl) ? acl_bytesInUse(sacl) : 0); RtlGetDaclSecurityDescriptor( SecurityDescriptor, &present, &dacl, &defaulted ); sd.dacl_len = ((present && dacl) ? acl_bytesInUse(dacl) : 0); wine_server_add_data( req, &sd, sizeof(sd) ); wine_server_add_data( req, owner, sd.owner_len ); wine_server_add_data( req, group, sd.group_len ); wine_server_add_data( req, sacl, sd.sacl_len ); wine_server_add_data( req, dacl, sd.dacl_len ); wine_server_set_reply( req, PrivilegeSet->Privilege, *ReturnLength - FIELD_OFFSET( PRIVILEGE_SET, Privilege ) ); status = wine_server_call( req ); *ReturnLength = FIELD_OFFSET( PRIVILEGE_SET, Privilege ) + reply->privileges_len; PrivilegeSet->PrivilegeCount = reply->privileges_len / sizeof(LUID_AND_ATTRIBUTES); if (status == STATUS_SUCCESS) { *AccessStatus = reply->access_status; *GrantedAccess = reply->access_granted; } } SERVER_END_REQ; return status; } /****************************************************************************** * NtSetSecurityObject [NTDLL.@] * ZwSetSecurityObject [NTDLL.@] * * Sets specified parts of the object's security descriptor. * * PARAMS * Handle [I] Handle to the object to change security descriptor of. * SecurityInformation [I] Specifies which parts of the security descriptor to set. * SecurityDescriptor [I] New parts of a security descriptor for the object. * * RETURNS * NTSTATUS code. * */ NTSTATUS WINAPI NtSetSecurityObject(HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor) { NTSTATUS status; struct security_descriptor sd; PACL dacl = NULL, sacl = NULL; PSID owner = NULL, group = NULL; BOOLEAN defaulted, present; DWORD revision; SECURITY_DESCRIPTOR_CONTROL control; TRACE("%p 0x%08x %p\n", Handle, SecurityInformation, SecurityDescriptor); if (!SecurityDescriptor) return STATUS_ACCESS_VIOLATION; memset( &sd, 0, sizeof(sd) ); status = RtlGetControlSecurityDescriptor( SecurityDescriptor, &control, &revision ); if (status != STATUS_SUCCESS) return status; sd.control = control & ~SE_SELF_RELATIVE; if (SecurityInformation & OWNER_SECURITY_INFORMATION) { status = RtlGetOwnerSecurityDescriptor( SecurityDescriptor, &owner, &defaulted ); if (status != STATUS_SUCCESS) return status; if (!(sd.owner_len = RtlLengthSid( owner ))) return STATUS_INVALID_SECURITY_DESCR; } if (SecurityInformation & GROUP_SECURITY_INFORMATION) { status = RtlGetGroupSecurityDescriptor( SecurityDescriptor, &group, &defaulted ); if (status != STATUS_SUCCESS) return status; if (!(sd.group_len = RtlLengthSid( group ))) return STATUS_INVALID_SECURITY_DESCR; } if (SecurityInformation & SACL_SECURITY_INFORMATION) { status = RtlGetSaclSecurityDescriptor( SecurityDescriptor, &present, &sacl, &defaulted ); if (status != STATUS_SUCCESS) return status; sd.sacl_len = (sacl && present) ? acl_bytesInUse(sacl) : 0; sd.control |= SE_SACL_PRESENT; } if (SecurityInformation & DACL_SECURITY_INFORMATION) { status = RtlGetDaclSecurityDescriptor( SecurityDescriptor, &present, &dacl, &defaulted ); if (status != STATUS_SUCCESS) return status; sd.dacl_len = (dacl && present) ? acl_bytesInUse(dacl) : 0; sd.control |= SE_DACL_PRESENT; } SERVER_START_REQ( set_security_object ) { req->handle = wine_server_obj_handle( Handle ); req->security_info = SecurityInformation; wine_server_add_data( req, &sd, sizeof(sd) ); wine_server_add_data( req, owner, sd.owner_len ); wine_server_add_data( req, group, sd.group_len ); wine_server_add_data( req, sacl, sd.sacl_len ); wine_server_add_data( req, dacl, sd.dacl_len ); status = wine_server_call( req ); } SERVER_END_REQ; return status; } /****************************************************************************** * RtlConvertSidToUnicodeString (NTDLL.@) * * The returned SID is used to access the USER registry hive usually * * the native function returns something like * "S-1-5-21-0000000000-000000000-0000000000-500"; */ NTSTATUS WINAPI RtlConvertSidToUnicodeString( PUNICODE_STRING String, PSID pSid, BOOLEAN AllocateString) { static const WCHAR formatW[] = {'-','%','u',0}; WCHAR buffer[2 + 10 + 10 + 10 * SID_MAX_SUB_AUTHORITIES]; WCHAR *p = buffer; const SID *sid = pSid; DWORD i, len; *p++ = 'S'; p += sprintfW( p, formatW, sid->Revision ); p += sprintfW( p, formatW, MAKELONG( MAKEWORD( sid->IdentifierAuthority.Value[5], sid->IdentifierAuthority.Value[4] ), MAKEWORD( sid->IdentifierAuthority.Value[3], sid->IdentifierAuthority.Value[2] ))); for (i = 0; i < sid->SubAuthorityCount; i++) p += sprintfW( p, formatW, sid->SubAuthority[i] ); len = (p + 1 - buffer) * sizeof(WCHAR); String->Length = len - sizeof(WCHAR); if (AllocateString) { String->MaximumLength = len; if (!(String->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY; } else if (len > String->MaximumLength) return STATUS_BUFFER_OVERFLOW; memcpy( String->Buffer, buffer, len ); return STATUS_SUCCESS; } /****************************************************************************** * RtlQueryInformationAcl (NTDLL.@) */ NTSTATUS WINAPI RtlQueryInformationAcl( PACL pAcl, LPVOID pAclInformation, DWORD nAclInformationLength, ACL_INFORMATION_CLASS dwAclInformationClass) { NTSTATUS status = STATUS_SUCCESS; TRACE("pAcl=%p pAclInfo=%p len=%d, class=%d\n", pAcl, pAclInformation, nAclInformationLength, dwAclInformationClass); switch (dwAclInformationClass) { case AclRevisionInformation: { PACL_REVISION_INFORMATION paclrev = pAclInformation; if (nAclInformationLength < sizeof(ACL_REVISION_INFORMATION)) status = STATUS_INVALID_PARAMETER; else paclrev->AclRevision = pAcl->AclRevision; break; } case AclSizeInformation: { PACL_SIZE_INFORMATION paclsize = pAclInformation; if (nAclInformationLength < sizeof(ACL_SIZE_INFORMATION)) status = STATUS_INVALID_PARAMETER; else { paclsize->AceCount = pAcl->AceCount; paclsize->AclBytesInUse = acl_bytesInUse(pAcl); if (pAcl->AclSize < paclsize->AclBytesInUse) { WARN("Acl uses %d bytes, but only has %d allocated! Returning smaller of the two values.\n", pAcl->AclSize, paclsize->AclBytesInUse); paclsize->AclBytesFree = 0; paclsize->AclBytesInUse = pAcl->AclSize; } else paclsize->AclBytesFree = pAcl->AclSize - paclsize->AclBytesInUse; } break; } default: WARN("Unknown AclInformationClass value: %d\n", dwAclInformationClass); status = STATUS_INVALID_PARAMETER; } return status; }