diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/se/privileg.c | 574 |
1 files changed, 574 insertions, 0 deletions
diff --git a/private/ntos/se/privileg.c b/private/ntos/se/privileg.c new file mode 100644 index 000000000..2257b2967 --- /dev/null +++ b/private/ntos/se/privileg.c @@ -0,0 +1,574 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + Privileg.c + +Abstract: + + This Module implements the privilege check procedures. + +Author: + + Robert Reichel (robertre) 26-Nov-90 + +Environment: + + Kernel Mode + +Revision History: + +--*/ + +#include "tokenp.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,NtPrivilegeCheck) +#pragma alloc_text(PAGE,SeCheckPrivilegedObject) +#pragma alloc_text(PAGE,SepPrivilegeCheck) +#pragma alloc_text(PAGE,SePrivilegeCheck) +#pragma alloc_text(PAGE,SeSinglePrivilegeCheck) +#endif + + +BOOLEAN +SepPrivilegeCheck( + IN PTOKEN Token, + IN OUT PLUID_AND_ATTRIBUTES RequiredPrivileges, + IN ULONG RequiredPrivilegeCount, + IN ULONG PrivilegeSetControl, + IN KPROCESSOR_MODE PreviousMode + ) +/*++ + +Routine Description: + + Worker routine for SePrivilegeCheck + +Arguments: + + Token - The user's effective token. + + RequiredPrivileges - A privilege set describing the required + privileges. The UsedForAccess bits will be set in any privilege + that is actually used (usually all of them). + + RequiredPrivilegeCount - How many privileges are in the + RequiredPrivileges set. + + PrivilegeSetControl - Describes how many privileges are required. + + PreviousMode - The previous processor mode. + +Return Value: + + Returns TRUE if requested privileges are granted, FALSE otherwise. + +--*/ + +{ + PLUID_AND_ATTRIBUTES CurrentRequiredPrivilege; + PLUID_AND_ATTRIBUTES CurrentTokenPrivilege; + + BOOLEAN RequiredAll; + + ULONG TokenPrivilegeCount; + ULONG MatchCount = 0; + + ULONG i; + ULONG j; + + PAGED_CODE(); + + // + // Take care of kernel callers first + // + + if (PreviousMode == KernelMode) { + + return(TRUE); + + } + + SepAcquireTokenReadLock( Token ); + + TokenPrivilegeCount = Token->PrivilegeCount; + + // + // Save whether we require ALL of them or ANY + // + + RequiredAll = (BOOLEAN)(PrivilegeSetControl & PRIVILEGE_SET_ALL_NECESSARY); + + for ( i = 0 , CurrentRequiredPrivilege = RequiredPrivileges ; + i < RequiredPrivilegeCount ; + i++, CurrentRequiredPrivilege++ ) { + + for ( j = 0, CurrentTokenPrivilege = Token->Privileges; + j < TokenPrivilegeCount ; + j++, CurrentTokenPrivilege++ ) { + + if ((CurrentTokenPrivilege->Attributes & SE_PRIVILEGE_ENABLED) && + (RtlEqualLuid(&CurrentTokenPrivilege->Luid, + &CurrentRequiredPrivilege->Luid)) + ) { + + CurrentRequiredPrivilege->Attributes |= + SE_PRIVILEGE_USED_FOR_ACCESS; + MatchCount++; + break; // start looking for next one + } + + } + + } + + SepReleaseTokenReadLock( Token ); + + // + // If we wanted ANY and didn't get any, return failure. + // + + if (!RequiredAll && (MatchCount == 0)) { + + return (FALSE); + + } + + // + // If we wanted ALL and didn't get all, return failure. + // + + if (RequiredAll && (MatchCount != RequiredPrivilegeCount)) { + + return(FALSE); + } + + return(TRUE); + +} + + + + +BOOLEAN +SePrivilegeCheck( + IN OUT PPRIVILEGE_SET RequiredPrivileges, + IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext, + IN KPROCESSOR_MODE AccessMode + ) +/*++ + +Routine Description: + + This routine checks to see if the token contains the specified + privileges. + +Arguments: + + RequiredPrivileges - Points to a set of privileges. The subject's + security context is to be checked to see which of the specified + privileges are present. The results will be indicated in the + attributes associated with each privilege. Note that + flags in this parameter indicate whether all the privileges listed + are needed, or any of the privileges. + + SubjectSecurityContext - A pointer to the subject's captured security + context. + + AccessMode - Indicates the access mode to use for access check. One of + UserMode or KernelMode. If the mode is kernel, then all privileges + will be marked as being possessed by the subject, and successful + completion status is returned. + + +Return Value: + + BOOLEAN - TRUE if all specified privileges are held by the subject, + otherwise FALSE. + + +--*/ + +{ + BOOLEAN Status; + + PAGED_CODE(); + + // + // If we're impersonating a client, we have to be at impersonation level + // of SecurityImpersonation or above. + // + + if ( (SubjectSecurityContext->ClientToken != NULL) && + (SubjectSecurityContext->ImpersonationLevel < SecurityImpersonation) + ) { + + return(FALSE); + } + + // + // SepPrivilegeCheck locks the passed token for read access + // + + Status = SepPrivilegeCheck( + EffectiveToken( SubjectSecurityContext ), + RequiredPrivileges->Privilege, + RequiredPrivileges->PrivilegeCount, + RequiredPrivileges->Control, + AccessMode + ); + + return(Status); +} + + + +NTSTATUS +NtPrivilegeCheck( + IN HANDLE ClientToken, + IN OUT PPRIVILEGE_SET RequiredPrivileges, + OUT PBOOLEAN Result + ) + +/*++ + +Routine Description: + + This routine tests the caller's client's security context to see if it + contains the specified privileges. + + This API requires the caller have SeTcbPrivilege privilege. The test + for this privilege is always against the primary token of the calling + process, not the impersonation token of the thread. + + +Arguments: + + ClientToken - A handle to a token object representing a client + attempting access. This handle must be obtained from a + communication session layer, such as from an LPC Port or Local + Named Pipe, to prevent possible security policy violations. + + RequiredPrivileges - Points to a set of privileges. The client's + security context is to be checked to see which of the specified + privileges are present. The results will be indicated in the + attributes associated with each privilege. Note that + flags in this parameter indicate whether all the privileges listed + are needed, or any of the privileges. + + Result - Receives a boolean flag indicating whether the client has all + the specified privileges or not. A value of TRUE indicates the + client has all the specified privileges. Otherwise a value of + FALSE is returned. + + + +Return Value: + + STATUS_SUCCESS - Indicates the call completed successfully. + + STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have + sufficient privilege to use this privileged system service. + +--*/ + + + +{ + BOOLEAN BStatus; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status; + PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; + PTOKEN Token; + ULONG CapturedPrivilegeCount; + ULONG CapturedPrivilegesLength; + ULONG ParameterLength; + ULONG PrivilegeSetControl; + + PAGED_CODE(); + + PreviousMode = KeGetPreviousMode(); + + Status = ObReferenceObjectByHandle( + ClientToken, // Handle + TOKEN_QUERY, // DesiredAccess + SepTokenObjectType, // ObjectType + PreviousMode, // AccessMode + (PVOID *)&Token, // Object + NULL // GrantedAccess + ); + + if ( !NT_SUCCESS(Status) ) { + return Status; + + } + + // + // If the passed token is an impersonation token, make sure + // it is at SecurityIdentification or above. + // + + if (Token->TokenType == TokenImpersonation) { + + if (Token->ImpersonationLevel < SecurityIdentification) { + + ObDereferenceObject( (PVOID)Token ); + + return( STATUS_BAD_IMPERSONATION_LEVEL ); + + } + } + + try { + + // + // Capture passed Privilege Set + // + + ProbeForWrite( + RequiredPrivileges, + sizeof(PRIVILEGE_SET), + sizeof(ULONG) + ); + + ParameterLength = (ULONG)sizeof(PRIVILEGE_SET) + + ((RequiredPrivileges->PrivilegeCount - ANYSIZE_ARRAY) * + (ULONG)sizeof(LUID_AND_ATTRIBUTES) ); + + ProbeForWrite( + RequiredPrivileges, + ParameterLength, + sizeof(ULONG) + ); + + + ProbeForWriteBoolean(Result); + + PrivilegeSetControl = RequiredPrivileges->Control; + CapturedPrivilegeCount = RequiredPrivileges->PrivilegeCount; + + + } except(EXCEPTION_EXECUTE_HANDLER) { + + ObDereferenceObject( (PVOID)Token ); + return GetExceptionCode(); + } + + Status = SeCaptureLuidAndAttributesArray( + (RequiredPrivileges->Privilege), + CapturedPrivilegeCount, + UserMode, + NULL, 0, + PagedPool, + TRUE, + &CapturedPrivileges, + &CapturedPrivilegesLength + ); + + if (!NT_SUCCESS(Status)) { + + ObDereferenceObject( (PVOID)Token ); + return Status; + } + + ASSERT(CapturedPrivileges != NULL); + + BStatus = SepPrivilegeCheck( + Token, // Token, + CapturedPrivileges, // RequiredPrivileges, + CapturedPrivilegeCount, // RequiredPrivilegeCount, + PrivilegeSetControl, // PrivilegeSetControl + PreviousMode // PreviousMode + ); + + ObDereferenceObject( Token ); + + + try { + + // + // copy the modified privileges buffer back to user + // + + RtlMoveMemory( + RequiredPrivileges->Privilege, + CapturedPrivileges, + CapturedPrivilegesLength + ); + + *Result = BStatus; + + } except (EXCEPTION_EXECUTE_HANDLER) { + + SeReleaseLuidAndAttributesArray( + CapturedPrivileges, + PreviousMode, + TRUE + ); + + return(GetExceptionCode()); + + } + + SeReleaseLuidAndAttributesArray( + CapturedPrivileges, + PreviousMode, + TRUE + ); + + return( STATUS_SUCCESS ); +} + + + +BOOLEAN +SeSinglePrivilegeCheck( + LUID PrivilegeValue, + KPROCESSOR_MODE PreviousMode + ) + +/*++ + +Routine Description: + + This function will check for the passed privilege value in the + current context. + +Arguments: + + PrivilegeValue - The value of the privilege being checked. + + +Return Value: + + TRUE - The current subject has the desired privilege. + + FALSE - The current subject does not have the desired privilege. +--*/ + +{ + BOOLEAN AccessGranted; + PRIVILEGE_SET RequiredPrivileges; + SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; + + PAGED_CODE(); + + // + // Make sure the caller has the privilege to make this + // call. + // + + RequiredPrivileges.PrivilegeCount = 1; + RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY; + RequiredPrivileges.Privilege[0].Luid = PrivilegeValue; + RequiredPrivileges.Privilege[0].Attributes = 0; + + SeCaptureSubjectContext( &SubjectSecurityContext ); + + AccessGranted = SePrivilegeCheck( + &RequiredPrivileges, + &SubjectSecurityContext, + PreviousMode + ); + + if ( PreviousMode != KernelMode ) { + + SePrivilegedServiceAuditAlarm ( + NULL, // BUGWARNING need service name + &SubjectSecurityContext, + &RequiredPrivileges, + AccessGranted + ); + } + + + SeReleaseSubjectContext( &SubjectSecurityContext ); + + return( AccessGranted ); + +} + + +BOOLEAN +SeCheckPrivilegedObject( + LUID PrivilegeValue, + HANDLE ObjectHandle, + ACCESS_MASK DesiredAccess, + KPROCESSOR_MODE PreviousMode + ) + +/*++ + +Routine Description: + + This function will check for the passed privilege value in the + current context, and generate audits as appropriate. + +Arguments: + + PrivilegeValue - The value of the privilege being checked. + + Object - Specifies a pointer to the object being accessed. + + ObjectHandle - Specifies the object handle being used. + + DesiredAccess - The desired access mask, if any + + PreviousMode - The previous processor mode + + +Return Value: + + TRUE - The current subject has the desired privilege. + + FALSE - The current subject does not have the desired privilege. +--*/ + +{ + BOOLEAN AccessGranted; + PRIVILEGE_SET RequiredPrivileges; + SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; + + PAGED_CODE(); + + // + // Make sure the caller has the privilege to make this + // call. + // + + RequiredPrivileges.PrivilegeCount = 1; + RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY; + RequiredPrivileges.Privilege[0].Luid = PrivilegeValue; + RequiredPrivileges.Privilege[0].Attributes = 0; + + SeCaptureSubjectContext( &SubjectSecurityContext ); + + AccessGranted = SePrivilegeCheck( + &RequiredPrivileges, + &SubjectSecurityContext, + PreviousMode + ); + + if ( PreviousMode != KernelMode ) { + + SePrivilegeObjectAuditAlarm( + ObjectHandle, + &SubjectSecurityContext, + DesiredAccess, + &RequiredPrivileges, + AccessGranted, + PreviousMode + ); + + } + + + SeReleaseSubjectContext( &SubjectSecurityContext ); + + return( AccessGranted ); + +} |