/*++

Copyright (c) Microsoft Corporation. All rights reserved. 

You may only use this code if you agree to the terms of the Windows Research Kernel Source Code License agreement (see License.txt).
If you do not agree to the terms, do not use the code.


Module Name:

    sep.h

Abstract:

    This module contains the internal (private) declarations needed by the
    Kernel mode security routines.

--*/

#ifndef _SEP_
#define _SEP_

#include "ntos.h"
#include <ntrmlsa.h>
#include "seopaque.h"



/////////////////////////////////////////////////////////////////////////
//                                                                     //
//                SE Diagnostics                                       //
//                                                                     //
/////////////////////////////////////////////////////////////////////////



#if DBG
#define SE_DIAGNOSTICS_ENABLED 1
#endif // DBG


//
// These definitions are useful diagnostics aids
//

#if SE_DIAGNOSTICS_ENABLED

//
// Test for enabled diagnostic
//

#define IF_SE_GLOBAL( FlagName ) \
    if (SeGlobalFlag & (SE_DIAG_##FlagName))

//
// Diagnostics print statement
//

#define SeDiagPrint( FlagName, _Text_ )                               \
    IF_SE_GLOBAL( FlagName )                                          \
        DbgPrint _Text_


#else

//
// diagnostics not enabled - No diagnostics included in build
//


//
// Test for diagnostics enabled
//

#define IF_SE_GLOBAL( FlagName ) if (FALSE)

//
// Diagnostics print statement (expands to no-op)
//

#define SeDiagPrint( FlagName, _Text_ )     ;

#endif // SE_DIAGNOSTICS_ENABLED




//
// The following flags enable or disable various diagnostic
// capabilities within SE code.  These flags are set in
// SeGlobalFlag (only available within a DBG system).
//
//      SD_TRACKING - Display information about create/deletion of
//          shared security descriptors
//
//

#define SE_DIAG_SD_TRACKING          ((ULONG) 0x00000001L)





//
// Control flag manipulation macros
//

//
//  Macro to query whether or not control flags ALL on
//  or not (ie, returns FALSE if any of the flags are not set)
//

#define SepAreFlagsSet( Mask, Bits )                                           \
            (                                                                  \
            ((Mask) & ( Bits )) == ( Bits )                                    \
            )

//
//  Macro to set the specified control bits in the given Security Descriptor
//

#define SepSetFlags( Mask, Bits )                                              \
            (                                                                  \
            ( Mask ) |= ( Bits )                                               \
            )

//
//  Macro to clear the passed control bits in the given Security Descriptor
//

#define SepClearFlags( Mask, Bits )                                            \
            (                                                                  \
            ( Mask ) &= ~( Bits )                                              \
            )




//
// Macro to determine the size of a PRIVILEGE_SET
//

#define SepPrivilegeSetSize( PrivilegeSet )                                    \
        ( ( PrivilegeSet ) == NULL ? 0 :                                       \
        ((( PrivilegeSet )->PrivilegeCount > 0)                                \
         ?                                                                     \
         ((ULONG)sizeof(PRIVILEGE_SET) +                                       \
           (                                                                   \
             (( PrivilegeSet )->PrivilegeCount  -  ANYSIZE_ARRAY) *            \
             (ULONG)sizeof(LUID_AND_ATTRIBUTES)                                \
           )                                                                   \
         )                                                                     \
         : ((ULONG)sizeof(PRIVILEGE_SET) - (ULONG)sizeof(LUID_AND_ATTRIBUTES)) \
        ))


//
//      Return the effective token from a SecurityContext
//

#define EffectiveToken( SubjectSecurityContext ) (                            \
                 (SubjectSecurityContext)->ClientToken ?                      \
                 (SubjectSecurityContext)->ClientToken :                      \
                 (SubjectSecurityContext)->PrimaryToken                       \
                 )                                                            \


//
//      Return a pointer to the Sid of the User of a given token
//

#define SepTokenUserSid( Token )   ((PTOKEN)(Token))->UserAndGroups->Sid


//
//      Return the AuthenticationId from a given token
//

#define SepTokenAuthenticationId( Token )   (((PTOKEN)(Token))->AuthenticationId)



//
//
// BOOLEAN
// SepBadImpersonationLevel(
//     IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
//     IN BOOLEAN ServerIsRemote
//     )
//
// Routine Description:
//
//     Determine whether a client is trying to impersonate inappropriately
//     This routine should only be called if a thread requesting impersonation
//     is itself already impersonating a client of its own.  This routine
//     indicates whether the client is attempting to violate the level of
//     impersonation granted to it by its client.
//
// Arguments:
//
//     ImpersonationLevel - Is the impersonation level of the client's
//         effective token.
//
//     ServerIsRemote - Is a boolean flag indicating whether the client
//         is requesting impersonation services to a remote system.  TRUE
//         indicates the session is a remote session, FALSE indicates the
//         session is a local session.  Delegation level is necessary to
//         achieve a remote session.
//
// Return Value:
//
//     TRUE - Indicates that the impersonation level of the client's client
//         token is inappropriate for the attempted impersonation.
//         An error (STATUS_BAD_IMPERSONATION_LEVEL) should be generated.
//
//     FALSE - Indicates the impersonation attempt is not bad, and should
//         be allowed.
//
//

#define SepBadImpersonationLevel(IL,SIR)  ((                                   \
            ((IL) == SecurityAnonymous) || ((IL) == SecurityIdentification) || \
            ( (SIR) && ((IL) != SecurityDelegation) )                          \
            ) ? TRUE : FALSE )



//++
//
// BOOL
// IsValidElementCount(
//      IN ULONG Count,
//      IN <STRUCTURE>
//      );
//
//--

#define IsValidElementCount( Count, STRUCTURE ) \
    ( Count < ( (ULONG_PTR) ( (PUCHAR) ( (PUCHAR) (LONG_PTR)(LONG)0xFFFFFFFF - (PUCHAR) MM_SYSTEM_RANGE_START ) + 1 ) \
        / sizeof( STRUCTURE ) ) )


#define SEP_MAX_PRIVILEGE_COUNT (SE_MAX_WELL_KNOWN_PRIVILEGE-SE_MIN_WELL_KNOWN_PRIVILEGE+32)

#define IsValidPrivilegeCount( count ) ((count == 0) || \
                                        ((count > 0) && \
                                         (count <= SEP_MAX_PRIVILEGE_COUNT)))

//
// the object type list limit is chosen arbitrarily 
//
#define SEP_MAX_OBJECT_TYPE_LIST_COUNT 4096 

#define IsValidObjectTypeListCount( count ) \
          ((count == 0) || \
           (count <= SEP_MAX_OBJECT_TYPE_LIST_COUNT))

#define IsInRange(item,min_val,max_val) \
            (((item) >= min_val) && ((item) <= max_val))

//       
// see msaudite.mc for def. of valid category-id
//
#define IsValidCategoryId(c) \
            (IsInRange((c), SE_ADT_MIN_CATEGORY_ID, SE_ADT_MAX_CATEGORY_ID))

//
// see msaudite.mc for def. of valid audit-id
//

#define IsValidAuditId(a) \
            (IsInRange((a), SE_ADT_MIN_AUDIT_ID, SE_ADT_MAX_AUDIT_ID))

//
// check for reasonable value of parameter count. we must have atleast
// 2 parameters in the audit-params array. Thus the min limit is 3.
// The max limit is determined by the value in ntlsa.h
//

#define IsValidParameterCount(p) \
            (IsInRange((p), 2, SE_MAX_AUDIT_PARAMETERS))





///////////////////////////////////////////////////////////////////////////
//                                                                       //
//  Constants                                                            //
//                                                                       //
///////////////////////////////////////////////////////////////////////////

#define SEP_MAX_GROUP_COUNT 4096


///////////////////////////////////////////////////////////////////////////
//                                                                       //
//  Private Data types                                                   //
//                                                                       //
///////////////////////////////////////////////////////////////////////////


extern HANDLE SepLsaHandle;

//extern BOOLEAN SepAuditShutdownEvents;

//
// Spinlock protecting the queue of work being passed to LSA
//

extern ERESOURCE SepLsaQueueLock;

extern ULONG SepLsaQueueLength;

//
// Doubly linked list of work items queued to worker threads.
//

extern LIST_ENTRY SepLsaQueue;


extern LONG SepTokenPolicyCounter[POLICY_AUDIT_EVENT_TYPE_COUNT];

// #define SepAcquireTokenReadLock(T)  KeEnterCriticalRegion();          \
//                                     ExAcquireResourceSharedLite(&SepTokenLock, TRUE)

#define SepLockLsaQueue()  KeEnterCriticalRegion();                           \
                           ExAcquireResourceExclusiveLite(&SepLsaQueueLock, TRUE)

#define SepUnlockLsaQueue() ExReleaseResourceLite(&SepLsaQueueLock);              \
                            KeLeaveCriticalRegion()

#define  SepWorkListHead()  ((PSEP_LSA_WORK_ITEM)(&SepLsaQueue)->Flink)

#define  SepWorkListEmpty() (IsListEmpty (&SepLsaQueue))

#ifndef ExAllocatePool
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'  eS')
#endif
#ifndef ExAllocatePoolWithQuota
#define ExAllocatePoolWithQuota(a,b) ExAllocatePoolWithQuotaTag(a,b,'  eS')
#endif

typedef
VOID
(*PSEP_LSA_WORKER_CLEANUP_ROUTINE)(
    IN PVOID Parameter
    );


typedef enum _SEP_LSA_WORK_ITEM_TAG {
    SepDeleteLogon,
    SepAuditRecord
} SEP_LSA_WORK_ITEM_TAG, *PSEP_LSA_WORK_ITEM_TAG;





typedef struct _SEP_LSA_WORK_ITEM {

    //
    // This field must be the first field of this structure
    //

    LIST_ENTRY                      List;

    //
    // Command Params Memory type
    //

    SEP_RM_LSA_MEMORY_TYPE          CommandParamsMemoryType;

    //
    // Tag describing what kind of structure we've got
    //

    SEP_LSA_WORK_ITEM_TAG           Tag;

    //
    // The following union contains the data to be passed
    // to LSA.
    //

    union {

        PVOID                       BaseAddress;
        LUID                        LogonId;

    } CommandParams;

    //
    // These fields must be filled in by the caller of SepRmCallLsa
    //

    LSA_COMMAND_NUMBER              CommandNumber;
    ULONG                           CommandParamsLength;
    PVOID                           ReplyBuffer;
    ULONG                           ReplyBufferLength;

    //
    // CleanupFunction (if specified) will be called with CleanupParameter
    // as its argument before the SEP_LSA_WORK_ITEM is freed by SepRmCallLsa
    //

    PSEP_LSA_WORKER_CLEANUP_ROUTINE CleanupFunction;
    PVOID                           CleanupParameter;

} SEP_LSA_WORK_ITEM, *PSEP_LSA_WORK_ITEM;


typedef struct _SEP_WORK_ITEM {

    WORK_QUEUE_ITEM  WorkItem;

} SEP_WORK_ITEM, *PSEP_WORK_ITEM;

//
// Each logon session active in the system has a corresponding record of
// the following type...
//

typedef struct _SEP_LOGON_SESSION_REFERENCES {
    struct _SEP_LOGON_SESSION_REFERENCES *Next;
    LUID LogonId;
    ULONG ReferenceCount;
    ULONG Flags;
    PDEVICE_MAP pDeviceMap;
#if DBG || TOKEN_LEAK_MONITOR
    LIST_ENTRY TokenList;
#endif
} SEP_LOGON_SESSION_REFERENCES, *PSEP_LOGON_SESSION_REFERENCES;


extern SEP_WORK_ITEM SepExWorkItem;






///////////////////////////////////////////////////////////////////////////
//                                                                       //
//  Private Routines                                                     //
//                                                                       //
///////////////////////////////////////////////////////////////////////////

BOOLEAN
SepDevelopmentTest( VOID );      //Used only for development testing


BOOLEAN
SepInitializationPhase0( VOID );

BOOLEAN
SepInitializationPhase1( VOID );

BOOLEAN
SepVariableInitialization( VOID );

NTSTATUS
SepCreateToken(
    OUT PHANDLE TokenHandle,
    IN KPROCESSOR_MODE RequestorMode,
    IN ACCESS_MASK DesiredAccess,
    IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
    IN TOKEN_TYPE TokenType,
    IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel OPTIONAL,
    IN PLUID AuthenticationId,
    IN PLARGE_INTEGER ExpirationTime,
    IN PSID_AND_ATTRIBUTES User,
    IN ULONG GroupCount,
    IN PSID_AND_ATTRIBUTES Groups,
    IN ULONG GroupsLength,
    IN ULONG PrivilegeCount,
    IN PLUID_AND_ATTRIBUTES Privileges,
    IN PSID Owner OPTIONAL,
    IN PSID PrimaryGroup,
    IN PACL DefaultDacl OPTIONAL,
    IN PTOKEN_SOURCE TokenSource,
    IN BOOLEAN SystemToken,
    IN PSECURITY_TOKEN_PROXY_DATA ProxyData OPTIONAL,
    IN PSECURITY_TOKEN_AUDIT_DATA AuditData OPTIONAL
    );

NTSTATUS
SepReferenceLogonSession(
    IN PLUID LogonId,
    OUT PSEP_LOGON_SESSION_REFERENCES *ReturnSession
    );

VOID
SepDeReferenceLogonSession(
    IN PLUID LogonId
    );

#define TOKEN_LEAK_MONITOR 0
#if DBG || TOKEN_LEAK_MONITOR

VOID 
SepAddTokenLogonSession(
    IN PACCESS_TOKEN Token
    );

VOID
SepRemoveTokenLogonSession(
    IN PACCESS_TOKEN Token
    );

extern LONG    SepTokenLeakMethodCount;
extern LONG    SepTokenLeakBreakCount;
extern LONG    SepTokenLeakMethodWatch;
extern PVOID   SepTokenLeakToken;
extern HANDLE  SepTokenLeakProcessCid;
extern BOOLEAN SepTokenLeakTracking;

#endif

VOID
SepLockSubjectContext(
    IN PSECURITY_SUBJECT_CONTEXT SubjectContext
    );

VOID
SepFreeSubjectContext(
    IN PSECURITY_SUBJECT_CONTEXT SubjectContext
    );

VOID
SepGetDefaultsSubjectContext(
    IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
    OUT PSID *Owner,
    OUT PSID *Group,
    OUT PSID *ServerOwner,
    OUT PSID *ServerGroup,
    OUT PACL *Dacl
    );

BOOLEAN
SepValidOwnerSubjectContext(
    IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
    IN PSID Owner,
    IN BOOLEAN ServerObject
    );

BOOLEAN
SepIdAssignableAsGroup(
    IN PACCESS_TOKEN Token,
    IN PSID Group
    );

BOOLEAN
SepCheckAcl (
    IN PACL Acl,
    IN ULONG Length
    );

BOOLEAN
SepAuditAlarm (
    IN PUNICODE_STRING SubsystemName,
    IN PVOID HandleId,
    IN PUNICODE_STRING ObjectTypeName,
    IN PUNICODE_STRING ObjectName,
    IN PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN ACCESS_MASK DesiredAccess,
    IN BOOLEAN ObjectCreation,
    IN ACCESS_MASK GrantedAccess,
    OUT PBOOLEAN GenerateOnClose
    );

BOOLEAN
SepSinglePrivilegeCheck (
   LUID DesiredPrivilege,
   IN PACCESS_TOKEN EffectiveToken,
   IN KPROCESSOR_MODE PreviousMode
   );

NTSTATUS
SepRmCallLsa(
    PSEP_WORK_ITEM SepWorkItem
    );

BOOLEAN
SepInitializeWorkList(
    VOID
    );

BOOLEAN
SepRmInitPhase0(
    );

VOID
SepConcatenatePrivileges(
    IN PPRIVILEGE_SET TargetPrivilegeSet,
    IN ULONG TargetBufferSize,
    IN PPRIVILEGE_SET SourcePrivilegeSet
    );

BOOLEAN
SepTokenIsOwner(
    IN PACCESS_TOKEN Token,
    IN PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN BOOLEAN TokenLocked
    );

#if DBG
VOID
SepPrintAcl (
    IN PACL Acl
    );

VOID
SepPrintSid(
    IN PSID Sid
    );

VOID
SepDumpSecurityDescriptor(
    IN PSECURITY_DESCRIPTOR SecurityDescriptor,
    IN PSZ TitleString
    );

BOOLEAN
SepSidTranslation(
    PSID Sid,
    PSTRING AccountName
    );

VOID
SepDumpTokenInfo(
    IN PACCESS_TOKEN Token
    );

VOID
SepDumpString(
    IN PUNICODE_STRING String
    );
#endif //DBG

BOOLEAN
SepSidInToken (
    IN PACCESS_TOKEN Token,
    IN PSID PrincipalSelfSid,
    IN PSID Sid,
    IN BOOLEAN DenyAce
    );


VOID
SepExamineSacl(
    IN PACL Sacl,
    IN PACCESS_TOKEN Token,
    IN ACCESS_MASK DesiredAccess,
    IN BOOLEAN AccessGranted,
    OUT PBOOLEAN GenerateAudit,
    OUT PBOOLEAN GenerateAlarm
    );


VOID
SepCopyString (
    IN PUNICODE_STRING SourceString,
    OUT PUNICODE_STRING *DestString
    );

VOID
SepAssemblePrivileges(
    IN ULONG PrivilegeCount,
    IN BOOLEAN SystemSecurity,
    IN BOOLEAN WriteOwner,
    OUT PPRIVILEGE_SET *Privileges
    );


PUNICODE_STRING
SepQueryTypeString(
    IN PVOID Object
    );


POBJECT_NAME_INFORMATION
SepQueryNameString(
    IN PVOID Object
    );
                        
#define SEP_SERVICES_FILTER 0x1

BOOLEAN
SepFilterPrivilegeAudits(
    IN ULONG Flags,
    IN PPRIVILEGE_SET PrivilegeSet
    );

BOOLEAN
SepQueueWorkItem(
    IN PSEP_LSA_WORK_ITEM LsaWorkItem,
    IN BOOLEAN ForceQueue
    );

PSEP_LSA_WORK_ITEM
SepDequeueWorkItem(
    VOID
    );

VOID
SepAdtGenerateDiscardAudit(
    VOID
    );

BOOLEAN
SepAdtValidateAuditBounds(
    ULONG Upper,
    ULONG Lower
    );

NTSTATUS
SepAdtInitializeCrashOnFail(
    VOID
    );

BOOLEAN
SepAdtInitializePrivilegeAuditing(
    VOID
    );

NTSTATUS
SepCopyProxyData (
    OUT PSECURITY_TOKEN_PROXY_DATA * DestProxyData,
    IN PSECURITY_TOKEN_PROXY_DATA SourceProxyData
    );

VOID
SepFreeProxyData (
    IN PSECURITY_TOKEN_PROXY_DATA ProxyData
    );

NTSTATUS
SepProbeAndCaptureQosData(
    IN PSECURITY_ADVANCED_QUALITY_OF_SERVICE CapturedSecurityQos
    );

VOID
SepAuditAssignPrimaryToken(
    IN PEPROCESS Process,
    IN PACCESS_TOKEN NewAccessToken
    );

BOOLEAN
SepAdtAuditThisEventWithContext(
    IN POLICY_AUDIT_EVENT_TYPE Category,
    IN BOOLEAN AccessGranted,
    IN BOOLEAN AccessDenied,
    IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext OPTIONAL
    );

#endif // _SEP_

