Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

523 lines
11 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
Acledit.c
Abstract:
This Module implements the Acl rtl editing functions that are defined in
ntseapi.h
Author:
Gary Kimura (GaryKi) 9-Nov-1989
Environment:
Pure Runtime Library Routine
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include "seopaque.h"
//
// Define the local macros and procedure for this module
//
//
// Return a pointer to the first Ace in an Acl (even if the Acl is empty).
//
// PACE_HEADER
// FirstAce (
// IN PACL Acl
// );
//
#define FirstAce(Acl) ((PVOID)((PUCHAR)(Acl) + sizeof(ACL)))
VOID
AddData (
IN PVOID From,
IN ULONG FromSize,
IN PVOID To,
IN ULONG ToSize
);
VOID
DeleteData (
IN PVOID Data,
IN ULONG RemoveSize,
IN ULONG TotalSize
);
NTSTATUS
RtlMakePosixAcl(
IN ULONG AclRevision,
IN PSID UserSid,
IN PSID GroupSid,
IN ACCESS_MASK UserAccess,
IN ACCESS_MASK GroupAccess,
IN ACCESS_MASK OtherAccess,
IN ULONG AclLength,
OUT PACL Acl,
OUT PULONG ReturnLength
)
/*++
Routine Description:
NOTE: THIS ROUTINE IS STILL BEING SPEC'D.
Make an ACL representing Posix protection from AccessMask and
security account ID (SID) information.
Arguments:
AclRevision - Indicates the ACL revision level of the access masks
provided. The ACL generated will be revision compatible with this
value and will not be a higher revision than this value.
UserSid - Provides the SID of the user (owner).
GroupSid - Provides the SID of the primary group.
UserAccess - Specifies the accesses to be given to the user (owner).
GroupAccess - Specifies the accesses to be given to the primary group.
OtherAccess - Specifies the accesses to be given to others (WORLD).
AclLength - Provides the length (in bytes) of the Acl buffer.
Acl - Points to a buffer to receive the generated ACL.
ReturnLength - Returns the actual length needed to store the resultant
ACL. If this length is greater than that specified in AclLength,
then STATUS_BUFFER_TOO_SMALL is returned and no ACL is generated.
Return Values:
STATUS_SUCCESS - The service completed successfully.
STATUS_UNKNOWN_REVISION - The revision level specified is not supported
by this service.
STATUS_BUFFER_TOO_SMALL - Indicates the length of the output buffer
wasn't large enough to hold the generated ACL. The length needed
is returned via the ReturnLength parameter.
--*/
{
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
ULONG UserSidLength;
ULONG GroupSidLength;
ULONG WorldSidLength;
ULONG RequiredAclSize;
ULONG AceSize;
ULONG CurrentAce;
PACCESS_ALLOWED_ACE Ace;
NTSTATUS Status;
PSID WorldSid;
if (!RtlValidSid( UserSid ) || !RtlValidSid( GroupSid )) {
return( STATUS_INVALID_SID );
}
UserSidLength = RtlLengthSid( UserSid );
GroupSidLength = RtlLengthSid( GroupSid );
WorldSidLength = RtlLengthRequiredSid( 1 );
//
// Figure out how much room we need for an ACL and three
// ACCESS_ALLOWED Ace's
//
RequiredAclSize = sizeof( ACL );
AceSize = sizeof( ACCESS_ALLOWED_ACE ) - sizeof( ULONG );
RequiredAclSize += (AceSize * 3) +
UserSidLength +
GroupSidLength +
WorldSidLength ;
if (RequiredAclSize > AclLength) {
*ReturnLength = RequiredAclSize;
return( STATUS_BUFFER_TOO_SMALL );
}
//
// The passed buffer is big enough, build the ACL in it.
//
Status = RtlCreateAcl(
Acl,
RequiredAclSize,
AclRevision
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
Status = RtlAddAccessAllowedAce(
Acl,
ACL_REVISION2,
UserAccess,
UserSid
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
Status = RtlAddAccessAllowedAce(
Acl,
ACL_REVISION2,
GroupAccess,
GroupSid
);
if (!NT_SUCCESS( Status )) {
return( Status );
}
Status = RtlAllocateAndInitializeSid(&WorldSidAuthority, 1,
SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &WorldSid);
if (!NT_SUCCESS( Status )) {
return( Status );
}
Status = RtlAddAccessAllowedAce(
Acl,
ACL_REVISION2,
OtherAccess,
WorldSid
);
RtlFreeSid(WorldSid);
if (!NT_SUCCESS( Status )) {
return( Status );
}
return( STATUS_SUCCESS );
}
NTSTATUS
RtlInterpretPosixAcl(
IN ULONG AclRevision,
IN PSID UserSid,
IN PSID GroupSid,
IN PACL Acl,
OUT PACCESS_MASK UserAccess,
OUT PACCESS_MASK GroupAccess,
OUT PACCESS_MASK OtherAccess
)
/*++
Routine Description:
NOTE: THIS ROUTINE IS STILL BEING SPEC'D.
Interpret an ACL representing Posix protection, returning AccessMasks.
Use security account IDs (SIDs) for object owner and primary group
identification.
This algorithm will pick up the first match of a given SID and ignore
all further matches of that SID. The first unrecognized SID becomes
the "other" SID.
Arguments:
AclRevision - Indicates the ACL revision level of the access masks to
be returned.
UserSid - Provides the SID of the user (owner).
GroupSid - Provides the SID of the primary group.
Acl - Points to a buffer containing the ACL to interpret.
UserAccess - Receives the accesses allowed for the user (owner).
GroupAccess - Receives the accesses allowed for the primary group.
OtherAccess - Receives the accesses allowed for others (WORLD).
Return Values:
STATUS_SUCCESS - The service completed successfully.
STATUS_UNKNOWN_REVISION - The revision level specified is not supported
by this service.
STATUS_EXTRENEOUS_INFORMATION - This warning status value indicates the
ACL contained protection or other information unrelated to Posix
style protection. This is a warning only. The interpretation was
otherwise successful and all access masks were returned.
STATUS_COULD_NOT_INTERPRET - Indicates the ACL does not contain
sufficient Posix style (user/group) protection information. The
ACL could not be interpreted.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN UserFound = FALSE;
BOOLEAN GroupFound = FALSE;
BOOLEAN OtherFound = FALSE;
ULONG i;
PKNOWN_ACE Ace;
*UserAccess = *GroupAccess = *OtherAccess = 0;
if (AclRevision != ACL_REVISION2) {
return( STATUS_UNKNOWN_REVISION );
}
//
// Special case for ACLs that are just "Everyone: Full Control".
//
if (Acl->AceCount < 3) {
SID_IDENTIFIER_AUTHORITY WorldSidAuth = SECURITY_WORLD_SID_AUTHORITY;
PSID WorldSid;
Status = RtlAllocateAndInitializeSid(&WorldSidAuth, 1,
SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &WorldSid);
if (!NT_SUCCESS( Status )) {
return( Status );
}
Status = RtlGetAce(Acl, 0, (PVOID *)&Ace);
if (!NT_SUCCESS(Status)) {
RtlFreeSid(WorldSid);
return Status;
}
if (RtlEqualSid((PSID)&Ace->SidStart, WorldSid)) {
*UserAccess = *GroupAccess = *OtherAccess = Ace->Mask;
RtlFreeSid(WorldSid);
return STATUS_SUCCESS;
}
RtlFreeSid(WorldSid);
}
for (i = 0; i < Acl->AceCount && (!UserFound || !GroupFound || !OtherFound);
++i) {
Status = RtlGetAce(Acl, i, (PVOID *)&Ace);
if (!NT_SUCCESS(Status)) {
return Status;
}
if (Ace->Header.AceType != ACCESS_ALLOWED_ACE_TYPE) {
Status = STATUS_EXTRANEOUS_INFORMATION;
continue;
}
if (RtlEqualSid(
(PSID)(&Ace->SidStart),
UserSid
) && !UserFound) {
*UserAccess = Ace->Mask;
UserFound = TRUE;
continue;
}
if (RtlEqualSid(
(PSID)(&Ace->SidStart),
GroupSid
) && !GroupFound) {
*GroupAccess = Ace->Mask;
GroupFound = TRUE;
continue;
}
//
// It isn't the user, and it isn't the group, pick it up
// as "other"
//
if (!OtherFound) {
*OtherAccess = Ace->Mask;
OtherFound = TRUE;
continue;
}
}
return( Status );
}
//
// Internal support routine
//
VOID
AddData (
IN PVOID From,
IN ULONG FromSize,
IN PVOID To,
IN ULONG ToSize
)
/*++
Routine Description:
This routine copies data to a string of bytes. It does this by moving
over data in the to string so that the from string will fit. It also
assumes that the checks that the data will fit in memory have already
been done. Pictorally the results are as follows.
Before:
From -> ffffffffff
To -> tttttttttttttttt
After:
From -> ffffffffff
To -> fffffffffftttttttttttttttt
Arguments:
From - Supplies a pointer to the source buffer
FromSize - Supplies the size of the from buffer in bytes
To - Supplies a pointer to the destination buffer
ToSize - Supplies the size of the to buffer in bytes
Return Value:
None
--*/
{
LONG i;
//
// Shift over the To buffer enough to fit in the From buffer
//
for (i = ToSize - 1; i >= 0; i--) {
((PUCHAR)To)[i+FromSize] = ((PUCHAR)To)[i];
}
//
// Now copy over the From buffer
//
for (i = 0; (ULONG)i < FromSize; i += 1) {
((PUCHAR)To)[i] = ((PUCHAR)From)[i];
}
//
// and return to our caller
//
return;
}
//
// Internal support routine
//
VOID
DeleteData (
IN PVOID Data,
IN ULONG RemoveSize,
IN ULONG TotalSize
)
/*++
Routine Description:
This routine deletes a string of bytes from the front of a data buffer
and compresses the data. It also zeros out the part of the string
that is no longer in use. Pictorially the results are as follows
Before:
Data = DDDDDddddd
RemoveSize = 5
TotalSize = 10
After:
Data = ddddd00000
Arguments:
Data - Supplies a pointer to the data being altered
RemoveSize - Supplies the number of bytes to delete from the front
of the data buffer
TotalSize - Supplies the total number of bytes in the data buffer
before the delete operation
Return Value:
None
--*/
{
ULONG i;
//
// Shift over the buffer to remove the amount
//
for (i = RemoveSize; i < TotalSize; i++) {
((PUCHAR)Data)[i-RemoveSize] = ((PUCHAR)Data)[i];
}
//
// Now as a safety precaution we'll zero out the rest of the string
//
for (i = TotalSize - RemoveSize; i < TotalSize; i++) {
((PUCHAR)Data)[i] = 0;
}
//
// And return to our caller
//
return;
}