几个函数

来源:互联网 发布:软件测试全套视频教程 编辑:程序博客网 时间:2024/05/16 23:38

/*++

Copyright (c) 1991  Microsoft Corporation

Module Name:

    security.c

Abstract:

    This module implements Object Security APIs for Win32

Author:

    Jim Anderson (JimA) 01-Jul-1991
    Robert Reichel (RobertRe) 01-Jan-92

Revision History:

--*/

#include "advapi.h"
#include <ntlsa.h>
#include <rpc.h>
#include <rpcndr.h>
#include <stdio.h>

#define LSADEFINED


/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//               Private Routine Prototypes                                //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////


VOID
SepFormatAccountSid(
    PSID iSid,
    LPWSTR OutputBuffer
    );



/////////////////////////////////////////////////////////////////////////////
//                                                                         //
//               Exported Routines                                         //
//                                                                         //
/////////////////////////////////////////////////////////////////////////////

 



BOOL
APIENTRY
DuplicateToken(
    HANDLE ExistingTokenHandle,
    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
    PHANDLE DuplicateTokenHandle
    )

/*++

Routine Description:

    Create a new token that is a duplicate of an existing token.  The
    new token will be an impersonation token of the supplied level.

Arguments:

    ExistingTokenHandle - Is a handle to a token already open for
        TOKEN_DUPLICATE access.

    ImpersonationLevel - Supplies the impersonation level of the new
        token.

    DuplicateTokenHandle - Returns the handle to the new token.  The
        handle will have TOKEN_IMPERSONATE and TOKEN_QUERY access to
        the new token.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.


--*/

{
    return( DuplicateTokenEx( ExistingTokenHandle,
                              TOKEN_IMPERSONATE | TOKEN_QUERY,
                              NULL,
                              ImpersonationLevel,
                              TokenImpersonation,
                              DuplicateTokenHandle
                              ) );

}

BOOL
DuplicateTokenEx(
    HANDLE hExistingToken,
    DWORD dwDesiredAccess,
    LPSECURITY_ATTRIBUTES lpTokenAttributes,
    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
    TOKEN_TYPE TokenType,
    PHANDLE phNewToken)
/*++

    Routine Description:

    Create a new token that is a duplicate of an existing token.  This API
    more fully exposes NtDuplicateToken .

    Arguments:

        hExistingToken - Is a handle to a token already open for
                                        TOKEN_DUPLICATE access.

        dwDesiredAccess - desired access rights to the new token, e.g.
                                       TOKEN_DUPLICATE, TOKEN_IMPERSONATE, etc.

        lpTokenAttributes - Desired security attributes for the new token.

        ImpersonationLevel - Supplies the impersonation level of the new token.

        TokenType - One of TokenImpersonation or TokenPrimary.

        phNewToken  - Returns the handle to the new token.

    Return Value:

        Returns TRUE for success, FALSE for failure.  Extended error status
        is available using GetLastError.

--*/


{

    OBJECT_ATTRIBUTES ObjA;
    SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
    PSECURITY_DESCRIPTOR SecurityDescriptor;
    NTSTATUS Status;
    ULONG Attributes;

    SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE  );
    SecurityQualityOfService.ImpersonationLevel = ImpersonationLevel;
    SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    SecurityQualityOfService.EffectiveOnly = FALSE;

    if (lpTokenAttributes)
    {
        SecurityDescriptor = lpTokenAttributes->lpSecurityDescriptor;
        if (lpTokenAttributes->bInheritHandle)
        {
            Attributes = OBJ_INHERIT;
        }
        else
        {
            Attributes = 0;
        }
    }
    else
    {
        SecurityDescriptor = NULL;
        Attributes = 0;
    }

    InitializeObjectAttributes(
        &ObjA,
        NULL,
        Attributes,
        NULL,
        SecurityDescriptor
        );

    ObjA.SecurityQualityOfService = &SecurityQualityOfService;

    Status = NtDuplicateToken(
                 hExistingToken,
                 dwDesiredAccess,
                 &ObjA,
                 FALSE,
                 TokenType,
                 phNewToken
                 );

    if ( !NT_SUCCESS( Status ) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return( TRUE );

}

 

 

BOOL
APIENTRY
AllocateLocallyUniqueId(
    PLUID Luid
    )
/*++

Routine Description:

    Allocates a locally unique ID (LUID).

Arguments:

    Luid - Supplies a pointer used to return the LUID.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/

{   NTSTATUS Status;

    Status = NtAllocateLocallyUniqueId( Luid );
    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }

    return( TRUE );
}

 


BOOL
APIENTRY
AccessCheck (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    HANDLE ClientToken,
    DWORD DesiredAccess,
    PGENERIC_MAPPING GenericMapping,
    PPRIVILEGE_SET PrivilegeSet,
    LPDWORD PrivilegeSetLength,
    LPDWORD GrantedAccess,
    LPBOOL AccessStatus
    )
/*++

Routine Description:

    This routine compares the input Security Descriptor against the
    input token and indicates by its return value if access is granted
    or denied.  If access is granted then the desired access mask
    becomes the granted access mask for the object.

    The semantics of the access check routine is described in the DSA
    Security Architecture workbook.  Note that during an access check
    only the discretionary ACL is examined.

Arguments:

    SecurityDescriptor - Supplies the security descriptor protecting the object
        being accessed

    ClientToken - Supplies the handle of the user's token.

    DesiredAccess - Supplies the desired access mask.

    GenericMapping - Supplies the generic mapping associated with this
        object type.

    PrivilegeSet - A pointer to a buffer that upon return will contain
        any privileges that were used to perform the access validation.
        If no privileges were used, the buffer will contain a privilege
        set consisting of zero privileges.

    PrivilegeSetLength - The size of the PrivilegeSet buffer in bytes.

    GrantedAccess - Returns an access mask describing the granted access.

    AccessStatus - Status value that may be returned indicating the
         reason why access was denied.  Routines should avoid hardcoding a
         return value of STATUS_ACCESS_DENIED so that a different value can
         be returned when mandatory access control is implemented.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    NTSTATUS RealStatus;

    Status = NtAccessCheck (
                pSecurityDescriptor,
                ClientToken,
                DesiredAccess,
                GenericMapping,
                PrivilegeSet,
                PrivilegeSetLength,
                GrantedAccess,
                &RealStatus
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    if ( !NT_SUCCESS( RealStatus ) ) {
        BaseSetLastNTError( RealStatus );
        *AccessStatus = FALSE;
        return( TRUE );
    }

    *AccessStatus = TRUE;
    return TRUE;
}

 


BOOL
APIENTRY
OpenProcessToken (
    HANDLE ProcessHandle,
    DWORD DesiredAccess,
    PHANDLE TokenHandle
    )
/*++

Routine Description:

    Open a token object associated with a process and return a handle
    that may be used to access that token.

Arguments:

    ProcessHandle - Specifies the process whose token is to be
        opened.

    DesiredAccess - Is an access mask indicating which access types
        are desired to the token.  These access types are reconciled
        with the Discretionary Access Control list of the token to
        determine whether the accesses will be granted or denied.

    TokenHandle - Receives the handle of the newly opened token.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = NtOpenProcessToken (
        ProcessHandle,
        DesiredAccess,
        TokenHandle
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
OpenThreadToken (
    HANDLE ThreadHandle,
    DWORD DesiredAccess,
    BOOL OpenAsSelf,
    PHANDLE TokenHandle
    )
/*++


Routine Description:

Open a token object associated with a thread and return a handle that
may be used to access that token.

Arguments:

    ThreadHandle - Specifies the thread whose token is to be opened.

    DesiredAccess - Is an access mask indicating which access types
        are desired to the token.  These access types are reconciled
        with the Discretionary Access Control list of the token to
        determine whether the accesses will be granted or denied.

    OpenAsSelf - Is a boolean value indicating whether the access should
        be made using the calling thread's current security context, which
        may be that of a client if impersonating, or using the caller's
        process-level security context.  A value of FALSE indicates the
        caller's current context should be used un-modified.  A value of
        TRUE indicates the request should be fulfilled using the process
        level security context.

        This parameter is necessary to allow a server process to open
        a client's token when the client specified IDENTIFICATION level
        impersonation.  In this case, the caller would not be able to
        open the client's token using the client's context (because you
        can't create executive level objects using IDENTIFICATION level
        impersonation).

    TokenHandle - Receives the handle of the newly opened token.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = NtOpenThreadToken (
        ThreadHandle,
        DesiredAccess,
        (BOOLEAN)OpenAsSelf,
        TokenHandle
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

BOOL
APIENTRY
GetTokenInformation (
    HANDLE TokenHandle,
    TOKEN_INFORMATION_CLASS TokenInformationClass,
    PVOID TokenInformation,
    DWORD TokenInformationLength,
    PDWORD ReturnLength
    )
/*++


Routine Description:

    Retrieve information about a specified token.

Arguments:

    TokenHandle - Provides a handle to the token to operate on.

    TokenInformationClass - The token information class about which
        to retrieve information.

    TokenInformation - The buffer to receive the requested class of
        information.  The buffer must be aligned on at least a
        longword boundary.  The actual structures returned are
        dependent upon the information class requested, as defined in
        the TokenInformationClass parameter description.

        TokenInformation Format By Information Class:

           TokenUser => TOKEN_USER data structure.  TOKEN_QUERY
           access is needed to retrieve this information about a
           token.

           TokenGroups => TOKEN_GROUPS data structure.  TOKEN_QUERY
           access is needed to retrieve this information about a
           token.

           TokenPrivileges => TOKEN_PRIVILEGES data structure.
           TOKEN_QUERY access is needed to retrieve this information
           about a token.

           TokenOwner => TOKEN_OWNER data structure.  TOKEN_QUERY
           access is needed to retrieve this information about a
           token.

           TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
           TOKEN_QUERY access is needed to retrieve this information
           about a token.

           TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
           TOKEN_QUERY access is needed to retrieve this information
           about a token.

           TokenSource => TOKEN_SOURCE data structure.
           TOKEN_QUERY_SOURCE access is needed to retrieve this
           information about a token.

           TokenType => TOKEN_TYPE data structure.
           TOKEN_QUERY access is needed to retrieve this information
           about a token.

           TokenStatistics => TOKEN_STATISTICS data structure.
           TOKEN_QUERY access is needed to retrieve this
           information about a token.

    TokenInformationLength - Indicates the length, in bytes, of the
        TokenInformation buffer.

    ReturnLength - This parameter receives the actual length of the
        requested information.  If this value is larger than that
        provided by the TokenInformationLength parameter, then the
        buffer provided to receive the requested information is not
        large enough to hold that data and no data is returned.

        If the queried class is TokenDefaultDacl and there is no
        default Dacl established for the token, then the return
        length will be returned as zero, and no data will be returned.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = NtQueryInformationToken (
        TokenHandle,
        TokenInformationClass,
        TokenInformation,
        TokenInformationLength,
        ReturnLength
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
SetTokenInformation (
    HANDLE TokenHandle,
    TOKEN_INFORMATION_CLASS TokenInformationClass,
    PVOID TokenInformation,
    DWORD TokenInformationLength
    )
/*++


Routine Description:

    Modify information in a specified token.

Arguments:

    TokenHandle - Provides a handle to the token to operate on.

    TokenInformationClass - The token information class being set.

    TokenInformation - The buffer containing the new values for the
        specified class of information.  The buffer must be aligned
        on at least a longword boundary.  The actual structures
        provided are dependent upon the information class specified,
        as defined in the TokenInformationClass parameter
        description.

        TokenInformation Format By Information Class:

           TokenUser => This value is not a valid value for this API.
           The User ID may not be replaced.

           TokenGroups => This value is not a valid value for this
           API.  The Group IDs may not be replaced.  However, groups
           may be enabled and disabled using NtAdjustGroupsToken().

           TokenPrivileges => This value is not a valid value for
           this API.  Privilege information may not be replaced.
           However, privileges may be explicitly enabled and disabled
           using the NtAdjustPrivilegesToken API.

           TokenOwner => TOKEN_OWNER data structure.
           TOKEN_ADJUST_DEFAULT access is needed to replace this
           information in a token.  The owner values that may be
           specified are restricted to the user and group IDs with an
           attribute indicating they may be assigned as the owner of
           objects.

           TokenPrimaryGroup => TOKEN_PRIMARY_GROUP data structure.
           TOKEN_ADJUST_DEFAULT access is needed to replace this
           information in a token.  The primary group values that may
           be specified are restricted to be one of the group IDs
           already in the token.

           TokenDefaultDacl => TOKEN_DEFAULT_DACL data structure.
           TOKEN_ADJUST_DEFAULT access is needed to replace this
           information in a token.  The ACL provided as a new default
           discretionary ACL is not validated for structural
           correctness or consistency.

           TokenSource => This value is not a valid value for this
           API.  The source name and context handle  may not be
           replaced.

           TokenStatistics => This value is not a valid value for this
           API.  The statistics of a token are read-only.

    TokenInformationLength - Indicates the length, in bytes, of the
        TokenInformation buffer.  This is only the length of the primary
        buffer.  All extensions of the primary buffer are self describing.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = NtSetInformationToken (
        TokenHandle,
        TokenInformationClass,
        TokenInformation,
        TokenInformationLength
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 

BOOL
APIENTRY
AdjustTokenPrivileges (
    HANDLE TokenHandle,
    BOOL DisableAllPrivileges,
    PTOKEN_PRIVILEGES NewState,
    DWORD BufferLength,
    PTOKEN_PRIVILEGES PreviousState,
    PDWORD ReturnLength
    )
/*++


Routine Description:

    This routine is used to disable or enable privileges in the
    specified token.  The absence of some of the privileges listed to
    be changed won't effect the successful modification of the
    privileges that are in the token.  The previous enabled/disabled
    state of changed privileges may optionally be capture (for
    resetting later).

    TOKEN_ADJUST_PRIVILEGES access is required to enable or disable
    privileges in a token.


Arguments:

    TokenHandle - Provides a handle to the token to operate on.

    DisableAllPrivileges - This boolean parameter may be
        used to disable all privileges assigned to the token.  If
        this parameter is specified as TRUE, then the NewState parameter is
        ignored.

    NewState - This (optional) parameter points to a TOKEN_PRIVILEGES
        data structure containing the privileges whose states are to
        be adjusted (disabled or enabled).  Only the Enabled flag of
        the attributes associated with each privilege is used.  It
        provides the new value that is to be assigned to the privilege
        in the token.

    BufferLength - This optional parameter indicates the length (in
        bytes) of the PreviousState buffer.  This value must be
        provided if the PreviousState parameter is provided.

    PreviousState - This (optional) parameter points to a buffer to
        receive the state of any privileges actually changed by this
        request.  This information is formated as a TOKEN_PRIVILEGES
        data structure which may be passed as the NewState parameter
        in a subsequent call to this routine to restore the original
        state of those privilges.  TOKEN_QUERY access is needed to use
        this parameter.

        If this buffer does not contain enough space to receive the
        complete list of modified privileges, then no privilege
        states are changed and STATUS_BUFFER_TOO_SMALL is returned.
        In this case, the ReturnLength OUT parameter will
        contain the actual number of bytes needed to hold the
        information.

    ReturnLength - Indicates the actual number of bytes needed to
        contain the previous privilege state information.  This
        parameter is ignored if the PreviousState argument is not
        passed.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = NtAdjustPrivilegesToken (
        TokenHandle,
        (BOOLEAN)DisableAllPrivileges,
        NewState,
        BufferLength,
        PreviousState,
        ReturnLength
        );

    //
    // We need to set last error even for success because that
    // is the only way to tell if the api successfully assigned
    // all privileges.  That is, STATUS_NOT_ALL_ASSIGNED is a
    // Success severity level.
    //

    BaseSetLastNTError(Status);


    if ( !NT_SUCCESS(Status) ) {
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
AdjustTokenGroups (
    HANDLE TokenHandle,
    BOOL ResetToDefault,
    PTOKEN_GROUPS NewState,
    DWORD BufferLength,
    PTOKEN_GROUPS PreviousState,
    PDWORD ReturnLength
    )
/*++


Routine Description:

    This routine is used to disable or enable groups in the specified
    token.  The absence of some of the groups listed to be changed
    won't effect the successful modification of the groups that are in
    the token.  The previous enabled/disabled state of changed groups
    may optionally be capture (for resetting later).

    TOKEN_ADJUST_GROUPS access is required to enable or disable groups
    in a token

    Note that mandatory groups can not be disabled.  An attempt
    disable any mandatory groups will cause the call to fail, leaving
    the state of all groups unchanged.


Arguments:

    TokenHandle - Provides a handle to the token to operate on.

    ResetToDefault - The parameter indicates whether all the groups
        in the token are to be reset to their default enabled/disabled
        state.

    NewState - This parameter points to a TOKEN_GROUPS data structure
        containing the groups whose states are to be adjusted
        (disabled or enabled).  Only the Enabled flag of the
        attributes associated with each group is used.  It provides
        the new value that is to be assigned to the group in the
        token.  If the ResetToDefault argument is specified as TRUE,
        then this argument is ignored.  Otherwise, it must be passed.

    BufferLength - This optional parameter indicates the length (in
        bytes) of the PreviousState buffer.  This value must be
        provided if the PreviousState parameter is provided.

    PreviousState - This (optional) parameter points to a buffer to
        receive the state of any groups actually changed by this
        request.  This information is formated as a TOKEN_GROUPS data
        structure which may be passed as the NewState parameter in a
        subsequent call to NtAdjustGroups to restore the original state
        of those groups.  TOKEN_QUERY access is needed to use this
        parameter.

        If this buffer does not contain enough space to receive the
        complete list of modified groups, then no group states are
        changed and STATUS_BUFFER_TOO_SMALL is returned.  In this
        case, the ReturnLength return parameter will contain the
        actual number of bytes needed to hold the information.

    ReturnLength - Indicates the actual number of bytes needed to
        contain the previous group state information.
        This parameter is ignored if the PreviousState argument is not
        passed.


Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = NtAdjustGroupsToken (
        TokenHandle,
        (BOOLEAN)ResetToDefault,
        NewState,
        BufferLength,
        PreviousState,
        ReturnLength
        );

    //
    // We need to set last error even for success because that
    // is the only way to tell if the api successfully assigned
    // all groups.  That is, STATUS_NOT_ALL_ASSIGNED is a
    // Success severity level.
    //

    BaseSetLastNTError(Status);


    if ( !NT_SUCCESS(Status) ) {
        return FALSE;
    }

    return TRUE;

}

 

 

BOOL
APIENTRY
PrivilegeCheck (
    HANDLE ClientToken,
    PPRIVILEGE_SET RequiredPrivileges,
    LPBOOL pfResult
    )
/*++

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 SeSecurityPrivilege 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.

    pfResult - 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:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    BOOLEAN Result;

    Status = NtPrivilegeCheck (
                ClientToken,
                RequiredPrivileges,
                &Result
                );

    *pfResult = Result;

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 

BOOL
APIENTRY
AccessCheckAndAuditAlarmW(
    LPCWSTR SubsystemName,
    PVOID HandleId,
    LPWSTR ObjectTypeName,
    LPWSTR ObjectName,
    PSECURITY_DESCRIPTOR SecurityDescriptor,
    DWORD DesiredAccess,
    PGENERIC_MAPPING GenericMapping,
    BOOL ObjectCreation,
    LPDWORD GrantedAccess,
    LPBOOL AccessStatus,
    LPBOOL pfGenerateOnClose
    )
/*++

Routine Description:

    This routine compares the input Security Descriptor against the
    caller's impersonation token and indicates if access is granted or
    denied.  If access is granted then the desired access mask becomes
    the granted access mask for the object.  The semantics of the
    access check routine is described in the DSA Security Architecture
    workbook.

    This routine will also generate any necessary audit messages as a
    result of the access attempt.

Arguments:

    SubsystemName - Supplies a name string identifying the subsystem
        calling the routine.

    HandleId - A unique value that will be used to represent the client's
        handle to the object.  This value is ignored (and may be re-used)
        if the access is denied.

    ObjectTypeName - Supplies the name of the type of the object being
        created or accessed.

    ObjectName - Supplies the name of the object being created or accessed.

    SecurityDescriptor - A pointer to the Security Descriptor against which
        acccess is to be checked.

    DesiredAccess - The desired acccess mask.  This mask must have been
        previously mapped to contain no generic accesses.

    GenericMapping - Supplies a pointer to the generic mapping associated
        with this object type.

    ObjectCreation - A boolean flag indicated whether the access will
        result in a new object being created if granted.  A value of TRUE
        indicates an object will be created, FALSE indicates an existing
        object will be opened.

    GrantedAccess - Receives a masking indicating which accesses have been
        granted (only valid on success).

    AccessStatus - Receives an indication of the success or failure of the
        access check.  If access is granted, STATUS_SUCCESS is returned.
        If access is denied, a value appropriate for return to the client
        is returned.  This will be STATUS_ACCESS_DENIED or, when mandatory
        access controls are implemented, STATUS_OBJECT_NOT_FOUND.

    pfGenerateOnClose - Points to a boolean that is set by the audity
        generation routine and must be passed to ObjectCloseAuditAlarm
        when the object handle is closed.


Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    NTSTATUS RealAccessStatus;
    BOOLEAN GenerateOnClose;
    UNICODE_STRING Subsystem;
    UNICODE_STRING ObjectType;
    UNICODE_STRING Object;


    RtlInitUnicodeString(
        &Subsystem,
        SubsystemName
        );

    RtlInitUnicodeString(
        &ObjectType,
        ObjectTypeName
        );

    RtlInitUnicodeString(
        &Object,
        ObjectName
        );

    Status = NtAccessCheckAndAuditAlarm (
                &Subsystem,
                HandleId,
                &ObjectType,
                &Object,
                SecurityDescriptor,
                DesiredAccess,
                GenericMapping,
                (BOOLEAN)ObjectCreation,
                GrantedAccess,
                &RealAccessStatus,
                &GenerateOnClose
                );


    *pfGenerateOnClose = (BOOL)GenerateOnClose;

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    if ( !NT_SUCCESS( RealAccessStatus )) {
        *AccessStatus = FALSE;
        BaseSetLastNTError( RealAccessStatus );
        return( TRUE );
    }

    *AccessStatus = TRUE;
    return TRUE;
}

 

BOOL
APIENTRY
AccessCheckAndAuditAlarmA (
    LPCSTR SubsystemName,
    PVOID HandleId,
    LPSTR ObjectTypeName,
    LPSTR ObjectName,
    PSECURITY_DESCRIPTOR SecurityDescriptor,
    DWORD DesiredAccess,
    PGENERIC_MAPPING GenericMapping,
    BOOL ObjectCreation,
    LPDWORD GrantedAccess,
    LPBOOL AccessStatus,
    LPBOOL pfGenerateOnClose
    )
/*++

Routine Description:

    ANSI Thunk to AccessCheckAndAuditAlarmW

--*/
{
    PUNICODE_STRING ObjectNameW;
    ANSI_STRING AnsiString;
    UNICODE_STRING SubsystemNameW;
    UNICODE_STRING ObjectTypeNameW;
    NTSTATUS Status;
    BOOL RVal;


    ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;


    RtlInitAnsiString(&AnsiString,SubsystemName);
    Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);

    if ( !NT_SUCCESS(Status) ) {

        BaseSetLastNTError(Status);
        return FALSE;
    }

 

    RtlInitAnsiString(&AnsiString,ObjectTypeName);
    Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);

    if ( !NT_SUCCESS(Status) ) {

        RtlFreeUnicodeString( &SubsystemNameW );

        BaseSetLastNTError(Status);
        return FALSE;
    }


    //
    // Convert the object name string, but don't allocate memory to
    // do it, since we've got the space in the TEB available.
    //

    RtlInitAnsiString(&AnsiString,ObjectName);
    Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);

    if ( !NT_SUCCESS(Status) ) {

        RtlFreeUnicodeString( &SubsystemNameW );
        RtlFreeUnicodeString( &ObjectTypeNameW );

        BaseSetLastNTError(Status);
        return FALSE;
    }


    RVal =  AccessCheckAndAuditAlarmW (
                (LPCWSTR)SubsystemNameW.Buffer,
                HandleId,
                ObjectTypeNameW.Buffer,
                ObjectNameW->Buffer,
                SecurityDescriptor,
                DesiredAccess,
                GenericMapping,
                ObjectCreation,
                GrantedAccess,
                AccessStatus,
                pfGenerateOnClose
                );


    RtlFreeUnicodeString( &SubsystemNameW );
    RtlFreeUnicodeString( &ObjectTypeNameW );

    return( RVal );
}


BOOL
APIENTRY
ObjectOpenAuditAlarmA (
    LPCSTR SubsystemName,
    PVOID HandleId,
    LPSTR ObjectTypeName,
    LPSTR ObjectName,
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    HANDLE ClientToken,
    DWORD DesiredAccess,
    DWORD GrantedAccess,
    PPRIVILEGE_SET Privileges OPTIONAL,
    BOOL ObjectCreation,
    BOOL AccessGranted,
    LPBOOL GenerateOnClose
    )
/*++

Routine Description:

    ANSI Thunk to ObjectOpenAuditAlarmW

--*/
{
    PUNICODE_STRING ObjectNameW;
    ANSI_STRING AnsiString;
    UNICODE_STRING SubsystemNameW;
    UNICODE_STRING ObjectTypeNameW;
    NTSTATUS Status;
    BOOL RVal;


    ObjectNameW = &NtCurrentTeb()->StaticUnicodeString;


    RtlInitAnsiString(&AnsiString,SubsystemName);
    Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);

    if ( !NT_SUCCESS(Status) ) {

        BaseSetLastNTError(Status);
        return FALSE;
    }

 

    RtlInitAnsiString(&AnsiString,ObjectTypeName);
    Status = RtlAnsiStringToUnicodeString(&ObjectTypeNameW,&AnsiString,TRUE);

    if ( !NT_SUCCESS(Status) ) {

        RtlFreeUnicodeString( &SubsystemNameW );

        BaseSetLastNTError(Status);
        return FALSE;
    }


    //
    // Convert the object name string, but don't allocate memory to
    // do it, since we've got the space in the TEB available.
    //

    RtlInitAnsiString(&AnsiString,ObjectName);
    Status = RtlAnsiStringToUnicodeString(ObjectNameW,&AnsiString,FALSE);

    if ( !NT_SUCCESS(Status) ) {

        RtlFreeUnicodeString( &SubsystemNameW );
        RtlFreeUnicodeString( &ObjectTypeNameW );

        BaseSetLastNTError(Status);
        return FALSE;
    }

    RVal = ObjectOpenAuditAlarmW (
               (LPCWSTR)SubsystemNameW.Buffer,
               HandleId,
               ObjectTypeNameW.Buffer,
               ObjectNameW->Buffer,
               pSecurityDescriptor,
               ClientToken,
               DesiredAccess,
               GrantedAccess,
               Privileges,
               ObjectCreation,
               AccessGranted,
               GenerateOnClose
               );

    RtlFreeUnicodeString( &SubsystemNameW );
    RtlFreeUnicodeString( &ObjectTypeNameW );

    return( RVal );

}

 

BOOL
APIENTRY
ObjectOpenAuditAlarmW (
    LPCWSTR SubsystemName,
    PVOID HandleId,
    LPWSTR ObjectTypeName,
    LPWSTR ObjectName,
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    HANDLE ClientToken,
    DWORD DesiredAccess,
    DWORD GrantedAccess,
    PPRIVILEGE_SET Privileges OPTIONAL,
    BOOL ObjectCreation,
    BOOL AccessGranted,
    LPBOOL GenerateOnClose
    )
/*++

    Routine Description:

    This routine is used to generate audit and alarm messages when an
    attempt is made to access an existing protected subsystem object or
    create a new one.  This routine may result in several messages being
    generated and sent to Port objects.  This may result in a significant
    latency before returning.  Design of routines that must call this
    routine must take this potential latency into account.  This may have
    an impact on the approach taken for data structure mutex locking, for
    example.

    This routine may not be able to generate a complete audit record
    due to memory restrictions.

    This API requires the caller have SeSecurityPrivilege privilege.
    The test for this privilege is always against the primary token of
    the calling process, not the impersonation token of the thread.

Arguments:

    SubsystemName - Supplies a name string identifying the
        subsystem calling the routine.

    HandleId - A unique value representing the client's handle to the
        object.  If the access attempt was not successful (AccessGranted is
        FALSE), then this parameter is ignored.

    ObjectTypeName - Supplies the name of the type of object being
        accessed.

    ObjectName - Supplies the name of the object the client
        accessed or attempted to access.

    pSecurityDescriptor - An optional pointer to the security
        descriptor of the object being accessed.

    ClientToken - A handle to a token object representing the client that
        requested the operation.  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.

    DesiredAccess - The desired access mask.  This mask must have been
        previously mapped to contain no generic accesses.

    GrantedAccess - The mask of accesses that were actually granted.

    Privileges - Optionally points to a set of privileges that were
        required for the access attempt.  Those privileges that were held
        by the subject are marked using the UsedForAccess flag of the
        attributes associated with each privilege.

    ObjectCreation - A boolean flag indicating whether the access will
        result in a new object being created if granted.  A value of TRUE
        indicates an object will be created, FALSE indicates an existing
        object will be opened.

    AccessGranted - Indicates whether the requested access was granted or
        not.  A value of TRUE indicates the access was granted.  A value of
        FALSE indicates the access was not granted.

    GenerateOnClose - Points to a boolean that is set by the audit
        generation routine and must be passed to NtCloseObjectAuditAlarm()
        when the object handle is closed.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    UNICODE_STRING Subsystem;
    UNICODE_STRING ObjectType;
    UNICODE_STRING Object;


    RtlInitUnicodeString(
        &Subsystem,
        SubsystemName
        );

    RtlInitUnicodeString(
        &ObjectType,
        ObjectTypeName
        );

    RtlInitUnicodeString(
        &Object,
        ObjectName
        );

    Status = NtOpenObjectAuditAlarm (
                &Subsystem,
                &HandleId,
                &ObjectType,
                &Object,
                pSecurityDescriptor,
                ClientToken,
                DesiredAccess,
                GrantedAccess,
                Privileges,
                (BOOLEAN)ObjectCreation,
                (BOOLEAN)AccessGranted,
                (PBOOLEAN)GenerateOnClose
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 

BOOL
APIENTRY
ObjectPrivilegeAuditAlarmA (
    LPCSTR SubsystemName,
    PVOID HandleId,
    HANDLE ClientToken,
    DWORD DesiredAccess,
    PPRIVILEGE_SET Privileges,
    BOOL AccessGranted
    )
/*++

Routine Description:

    ANSI Thunk to ObjectPrivilegeAuditAlarmW

--*/
{
    PUNICODE_STRING SubsystemNameW;
    ANSI_STRING AnsiString;
    NTSTATUS Status;
    BOOL RVal;

    SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;

    //
    // Convert the object name string, but don't allocate memory to
    // do it, since we've got the space in the TEB available.
    //

    RtlInitAnsiString(&AnsiString,SubsystemName);
    Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);

    if ( !NT_SUCCESS(Status) ) {

        BaseSetLastNTError(Status);
        return FALSE;
    }

    RVal = ObjectPrivilegeAuditAlarmW (
                (LPCWSTR)SubsystemNameW->Buffer,
                HandleId,
                ClientToken,
                DesiredAccess,
                Privileges,
                AccessGranted
                );

    return( RVal );
}

 


BOOL
APIENTRY
ObjectPrivilegeAuditAlarmW (
    LPCWSTR SubsystemName,
    PVOID HandleId,
    HANDLE ClientToken,
    DWORD DesiredAccess,
    PPRIVILEGE_SET Privileges,
    BOOL AccessGranted
    )
/*++

Routine Description:

    This routine is used to generate audit and alarm messages when an
    attempt is made to perform privileged operations on a protected
    subsystem object after the object is already opened.  This routine
    may result in several messages being generated and sent to Port
    objects.  This may result in a significant latency before
    returning.  Design of routines that must call this routine must
    take this potential latency into account.  This may have an impact
    on the approach taken for data structure mutex locking, for
    example.

    This API requires the caller have SeSecurityPrivilege privilege.
    The test for this privilege is always against the primary token of
    the calling process, allowing the caller to be impersonating a
    client during the call with no ill effects.

Arguments:

    SubsystemName - Supplies a name string identifying the subsystem
        calling the routine.

    HandleId - A unique value representing the client's handle to the
        object.

    ClientToken - A handle to a token object representing the client that
        requested the operation.  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.

    DesiredAccess - The desired access mask.  This mask must have been
        previously mapped to contain no generic accesses.

    Privileges - The set of privileges required for the requested
        operation.  Those privileges that were held by the subject are
        marked using the UsedForAccess flag of the attributes
        associated with each privilege.

    AccessGranted - Indicates whether the requested access was granted or
        not.  A value of TRUE indicates the access was granted.  A value of
        FALSE indicates the access was not granted.

Return value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    UNICODE_STRING Subsystem;

    RtlInitUnicodeString(
        &Subsystem,
        SubsystemName
        );

    Status = NtPrivilegeObjectAuditAlarm (
        &Subsystem,
        HandleId,
        ClientToken,
        DesiredAccess,
        Privileges,
        (BOOLEAN)AccessGranted
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}


BOOL
APIENTRY
ObjectCloseAuditAlarmA (
    LPCSTR SubsystemName,
    PVOID HandleId,
    BOOL GenerateOnClose
    )
/*++

Routine Description:

    ANSI Thunk to ObjectCloseAuditAlarmW

--*/
{
    PUNICODE_STRING SubsystemNameW;
    NTSTATUS Status;
    ANSI_STRING AnsiString;

    SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;

    //
    // Convert the object name string, but don't allocate memory to
    // do it, since we've got the space in the TEB available.
    //

    RtlInitAnsiString(&AnsiString,SubsystemName);
    Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);

    if ( !NT_SUCCESS(Status) ) {

        BaseSetLastNTError(Status);
        return FALSE;
    }

    return ObjectCloseAuditAlarmW (
               (LPCWSTR)SubsystemNameW->Buffer,
               HandleId,
               GenerateOnClose
               );


}

BOOL
APIENTRY
ObjectCloseAuditAlarmW (
    LPCWSTR SubsystemName,
    PVOID HandleId,
    BOOL GenerateOnClose
    )
/*++

Routine Description:

    This routine is used to generate audit and alarm messages when a handle
    to a protected subsystem object is deleted.  This routine may result in
    several messages being generated and sent to Port objects.  This may
    result in a significant latency before returning.  Design of routines
    that must call this routine must take this potential latency into
    account.  This may have an impact on the approach taken for data
    structure mutex locking, for example.

    This API requires the caller have SeSecurityPrivilege privilege.  The test
    for this privilege is always against the primary token of the calling
    process, allowing the caller to be impersonating a client during the
    call with no ill effects.

Arguments:

    SubsystemName - Supplies a name string identifying the subsystem
        calling the routine.

    HandleId - A unique value representing the client's handle to the
        object.

    GenerateOnClose - Is a boolean value returned from a corresponding
        AccessCheckAndAuditAlarm() call or ObjectOpenAuditAlarm() call
        when the object handle was created.

Return value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.


--*/
{
    NTSTATUS Status;
    UNICODE_STRING Subsystem;

    RtlInitUnicodeString( &Subsystem, SubsystemName );

    Status = NtCloseObjectAuditAlarm (
        &Subsystem,
        HandleId,
        (BOOLEAN)GenerateOnClose
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}


BOOL
APIENTRY
ObjectDeleteAuditAlarmA (
    LPCSTR SubsystemName,
    PVOID HandleId,
    BOOL GenerateOnClose
    )
/*++

Routine Description:

    ANSI Thunk to ObjectDeleteAuditAlarmW

--*/
{
    PUNICODE_STRING SubsystemNameW;
    NTSTATUS Status;
    ANSI_STRING AnsiString;

    SubsystemNameW = &NtCurrentTeb()->StaticUnicodeString;

    //
    // Convert the object name string, but don't allocate memory to
    // do it, since we've got the space in the TEB available.
    //

    RtlInitAnsiString(&AnsiString,SubsystemName);
    Status = RtlAnsiStringToUnicodeString(SubsystemNameW,&AnsiString,FALSE);

    if ( !NT_SUCCESS(Status) ) {

        BaseSetLastNTError(Status);
        return FALSE;
    }

    return ObjectDeleteAuditAlarmW (
               (LPCWSTR)SubsystemNameW->Buffer,
               HandleId,
               GenerateOnClose
               );


}

BOOL
APIENTRY
ObjectDeleteAuditAlarmW (
    LPCWSTR SubsystemName,
    PVOID HandleId,
    BOOL GenerateOnClose
    )
/*++

Routine Description:

    This routine is used to generate audit and alarm messages when an object
    in a protected subsystem is deleted.  This routine may result in
    several messages being generated and sent to Port objects.  This may
    result in a significant latency before returning.  Design of routines
    that must call this routine must take this potential latency into
    account.  This may have an impact on the approach taken for data
    structure mutex locking, for example.

    This API requires the caller have SeSecurityPrivilege privilege.  The test
    for this privilege is always against the primary token of the calling
    process, allowing the caller to be impersonating a client during the
    call with no ill effects.

Arguments:

    SubsystemName - Supplies a name string identifying the subsystem
        calling the routine.

    HandleId - A unique value representing the client's handle to the
        object.

    GenerateOnClose - Is a boolean value returned from a corresponding
        AccessCheckAndAuditAlarm() call or ObjectOpenAuditAlarm() call
        when the object handle was created.

Return value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.


--*/
{
    NTSTATUS Status;
    UNICODE_STRING Subsystem;

    RtlInitUnicodeString( &Subsystem, SubsystemName );

    Status = NtDeleteObjectAuditAlarm (
        &Subsystem,
        HandleId,
        (BOOLEAN)GenerateOnClose
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 

BOOL
APIENTRY
PrivilegedServiceAuditAlarmA (
    LPCSTR SubsystemName,
    LPCSTR ServiceName,
    HANDLE ClientToken,
    PPRIVILEGE_SET Privileges,
    BOOL AccessGranted
    )
/*++

Routine Description:

    ANSI Thunk to PrivilegedServiceAuditAlarmW

--*/
{
    PUNICODE_STRING ServiceNameW;
    UNICODE_STRING SubsystemNameW;
    ANSI_STRING  AnsiString;
    NTSTATUS Status;
    BOOL RVal;

    ServiceNameW = &NtCurrentTeb()->StaticUnicodeString;

    //
    // Convert the object name string, but don't allocate memory to
    // do it, since we've got the space in the TEB available.
    //

    RtlInitAnsiString(&AnsiString,ServiceName);
    Status = RtlAnsiStringToUnicodeString(ServiceNameW,&AnsiString,FALSE);

    if ( !NT_SUCCESS(Status) ) {

        BaseSetLastNTError(Status);
        return FALSE;
    }

    RtlInitAnsiString(&AnsiString,SubsystemName);
    Status = RtlAnsiStringToUnicodeString(&SubsystemNameW,&AnsiString,TRUE);

    if ( !NT_SUCCESS(Status) ) {

        BaseSetLastNTError(Status);
        return FALSE;
    }

    RVal =  PrivilegedServiceAuditAlarmW (
                (LPCWSTR)SubsystemNameW.Buffer,
                (LPCWSTR)ServiceNameW->Buffer,
                ClientToken,
                Privileges,
                AccessGranted
                );

    RtlFreeUnicodeString( &SubsystemNameW );

    return( RVal );

}

BOOL
APIENTRY
PrivilegedServiceAuditAlarmW (
    LPCWSTR SubsystemName,
    LPCWSTR ServiceName,
    HANDLE ClientToken,
    PPRIVILEGE_SET Privileges,
    BOOL AccessGranted
    )
/*++

Routine Description:

    This routine is used to generate audit and alarm messages when an
    attempt is made to perform privileged system service operations.  This
    routine may result in several messages being generated and sent to Port
    objects.  This may result in a significant latency before returning.
    Design of routines that must call this routine must take this potential
    latency into account.  This may have an impact on the approach taken
    for data structure mutex locking, for example.

    This API requires the caller have SeSecurityPrivilege privilege.  The test
    for this privilege is always against the primary token of the calling
    process, allowing the caller to be impersonating a client during the
    call with no ill effects

Arguments:

    SubsystemName - Supplies a name string identifying the subsystem
        calling the routine.

    ServiceName - Supplies a name of the privileged subsystem service.  For
        example, "RESET RUNTIME LOCAL SECURITY POLICY" might be specified
        by a Local Security Authority service used to update the local
        security policy database.

    ClientToken - A handle to a token object representing the client that
        requested the operation.  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.

    Privileges - Points to a set of privileges required to perform the
        privileged operation.  Those privileges that were held by the
        subject are marked using the UsedForAccess flag of the
        attributes associated with each privilege.

    AccessGranted - Indicates whether the requested access was granted or
        not.  A value of TRUE indicates the access was granted.  A value of
        FALSE indicates the access was not granted.


Return value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.


--*/
{
    NTSTATUS Status;
    UNICODE_STRING Subsystem;
    UNICODE_STRING Service;

    RtlInitUnicodeString( &Subsystem, SubsystemName );

    RtlInitUnicodeString( &Service, ServiceName );

    Status = NtPrivilegedServiceAuditAlarm (
        &Subsystem,
        &Service,
        ClientToken,
        Privileges,
        (BOOLEAN)AccessGranted
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
IsValidSid (
    PSID pSid
    )
/*++

Routine Description:

    This procedure validates an SID's structure.

Arguments:

    pSid - Pointer to the SID structure to validate.

Return Value:

    BOOLEAN - TRUE if the structure of pSid is valid.

--*/
{
    return (BOOL) RtlValidSid (
                      pSid
                      );
}

 


BOOL
APIENTRY
EqualSid (
    PSID pSid1,
    PSID pSid2
    )
/*++

Routine Description:

    This procedure tests two SID values for equality.

Arguments:

    pSid1, pSid2 - Supply pointers to the two SID values to compare.
        The SID structures are assumed to be valid.

Return Value:

    BOOLEAN - TRUE if the value of pSid1 is equal to pSid2, and FALSE
        otherwise.

--*/
{
    return (BOOL) RtlEqualSid (
                    pSid1,
                    pSid2
                    );
}

 


BOOL
APIENTRY
EqualPrefixSid (
    PSID pSid1,
    PSID pSid2
    )
/*++

Routine Description:

    This procedure tests two SID prefix values for equality.

    An SID prefix is the entire SID except for the last sub-authority
    value.

Arguments:

    pSid1, pSid2 - Supply pointers to the two SID values to compare.
        The SID structures are assumed to be valid.

Return Value:

    BOOLEAN - TRUE if the prefix value of pSid1 is equal to pSid2, and
        FALSE otherwise.

--*/
{
    return (BOOL) RtlEqualPrefixSid (
                    pSid1,
                    pSid2
                    );
}

 


DWORD
APIENTRY
GetSidLengthRequired (
    UCHAR nSubAuthorityCount
    )
/*++

Routine Description:

    This routine returns the length, in bytes, required to store an SID
    with the specified number of Sub-Authorities.

Arguments:

    nSubAuthorityCount - The number of sub-authorities to be stored in
        the SID.

Return Value:

    DWORD - The length, in bytes, required to store the SID.

--*/
{
    return RtlLengthRequiredSid (
                nSubAuthorityCount
                );
}

 

BOOL
APIENTRY
InitializeSid (
    PSID Sid,
    PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
    BYTE nSubAuthorityCount
    )

/*++

Routine Description:

    This function initializes an SID data structure.  It does not,
    however, set the sub-authority values.  This must be done
    separately.

Arguments:

    Sid - Pointer to the SID data structure to initialize.

    pIdentifierAuthority - Pointer to the Identifier Authority value
        to set in the SID.

    nSubAuthorityCount - The number of sub-authorities that will be
        placed in the SID (a separate action).

Return Value:

    None

--*/
{
    NTSTATUS Status;

    Status = RtlInitializeSid (
                Sid,
                pIdentifierAuthority,
                nSubAuthorityCount
                );

    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }

    return( TRUE );
}

 

PVOID
APIENTRY
FreeSid(
    PSID pSid
    )

/*++

Routine Description:

    This function is used to free a SID previously allocated using
    AllocateAndInitializeSid().


Arguments:

    Sid - Pointer to the SID to free.

Return Value:

    None.


--*/
{
    return(RtlFreeSid( pSid ));
}

 

BOOL
APIENTRY
AllocateAndInitializeSid (
    PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority,
    BYTE nSubAuthorityCount,
    DWORD nSubAuthority0,
    DWORD nSubAuthority1,
    DWORD nSubAuthority2,
    DWORD nSubAuthority3,
    DWORD nSubAuthority4,
    DWORD nSubAuthority5,
    DWORD nSubAuthority6,
    DWORD nSubAuthority7,
    PSID *pSid
    )

/*++

Routine Description:

    This function allocates and initializes a sid with the specified
    number of sub-authorities (up to 8).  A sid allocated with this
    routine must be freed using FreeSid().


Arguments:

    pIdentifierAuthority - Pointer to the Identifier Authority value to
        set in the SID.

    nSubAuthorityCount - The number of sub-authorities to place in the SID.
        This also identifies how many of the SubAuthorityN parameters
        have meaningful values.  This must contain a value from 0 through
        8.

    nSubAuthority0-7 - Provides the corresponding sub-authority value to
        place in the SID.  For example, a SubAuthorityCount value of 3
        indicates that SubAuthority0, SubAuthority1, and SubAuthority0
        have meaningful values and the rest are to be ignored.

    Sid - Receives a pointer to the allocated and initialized SID data
        structure.

Return Value:


    ERROR_NO_MEMORY - The attempt to allocate memory for the SID
        failed.

    ERROR_INVALID_SID - The number of sub-authorities specified did
        not fall in the valid range for this api (0 through 8).

--*/
{
    NTSTATUS Status;

    Status = RtlAllocateAndInitializeSid (
                 pIdentifierAuthority,
                 (UCHAR)nSubAuthorityCount,
                 (ULONG)nSubAuthority0,
                 (ULONG)nSubAuthority1,
                 (ULONG)nSubAuthority2,
                 (ULONG)nSubAuthority3,
                 (ULONG)nSubAuthority4,
                 (ULONG)nSubAuthority5,
                 (ULONG)nSubAuthority6,
                 (ULONG)nSubAuthority7,
                 pSid
                 );

    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }

    return( TRUE );
}

 


PSID_IDENTIFIER_AUTHORITY
GetSidIdentifierAuthority (
    PSID pSid
    )
/*++

Routine Description:

    This function returns the address of an SID's IdentifierAuthority field.

Arguments:

    Sid - Pointer to the SID data structure.

Return Value:

    Address of an SID's Identifier Authority field.

--*/
{
    return RtlIdentifierAuthoritySid (
               pSid
               );
}

 


PDWORD
GetSidSubAuthority (
    PSID pSid,
    DWORD nSubAuthority
    )
/*++

Routine Description:

    This function returns the address of a sub-authority array element of
    an SID.

Arguments:

    pSid - Pointer to the SID data structure.

    nSubAuthority - An index indicating which sub-authority is being
        specified.  This value is not compared against the number of
        sub-authorities in the SID for validity.

Return Value:

    Address of a relative ID within the SID.

--*/
{
    return RtlSubAuthoritySid (
               pSid,
               nSubAuthority
               );
}

PUCHAR
GetSidSubAuthorityCount (
    PSID pSid
    )
/*++

Routine Description:

    This function returns the address of the sub-authority count field of
    an SID.

Arguments:

    pSid - Pointer to the SID data structure.

Return Value:

    Address of the sub-authority count field of an SID.


--*/
{
    return RtlSubAuthorityCountSid (
               pSid
               );
}

 

DWORD
APIENTRY
GetLengthSid (
    PSID pSid
    )
/*++

Routine Description:

    This routine returns the length, in bytes, of a structurally valid SID.

Arguments:

    pSid - Points to the SID whose length is to be returned.  The
        SID's structure is assumed to be valid.

Return Value:

    DWORD - The length, in bytes, of the SID.

--*/
{
    return RtlLengthSid (
                pSid
                );
}

 

BOOL
APIENTRY
CopySid (
    DWORD nDestinationSidLength,
    PSID pDestinationSid,
    PSID pSourceSid
    )
/*++

Routine Description:

    This routine copies the value of the source SID to the destination
    SID.

Arguments:

    nDestinationSidLength - Indicates the length, in bytes, of the
        destination SID buffer.

    pDestinationSid - Pointer to a buffer to receive a copy of the
        source Sid value.

    pSourceSid - Supplies the Sid value to be copied.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlCopySid (
                nDestinationSidLength,
                pDestinationSid,
                pSourceSid
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
AreAllAccessesGranted (
    DWORD GrantedAccess,
    DWORD DesiredAccess
    )
/*++

Routine Description:

    This routine is used to check a desired access mask against a
    granted access mask.

Arguments:

        GrantedAccess - Specifies the granted access mask.

        DesiredAccess - Specifies the desired access mask.

Return Value:

    BOOL - TRUE if the GrantedAccess mask has all the bits set that
        the DesiredAccess mask has set.  That is, TRUE is returned if
        all of the desired accesses have been granted.

--*/
{
    return (BOOL) RtlAreAllAccessesGranted (
        GrantedAccess,
        DesiredAccess
        );
}

 


BOOL
APIENTRY
AreAnyAccessesGranted (
    DWORD GrantedAccess,
    DWORD DesiredAccess
    )
/*++

Routine Description:

    This routine is used to test whether any of a set of desired
    accesses are granted by a granted access mask.

Arguments:

        GrantedAccess - Specifies the granted access mask.

        DesiredAccess - Specifies the desired access mask.

Return Value:

    BOOL - TRUE if the GrantedAccess mask contains any of the bits
        specified in the DesiredAccess mask.  That is, if any of the
        desired accesses have been granted, TRUE is returned.


--*/
{
    return (BOOL) RtlAreAnyAccessesGranted (
        GrantedAccess,
        DesiredAccess
        );
}

 


VOID
APIENTRY
MapGenericMask (
    PDWORD AccessMask,
    PGENERIC_MAPPING GenericMapping
    )
/*++

Routine Description:

    This routine maps all generic accesses in the provided access mask
    to specific and standard accesses according to the provided
    GenericMapping.  The resulting mask will not have any of the
    generic bits set (GenericRead, GenericWrite, GenericExecute, or
    GenericAll) or any undefined bits set, but may have any other bit
    set.  If bits other than the generic bits are provided on input,
    they will not be cleared bt the mapping.

Arguments:

    AccessMask - Points to the access mask to be mapped.

    GenericMapping - The mapping of generic to specific and standard
        access types.

Return Value:

    None.

--*/
{
    RtlMapGenericMask (
        AccessMask,
        GenericMapping
        );
}

 

BOOL
APIENTRY
IsValidAcl (
    PACL pAcl
    )
/*++

Routine Description:

    This procedure validates an ACL.

    This involves validating the revision level of the ACL and ensuring
    that the number of ACEs specified in the AceCount fit in the space
    specified by the AclSize field of the ACL header.

Arguments:

    pAcl - Pointer to the ACL structure to validate.

Return Value:

    BOOLEAN - TRUE if the structure of Acl is valid.


--*/
{
    return (BOOL) RtlValidAcl (
                    pAcl
                    );
}

 


BOOL
APIENTRY
InitializeAcl (
    PACL pAcl,
    DWORD nAclLength,
    DWORD dwAclRevision
    )
/*++

Routine Description:

    InitializeAcl creates a new ACL in the caller supplied memory
    buffer.  The ACL contains zero ACEs; therefore, it is an empty ACL
    as opposed to a nonexistent ACL.  That is, if the ACL is now set
    to an object it will implicitly deny access to everyone.

Arguments:

    pAcl - Supplies the buffer containing the ACL being initialized

    nAclLength - Supplies the length of the ace buffer in bytes

    dwAclRevision - Supplies the revision for this Acl

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlCreateAcl (
                pAcl,
                nAclLength,
                dwAclRevision
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 

BOOL
APIENTRY
GetAclInformation (
    PACL pAcl,
    PVOID pAclInformation,
    DWORD nAclInformationLength,
    ACL_INFORMATION_CLASS dwAclInformationClass
    )
/*++

Routine Description:

    This routine returns to the caller information about an ACL.  The requested
    information can be AclRevisionInformation, or AclSizeInformation.

Arguments:

    pAcl - Supplies the Acl being examined

    pAclInformation - Supplies the buffer to receive the information
        being requested

    nAclInformationLength - Supplies the length of the AclInformation
        buffer in bytes

    dwAclInformationClass - Supplies the type of information being
        requested

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlQueryInformationAcl (
                pAcl,
                pAclInformation,
                nAclInformationLength,
                dwAclInformationClass
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
SetAclInformation (
    PACL pAcl,
    PVOID pAclInformation,
    DWORD nAclInformationLength,
    ACL_INFORMATION_CLASS dwAclInformationClass
    )
/*++

Routine Description:

    This routine sets the state of an ACL.  For now only the revision
    level can be set and for now only a revision level of 1 is accepted
    so this procedure is rather simple

Arguments:

    pAcl - Supplies the Acl being altered

    pAclInformation - Supplies the buffer containing the information
        being set

    nAclInformationLength - Supplies the length of the Acl information
        buffer

    dwAclInformationClass - Supplies the type of information begin set

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlSetInformationAcl (
                pAcl,
                pAclInformation,
                nAclInformationLength,
                dwAclInformationClass
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

BOOL
APIENTRY
AddAce (
    PACL pAcl,
    DWORD dwAceRevision,
    DWORD dwStartingAceIndex,
    PVOID pAceList,
    DWORD nAceListLength
    )
/*++

Routine Description:

    This routine adds a string of ACEs to an ACL.

Arguments:

    pAcl - Supplies the Acl being modified

    dwAceRevision - Supplies the Acl/Ace revision of the ACE being
        added

    dwStartingAceIndex - Supplies the ACE index which will be the
        index of the first ace inserted in the acl.  0 for the
        beginning of the list and MAXULONG for the end of the list.

    pAceList - Supplies the list of Aces to be added to the Acl

    nAceListLength - Supplies the size, in bytes, of the AceList
        buffer

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.


--*/
{
    NTSTATUS Status;

    Status = RtlAddAce (
        pAcl,
        dwAceRevision,
        dwStartingAceIndex,
        pAceList,
        nAceListLength
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

BOOL
APIENTRY
DeleteAce (
    PACL pAcl,
    DWORD dwAceIndex
    )
/*++

Routine Description:

    This routine deletes one ACE from an ACL.

Arguments:

    pAcl - Supplies the Acl being modified

    dwAceIndex - Supplies the index of the Ace to delete.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlDeleteAce (
                pAcl,
                dwAceIndex
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

BOOL
APIENTRY
GetAce (
    PACL pAcl,
    DWORD dwAceIndex,
    PVOID *pAce
    )
/*++

Routine Description:

    This routine returns a pointer to an ACE in an ACl referenced by
    ACE index

Arguments:

    pAcl - Supplies the ACL being queried

    dwAceIndex - Supplies the Ace index to locate

    pAce - Receives the address of the ACE within the ACL

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlGetAce (
                pAcl,
                dwAceIndex,
                pAce
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

BOOL
APIENTRY
AddAccessAllowedAce (
    PACL pAcl,
    DWORD dwAceRevision,
    DWORD AccessMask,
    PSID pSid
    )
/*++

Routine Description:

    This routine adds an ACCESS_ALLOWED ACE to an ACL.  This is
    expected to be a common form of ACL modification.

    A very bland ACE header is placed in the ACE.  It provides no
    inheritance and no ACE flags.

Arguments:

    PAcl - Supplies the Acl being modified

    dwAceRevision - Supplies the Acl/Ace revision of the ACE being added

    AccessMask - The mask of accesses to be granted to the specified SID.

    pSid - Pointer to the SID being granted access.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlAddAccessAllowedAce (
                pAcl,
                dwAceRevision,
                AccessMask,
                pSid
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 

BOOL
APIENTRY
AddAccessDeniedAce (
    PACL pAcl,
    DWORD dwAceRevision,
    DWORD AccessMask,
    PSID pSid
    )
/*++

Routine Description:

    This routine adds an ACCESS_DENIED ACE to an ACL.  This is
    expected to be a common form of ACL modification.

    A very bland ACE header is placed in the ACE.  It provides no
    inheritance and no ACE flags.


Arguments:

    pAcl - Supplies the Acl being modified

    dwAceRevision - Supplies the Acl/Ace revision of the ACE being added

    AccessMask - The mask of accesses to be denied to the specified SID.

    pSid - Pointer to the SID being denied access.


Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlAddAccessDeniedAce (
                pAcl,
                dwAceRevision,
                AccessMask,
                pSid
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
AddAuditAccessAce(
    PACL pAcl,
    DWORD dwAceRevision,
    DWORD dwAccessMask,
    PSID pSid,
    BOOL bAuditSuccess,
    BOOL bAuditFailure
    )
/*++

Routine Description:

    This routine adds a SYSTEM_AUDIT ACE to an ACL.  This is
    expected to be a common form of ACL modification.

    A very bland ACE header is placed in the ACE.  It provides no
    inheritance.

    Parameters are used to indicate whether auditing is to be performed
    on success, failure, or both.


Arguments:

    pAcl - Supplies the Acl being modified

    dwAceRevision - Supplies the Acl/Ace revision of the ACE being added

    dwAccessMask - The mask of accesses to be denied to the specified SID.

    pSid - Pointer to the SID to be audited.

    bAuditSuccess - If TRUE, indicates successful access attempts are to be
        audited.

    bAuditFailure - If TRUE, indicated failed access attempts are to be
        audited.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/

{
    NTSTATUS Status;

    Status =  RtlAddAuditAccessAce (
                pAcl,
                dwAceRevision,
                dwAccessMask,
                pSid,
                (BOOLEAN)bAuditSuccess,
                (BOOLEAN)bAuditFailure
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
FindFirstFreeAce (
    PACL pAcl,
    PVOID *pAce
    )
/*++

Routine Description:

    This routine returns a pointer to the first free byte in an Acl
    or NULL if the acl is ill-formed.  If the Acl is full then the
    return pointer is to the byte immediately following the acl, and
    TRUE will be returned.

Arguments:

    pAcl - Supplies a pointer to the Acl to examine

    pAce - Receives a pointer to the first free position in the Acl

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    return (BOOL) RtlFirstFreeAce (
                    pAcl,
                    pAce
                    );
}

BOOL
APIENTRY
InitializeSecurityDescriptor (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    DWORD dwRevision
    )
/*++

Routine Description:

    This procedure initializes a new "absolute format" security descriptor.
    After the procedure call the security descriptor is initialized with no
    system ACL, no discretionary ACL, no owner, no primary group and
    all control flags set to false (null).

Arguments:


    pSecurityDescriptor - Supplies the security descriptor to
        initialize.

    dwRevision - Provides the revision level to assign to the security
        descriptor.  This should be one (1) for this release.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlCreateSecurityDescriptor (
                pSecurityDescriptor,
                dwRevision
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
IsValidSecurityDescriptor (
    PSECURITY_DESCRIPTOR pSecurityDescriptor
    )
/*++

Routine Description:

    This procedure validates a SecurityDescriptor's structure.  This
    involves validating the revision levels of each component of the
    security descriptor.

Arguments:

    pSecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
        to validate.

Return Value:

    BOOL - TRUE if the structure of SecurityDescriptor is valid.


--*/
{
    if (!RtlValidSecurityDescriptor ( pSecurityDescriptor )) {
        BaseSetLastNTError( STATUS_INVALID_SECURITY_DESCR );
        return( FALSE );
    }

    return( TRUE );
}

 


DWORD
APIENTRY
GetSecurityDescriptorLength (
    PSECURITY_DESCRIPTOR pSecurityDescriptor
    )
/*++

Routine Description:

    This routine returns the length, in bytes, necessary to capture a
    structurally valid SECURITY_DESCRIPTOR.  The length includes the length
    of all associated data structures (like SIDs and ACLs).  The length also
    takes into account the alignment requirements of each component.

    The minimum length of a security descriptor (one which has no associated
    SIDs or ACLs) is SECURITY_DESCRIPTOR_MIN_LENGTH.


Arguments:

    pSecurityDescriptor - Points to the SECURITY_DESCRIPTOR whose
        length is to be returned.  The SECURITY_DESCRIPTOR's structure
        is assumed to be valid.

Return Value:

    DWORD - The length, in bytes, of the SECURITY_DESCRIPTOR.


--*/
{
    return RtlLengthSecurityDescriptor (
        pSecurityDescriptor
        );
}

 

 

BOOL
APIENTRY
GetSecurityDescriptorControl (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    PSECURITY_DESCRIPTOR_CONTROL pControl,
    LPDWORD lpdwRevision
    )
/*++

Routine Description:

    This procedure retrieves the control information from a security descriptor.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor.

    pControl - Receives the control information.

    lpdwRevision - Receives the revision of the security descriptor.
        This value will always be returned, even if an error is
        returned by this routine.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlGetControlSecurityDescriptor (
                pSecurityDescriptor,
                pControl,
                lpdwRevision
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
SetSecurityDescriptorDacl (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    BOOL bDaclPresent,
    PACL pDacl OPTIONAL,
    BOOL bDaclDefaulted OPTIONAL
    )
/*++

Routine Description:

    This procedure sets the discretionary ACL information of an absolute
    format security descriptor.  If there is already a discretionary ACL
    present in the security descriptor, it is superseded.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor to be which
        the discretionary ACL is to be added.

    bDaclPresent - If FALSE, indicates the DaclPresent flag in the
        security descriptor should be set to FALSE.  In this case, the
        remaining optional parameters are ignored.  Otherwise, the
        DaclPresent control flag in the security descriptor is set to
        TRUE and the remaining optional parameters are not ignored.

    pDacl - Supplies the discretionary ACL for the security
        descriptor.  If this optional parameter is not passed, then a
        null ACL is assigned to the security descriptor.  A null
        discretionary ACL unconditionally grants access.  The ACL is
        referenced by, not copied into, by the security descriptor.

    bDaclDefaulted - When set, indicates the discretionary ACL was
        picked up from some default mechanism (rather than explicitly
        specified by a user).  This value is set in the DaclDefaulted
        control flag in the security descriptor.  If this optional
        parameter is not passed, then the DaclDefaulted flag will be
        cleared.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlSetDaclSecurityDescriptor (
        pSecurityDescriptor,
        (BOOLEAN)bDaclPresent,
        pDacl,
        (BOOLEAN)bDaclDefaulted
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 

BOOL
APIENTRY
GetSecurityDescriptorDacl (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    LPBOOL lpbDaclPresent,
    PACL *pDacl,
    LPBOOL lpbDaclDefaulted
    )
/*++

Routine Description:

    This procedure retrieves the discretionary ACL information of a
    security descriptor.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor.

    lpbDaclPresent - If TRUE, indicates that the security descriptor
        does contain a discretionary ACL.  In this case, the
        remaining OUT parameters will receive valid values.
        Otherwise, the security descriptor does not contain a
        discretionary ACL and the remaining OUT parameters will not
        receive valid values.

    pDacl - This value is returned only if the value returned for the
        DaclPresent flag is TRUE.  In this case, the Dacl parameter
        receives the address of the security descriptor's
        discretionary ACL.  If this value is returned as null, then
        the security descriptor has a null discretionary ACL.

    lpbDaclDefaulted - This value is returned only if the value
        returned for the DaclPresent flag is TRUE.  In this case, the
        DaclDefaulted parameter receives the value of the security
        descriptor's DaclDefaulted control flag.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    BOOLEAN DaclPresent, DaclDefaulted;

    Status = RtlGetDaclSecurityDescriptor (
        pSecurityDescriptor,
        &DaclPresent,
        pDacl,
        &DaclDefaulted
        );
    *lpbDaclPresent = (BOOL)DaclPresent;
    *lpbDaclDefaulted = (BOOL)DaclDefaulted;

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
SetSecurityDescriptorSacl (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    BOOL bSaclPresent,
    PACL pSacl OPTIONAL,
    BOOL bSaclDefaulted
    )
/*++

Routine Description:

    This procedure sets the system ACL information of an absolute security
    descriptor.  If there is already a system ACL present in the
    security descriptor, it is superseded.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor to be which
        the system ACL is to be added.

    bSaclPresent - If FALSE, indicates the SaclPresent flag in the
        security descriptor should be set to FALSE.  In this case,
        the remaining optional parameters are ignored.  Otherwise,
        the SaclPresent control flag in the security descriptor is
        set to TRUE and the remaining optional parameters are not
        ignored.

    pSacl - Supplies the system ACL for the security descriptor.  If
        this optional parameter is not passed, then a null ACL is
        assigned to the security descriptor.  The ACL is referenced
        by, not copied into, by the security descriptor.

    bSaclDefaulted - When set, indicates the system ACL was picked up
        from some default mechanism (rather than explicitly specified
        by a user).  This value is set in the SaclDefaulted control
        flag in the security descriptor.  If this optional parameter
        is not passed, then the SaclDefaulted flag will be cleared.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlSetSaclSecurityDescriptor (
                pSecurityDescriptor,
                (BOOLEAN)bSaclPresent,
                pSacl,
                (BOOLEAN)bSaclDefaulted
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
GetSecurityDescriptorSacl (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    LPBOOL lpbSaclPresent,
    PACL *pSacl,
    LPBOOL lpbSaclDefaulted
    )
/*++

Routine Description:

    This procedure retrieves the system ACL information of a security
    descriptor.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor.

    lpbSaclPresent - If TRUE, indicates that the security descriptor
        does contain a system ACL.  In this case, the remaining OUT
        parameters will receive valid values.  Otherwise, the
        security descriptor does not contain a system ACL and the
        remaining OUT parameters will not receive valid values.

    pSacl - This value is returned only if the value returned for the
        SaclPresent flag is TRUE.  In this case, the Sacl parameter
        receives the address of the security descriptor's system ACL.
        If this value is returned as null, then the security
        descriptor has a null system ACL.

    lpbSaclDefaulted - This value is returned only if the value
        returned for the SaclPresent flag is TRUE.  In this case, the
        SaclDefaulted parameter receives the value of the security
        descriptor's SaclDefaulted control flag.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    BOOLEAN SaclPresent, SaclDefaulted;

    Status = RtlGetSaclSecurityDescriptor (
        pSecurityDescriptor,
        &SaclPresent,
        pSacl,
        &SaclDefaulted
        );
    *lpbSaclPresent = (BOOL)SaclPresent;
    *lpbSaclDefaulted = (BOOL)SaclDefaulted;

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
SetSecurityDescriptorOwner (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    PSID pOwner OPTIONAL,
    BOOL bOwnerDefaulted OPTIONAL
    )
/*++

Routine Description:

    This procedure sets the owner information of an absolute security
    descriptor.  If there is already an owner present in the security
    descriptor, it is superseded.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor in which
        the owner is to be set.  If the security descriptor already
        includes an owner, it will be superseded by the new owner.

    pOwner - Supplies the owner SID for the security descriptor.  If
        this optional parameter is not passed, then the owner is
        cleared (indicating the security descriptor has no owner).
        The SID is referenced by, not copied into, the security
        descriptor.

    bOwnerDefaulted - When set, indicates the owner was picked up from
        some default mechanism (rather than explicitly specified by a
        user).  This value is set in the OwnerDefaulted control flag
        in the security descriptor.  If this optional parameter is
        not passed, then the SaclDefaulted flag will be cleared.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.


--*/
{
    NTSTATUS Status;

    Status = RtlSetOwnerSecurityDescriptor (
        pSecurityDescriptor,
        pOwner,
        (BOOLEAN)bOwnerDefaulted
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

BOOL
APIENTRY
GetSecurityDescriptorOwner (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    PSID *pOwner,
    LPBOOL lpbOwnerDefaulted
    )
/*++

Routine Description:

    This procedure retrieves the owner information of a security
    descriptor.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor.

    pOwner - Receives a pointer to the owner SID.  If the security
        descriptor does not currently contain an owner, then this
        value will be returned as null.  In this case, the remaining
        OUT parameters are not given valid return values.  Otherwise,
        this parameter points to an SID and the remaining OUT
        parameters are provided valid return values.

    lpbOwnerDefaulted - This value is returned only if the value
        returned for the Owner parameter is not null.  In this case,
        the OwnerDefaulted parameter receives the value of the
        security descriptor's OwnerDefaulted control flag.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    BOOLEAN OwnerDefaulted;

    Status = RtlGetOwnerSecurityDescriptor (
        pSecurityDescriptor,
        pOwner,
        &OwnerDefaulted
        );
    *lpbOwnerDefaulted = (BOOL)OwnerDefaulted;

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
SetSecurityDescriptorGroup (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    PSID pGroup OPTIONAL,
    BOOL bGroupDefaulted OPTIONAL
    )
/*++

Routine Description:

    This procedure sets the primary group information of an absolute security
    descriptor.  If there is already an primary group present in the
    security descriptor, it is superseded.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor in which
        the primary group is to be set.  If the security descriptor
        already includes a primary group, it will be superseded by
        the new group.

    pGroup - Supplies the primary group SID for the security
        descriptor.  If this optional parameter is not passed, then
        the primary group is cleared (indicating the security
        descriptor has no primary group).  The SID is referenced by,
        not copied into, the security descriptor.

    bGroupDefaulted - When set, indicates the owner was picked up from
        some default mechanism (rather than explicitly specified by a
        user).  This value is set in the OwnerDefaulted control flag
        in the security descriptor.  If this optional parameter is
        not passed, then the SaclDefaulted flag will be cleared.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlSetGroupSecurityDescriptor (
        pSecurityDescriptor,
        pGroup,
        (BOOLEAN)bGroupDefaulted
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
GetSecurityDescriptorGroup (
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    PSID *pGroup,
    LPBOOL lpbGroupDefaulted
    )
/*++

Routine Description:

    This procedure retrieves the primary group information of a
    security descriptor.

Arguments:

    pSecurityDescriptor - Supplies the security descriptor.

    pGroup - Receives a pointer to the primary group SID.  If the
        security descriptor does not currently contain a primary
        group, then this value will be returned as null.  In this
        case, the remaining OUT parameters are not given valid return
        values.  Otherwise, this parameter points to an SID and the
        remaining OUT parameters are provided valid return values.

    lpbGroupDefaulted - This value is returned only if the value
        returned for the Group parameter is not null.  In this case,
        the GroupDefaulted parameter receives the value of the
        security descriptor's GroupDefaulted control flag.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;
    BOOLEAN GroupDefaulted;

    Status = RtlGetGroupSecurityDescriptor (
        pSecurityDescriptor,
        pGroup,
        &GroupDefaulted
        );
    *lpbGroupDefaulted = GroupDefaulted;

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
CreatePrivateObjectSecurity (
    PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
    PSECURITY_DESCRIPTOR CreatorDescriptor OPTIONAL,
    PSECURITY_DESCRIPTOR * NewDescriptor,
    BOOL IsDirectoryObject,
    HANDLE Token,
    PGENERIC_MAPPING GenericMapping
    )
/*++

Routine Description:

    The procedure is used to allocpate and initialize a self-relative
    Security Descriptor for a new protected server's object.  It is called
    when a new protected server object is being created.  The generated
    security descriptor will be in self-relative form.

    This procedure, called only from user mode, is used to establish a
    security descriptor for a new protected server's object.  When no
    longer needed, this descriptor must be freed using
    DestroyPrivateObjectSecurity().

Arguments:

    ParentDescriptor - Supplies the Security Descriptor for the parent
        directory under which a new object is being created.  If there is
        no parent directory, then this argument is specified as NULL.

    CreatorDescriptor - (Optionally) Points to a security descriptor
        presented by the creator of the object.  If the creator of the
        object did not explicitly pass security information for the new
        object, then a null pointer should be passed.

    NewDescriptor - Points to a pointer that is to be made to point to the
        newly allocated self-relative security descriptor.

    IsDirectoryObject - Specifies if the new object is going to be a
        directory object.  A value of TRUE indicates the object is a
        container of other objects.

    Token - Supplies the token for the client on whose behalf the
        object is being created.  If it is an impersonation token,
        then it must be at SecurityIdentification level or higher.  If
        it is not an impersonation token, the operation proceeds
        normally.

        A client token is used to retrieve default security
        information for the new object, such as default owner, primary
        group, and discretionary access control.  The token must be
        open for TOKEN_QUERY access.

    GenericMapping - Supplies a pointer to a generic mapping array denoting
        the mapping between each generic right to specific rights.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlNewSecurityObject (
        ParentDescriptor,
        CreatorDescriptor,
        NewDescriptor,
        (BOOLEAN)IsDirectoryObject,
        Token,
        GenericMapping
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
SetPrivateObjectSecurity (
    SECURITY_INFORMATION SecurityInformation,
    PSECURITY_DESCRIPTOR ModificationDescriptor,
    PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
    PGENERIC_MAPPING GenericMapping,
    HANDLE Token OPTIONAL
    )
/*++

Routine Description:

    Modify an object's existing self-relative form security descriptor.

    This procedure, called only from user mode, is used to update a
    security descriptor on an existing protected server's object.  It
    applies changes requested by a new security descriptor to the existing
    security descriptor.  If necessary, this routine will allocate
    additional memory to produce a larger security descriptor.  All access
    checking is expected to be done before calling this routine.  This
    includes checking for WRITE_OWNER, WRITE_DAC, and privilege to assign a
    system ACL as appropriate.

    The caller of this routine must not be impersonating a client.

Arguments:

    SecurityInformation - Indicates which security information is
        to be applied to the object.  The value(s) to be assigned are
        passed in the ModificationDescriptor parameter.

    ModificationDescriptor - Supplies the input security descriptor to be
        applied to the object.  The caller of this routine is expected
        to probe and capture the passed security descriptor before calling
        and release it after calling.

    ObjectsSecurityDescriptor - Supplies the address of a pointer to
        the objects security descriptor that is going to be altered by
        this procedure.  This security descriptor must be in self-
        relative form or an error will be returned.

    GenericMapping - This argument provides the mapping of generic to
        specific/standard access types for the object being accessed.
        This mapping structure is expected to be safe to access
        (i.e., captured if necessary) prior to be passed to this routine.

    Token - (optionally) Supplies the token for the client on whose
        behalf the security is being modified.  This parameter is only
        required to ensure that the client has provided a legitimate
        value for a new owner SID.  The token must be open for
        TOKEN_QUERY access.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlSetSecurityObject (
        SecurityInformation,
        ModificationDescriptor,
        ObjectsSecurityDescriptor,
        GenericMapping,
        Token
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
GetPrivateObjectSecurity (
    PSECURITY_DESCRIPTOR ObjectDescriptor,
    SECURITY_INFORMATION SecurityInformation,
    PSECURITY_DESCRIPTOR ResultantDescriptor,
    DWORD DescriptorLength,
    PDWORD ReturnLength
    )
/*++

Routine Description:

    Query information from a protected server object's existing security
    descriptor.

    This procedure, called only from user mode, is used to retrieve
    information from a security descriptor on an existing protected
    server's object.  All access checking is expected to be done before
    calling this routine.  This includes checking for READ_CONTROL, and
    privilege to read a system ACL as appropriate.

Arguments:

    ObjectDescriptor - Points to a pointer to a security descriptor to be
        queried.

    SecurityInformation - Identifies the security information being
        requested.

    ResultantDescriptor - Points to buffer to receive the resultant
        security descriptor.  The resultant security descriptor will
        contain all information requested by the SecurityInformation
        parameter.

    DescriptorLength - Is an unsigned integer which indicates the length,
        in bytes, of the buffer provided to receive the resultant
        descriptor.

    ReturnLength - Receives an unsigned integer indicating the actual
        number of bytes needed in the ResultantDescriptor to store the
        requested information.  If the value returned is greater than the
        value passed via the DescriptorLength parameter, then
        STATUS_BUFFER_TOO_SMALL is returned and no information is returned.


Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlQuerySecurityObject (
         ObjectDescriptor,
         SecurityInformation,
         ResultantDescriptor,
         DescriptorLength,
         ReturnLength
         );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
DestroyPrivateObjectSecurity (
    PSECURITY_DESCRIPTOR * ObjectDescriptor
    )
/*++

Routine Description:

    Delete a protected server object's security descriptor.

    This procedure, called only from user mode, is used to delete a
    security descriptor associated with a protected server's object.  This
    routine will normally be called by a protected server during object
    deletion.  The input descriptor is expected to be one created via
    a call to CreatePrivateObjectSecurity.

Arguments:

    ObjectDescriptor - Points to a pointer to a security descriptor to be
        deleted.


Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlDeleteSecurityObject (
        ObjectDescriptor
        );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
MakeSelfRelativeSD (
    PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
    PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
    LPDWORD lpdwBufferLength
    )
/*++

Routine Description:

    Converts a security descriptor in absolute form to one in self-relative
    form.

Arguments:

    pAbsoluteSecurityDescriptor - Pointer to an absolute format
        security descriptor.  This descriptor will not be modified.

    pSelfRelativeSecurityDescriptor - Pointer to a buffer that will
        contain the returned self-relative security descriptor.

    lpdwBufferLength - Supplies the length of the buffer.  If the
        supplied buffer is not large enough to hold the self-relative
        security descriptor, an error will be returned, and this field
        will return the minimum size required.


Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlAbsoluteToSelfRelativeSD (
                pAbsoluteSecurityDescriptor,
                pSelfRelativeSecurityDescriptor,
                lpdwBufferLength
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

BOOL
APIENTRY
MakeAbsoluteSD (
    PSECURITY_DESCRIPTOR pSelfRelativeSecurityDescriptor,
    PSECURITY_DESCRIPTOR pAbsoluteSecurityDescriptor,
    LPDWORD lpdwAbsoluteSecurityDescriptorSize,
    PACL pDacl,
    LPDWORD lpdwDaclSize,
    PACL pSacl,
    LPDWORD lpdwSaclSize,
    PSID pOwner,
    LPDWORD lpdwOwnerSize,
    PSID pPrimaryGroup,
    LPDWORD lpdwPrimaryGroupSize
    )
/*++

Routine Description:

    Converts a security descriptor from self-relative format to absolute
    format

Arguments:

    pSecurityDescriptor - Supplies a pointer to a security descriptor
        in Self-Relative format

    pAbsoluteSecurityDescriptor - A pointer to a buffer in which will
        be placed the main body of the Absolute format security
        descriptor.

    lpdwAbsoluteSecurityDescriptorSize - The size in bytes of the
        buffer pointed to by pAbsoluteSecurityDescriptor.

    pDacl - Supplies a pointer to a buffer that will contain the Dacl
        of the output descriptor.  This pointer will be referenced by,
        not copied into, the output descriptor.

    lpdwDaclSize - Supplies the size of the buffer pointed to by Dacl.
        In case of error, it will return the minimum size necessary to
        contain the Dacl.

    pSacl - Supplies a pointer to a buffer that will contain the Sacl
        of the output descriptor.  This pointer will be referenced by,
        not copied into, the output descriptor.

    lpdwSaclSize - Supplies the size of the buffer pointed to by Sacl.
        In case of error, it will return the minimum size necessary to
        contain the Sacl.

    pOwner - Supplies a pointer to a buffer that will contain the
        Owner of the output descriptor.  This pointer will be
        referenced by, not copied into, the output descriptor.

    lpdwOwnerSize - Supplies the size of the buffer pointed to by
        Owner.  In case of error, it will return the minimum size
        necessary to contain the Owner.

    pPrimaryGroup - Supplies a pointer to a buffer that will contain
        the PrimaryGroup of the output descriptor.  This pointer will
        be referenced by, not copied into, the output descriptor.

    lpdwPrimaryGroupSize - Supplies the size of the buffer pointed to
        by PrimaryGroup.  In case of error, it will return the minimum
        size necessary to contain the PrimaryGroup.


Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{
    NTSTATUS Status;

    Status = RtlSelfRelativeToAbsoluteSD (
                pSelfRelativeSecurityDescriptor,
                pAbsoluteSecurityDescriptor,
                lpdwAbsoluteSecurityDescriptorSize,
                pDacl,
                lpdwDaclSize,
                pSacl,
                lpdwSaclSize,
                pOwner,
                lpdwOwnerSize,
                pPrimaryGroup,
                lpdwPrimaryGroupSize
                );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}


VOID
SetSecurityAccessMask(
    IN SECURITY_INFORMATION SecurityInformation,
    OUT LPDWORD DesiredAccess
    )

/*++

Routine Description:

    This routine builds an access mask representing the accesses necessary
    to set the object security information specified in the SecurityInformation
    parameter.  While it is not difficult to determine this information,
    the use of a single routine to generate it will ensure minimal impact
    when the security information associated with an object is extended in
    the future (to include mandatory access control information).

Arguments:

    SecurityInformation - Identifies the object's security information to be
        modified.

    DesiredAccess - Points to an access mask to be set to represent the
        accesses necessary to modify the information specified in the
        SecurityInformation parameter.

Return Value:

    None.

--*/

{

    //
    // Figure out accesses needed to perform the indicated operation(s).
    //

    (*DesiredAccess) = 0;

    if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
        (SecurityInformation & GROUP_SECURITY_INFORMATION)   ) {
        (*DesiredAccess) |= WRITE_OWNER;
    }

    if (SecurityInformation & DACL_SECURITY_INFORMATION) {
        (*DesiredAccess) |= WRITE_DAC;
    }

    if (SecurityInformation & SACL_SECURITY_INFORMATION) {
        (*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
    }

    return;

}


VOID
QuerySecurityAccessMask(
    IN SECURITY_INFORMATION SecurityInformation,
    OUT LPDWORD DesiredAccess
    )

/*++

Routine Description:

    This routine builds an access mask representing the accesses necessary
    to query the object security information specified in the
    SecurityInformation parameter.  While it is not difficult to determine
    this information, the use of a single routine to generate it will ensure
    minimal impact when the security information associated with an object is
    extended in the future (to include mandatory access control information).

Arguments:

    SecurityInformation - Identifies the object's security information to be
        queried.

    DesiredAccess - Points to an access mask to be set to represent the
        accesses necessary to query the information specified in the
        SecurityInformation parameter.

Return Value:

    None.

--*/

{

    //
    // Figure out accesses needed to perform the indicated operation(s).
    //

    (*DesiredAccess) = 0;

    if ((SecurityInformation & OWNER_SECURITY_INFORMATION) ||
        (SecurityInformation & GROUP_SECURITY_INFORMATION) ||
        (SecurityInformation & DACL_SECURITY_INFORMATION)) {
        (*DesiredAccess) |= READ_CONTROL;
    }

    if ((SecurityInformation & SACL_SECURITY_INFORMATION)) {
        (*DesiredAccess) |= ACCESS_SYSTEM_SECURITY;
    }

    return;

}

BOOL
APIENTRY
SetFileSecurityW(
    LPCWSTR lpFileName,
    SECURITY_INFORMATION SecurityInformation,
    PSECURITY_DESCRIPTOR pSecurityDescriptor
    )

/*++

Routine Description:

    This API can be used to set the security of a file or directory
    (process, file, event, etc.).  This call is only successful if the
    following conditions are met:

    o If the object's owner or group is to be set, the caller must
      have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.

    o If the object's DACL is to be set, the caller must have
      WRITE_DAC permission or be the object's owner.

    o If the object's SACL is to be set, the caller must have
      SeSecurityPrivilege.

Arguments:

    lpFileName - Supplies the file name of the file to open.  Depending on
        the value of the FailIfExists parameter, this name may or may
        not already exist.

    SecurityInformation - A pointer to information describing the
        contents of the Security Descriptor.

    pSecurityDescriptor - A pointer to a well formed Security
        Descriptor.

Return Value:

    TRUE - The operation was successful.

    FALSE/NULL - The operation failed. Extended error status is available
        using GetLastError.

--*/
{
    NTSTATUS Status;
    HANDLE FileHandle;
    ACCESS_MASK DesiredAccess;

    OBJECT_ATTRIBUTES Obja;
    UNICODE_STRING FileName;
    BOOLEAN TranslationStatus;
    RTL_RELATIVE_NAME RelativeName;
    IO_STATUS_BLOCK IoStatusBlock;
    PVOID FreeBuffer;


    SetSecurityAccessMask(
        SecurityInformation,
        &DesiredAccess
        );

    TranslationStatus = RtlDosPathNameToNtPathName_U(
                            lpFileName,
                            &FileName,
                            NULL,
                            &RelativeName
                            );

    if ( !TranslationStatus ) {
        BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
        return FALSE;
        }

    FreeBuffer = FileName.Buffer;

    if ( RelativeName.RelativeName.Length ) {
        FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
        }
    else {
        RelativeName.ContainingDirectory = NULL;
        }

    InitializeObjectAttributes(
        &Obja,
        &FileName,
        OBJ_CASE_INSENSITIVE,
        RelativeName.ContainingDirectory,
        NULL
        );

    Status = NtOpenFile(
                 &FileHandle,
                 DesiredAccess,
                 &Obja,
                 &IoStatusBlock,
                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                 0
                 );

    RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);

    if ( !NT_SUCCESS( Status ) ) {
        BaseSetLastNTError( Status );
        return FALSE;
        }

    Status = NtSetSecurityObject(
                FileHandle,
                SecurityInformation,
                pSecurityDescriptor
                );

    NtClose(FileHandle);

    if (!NT_SUCCESS(Status)) {
        BaseSetLastNTError(Status);
        return FALSE;
        }

    return TRUE;
}

BOOL
APIENTRY
SetFileSecurityA(
    LPCSTR lpFileName,
    SECURITY_INFORMATION SecurityInformation,
    PSECURITY_DESCRIPTOR pSecurityDescriptor
    )

/*++

Routine Description:

    ANSI thunk to SetFileSecurityW

--*/

{

    PUNICODE_STRING Unicode;
    ANSI_STRING AnsiString;
    NTSTATUS Status;

    Unicode = &NtCurrentTeb()->StaticUnicodeString;
    RtlInitAnsiString(&AnsiString,lpFileName);
    Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
        }
    return ( SetFileSecurityW( (LPCWSTR)Unicode->Buffer,
                               SecurityInformation,
                               pSecurityDescriptor
                        )
           );
}

BOOL
APIENTRY
GetFileSecurityW(
    LPCWSTR lpFileName,
    SECURITY_INFORMATION RequestedInformation,
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    DWORD nLength,
    LPDWORD lpnLengthNeeded
    )

/*++

Routine Description:

    This API returns top the caller a copy of the security descriptor
    protecting a file or directory.  Based on the caller's access
    rights and privileges, this procedure will return a security
    descriptor containing the requested security descriptor fields.
    To read the handle's security descriptor the caller must be
    granted READ_CONTROL access or be the owner of the object.  In
    addition, the caller must have SeSecurityPrivilege privilege to
    read the system ACL.

Arguments:

    lpFileName - Represents the name of the file or directory whose
        security is being retrieved.

    RequestedInformation - A pointer to the security information being
        requested.

    pSecurityDescriptor - A pointer to the buffer to receive a copy of
        the secrity descriptor protecting the object that the caller
        has the rigth to view.  The security descriptor is returned in
        self-relative format.

    nLength - The size, in bytes, of the security descriptor buffer.

    lpnLengthNeeded - A pointer to the variable to receive the number
        of bytes needed to store the complete secruity descriptor.  If
        returned number of bytes is less than or equal to nLength then
        the entire security descriptor is returned in the output
        buffer, otherwise none of the descriptor is returned.

Return Value:

    TRUE is returned for success, FALSE if access is denied or if the
        buffer is too small to hold the security descriptor.


--*/
{
    NTSTATUS Status;
    HANDLE FileHandle;
    ACCESS_MASK DesiredAccess;

    OBJECT_ATTRIBUTES Obja;
    UNICODE_STRING FileName;
    BOOLEAN TranslationStatus;
    RTL_RELATIVE_NAME RelativeName;
    IO_STATUS_BLOCK IoStatusBlock;
    PVOID FreeBuffer;

    QuerySecurityAccessMask(
        RequestedInformation,
        &DesiredAccess
        );

    TranslationStatus = RtlDosPathNameToNtPathName_U(
                            lpFileName,
                            &FileName,
                            NULL,
                            &RelativeName
                            );

    if ( !TranslationStatus ) {
        BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
        return FALSE;
        }

    FreeBuffer = FileName.Buffer;

    if ( RelativeName.RelativeName.Length ) {
        FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
        }
    else {
        RelativeName.ContainingDirectory = NULL;
        }

    InitializeObjectAttributes(
        &Obja,
        &FileName,
        OBJ_CASE_INSENSITIVE,
        RelativeName.ContainingDirectory,
        NULL
        );

    Status = NtOpenFile(
                 &FileHandle,
                 DesiredAccess,
                 &Obja,
                 &IoStatusBlock,
                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                 0
                 );

    RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);

    if (NT_SUCCESS(Status)) {
        Status = NtQuerySecurityObject(
                     FileHandle,
                     RequestedInformation,
                     pSecurityDescriptor,
                     nLength,
                     lpnLengthNeeded
                     );
        NtClose(FileHandle);
    }


    if (!NT_SUCCESS(Status)) {
        BaseSetLastNTError(Status);
        return FALSE;
        }

    return TRUE;
}

BOOL
APIENTRY
GetFileSecurityA(
    LPCSTR lpFileName,
    SECURITY_INFORMATION RequestedInformation,
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    DWORD nLength,
    LPDWORD lpnLengthNeeded
    )

/*++

Routine Description:

    ANSI thunk to GetFileSecurityW

--*/

{

    PUNICODE_STRING Unicode;
    ANSI_STRING AnsiString;
    NTSTATUS Status;

    Unicode = &NtCurrentTeb()->StaticUnicodeString;
    RtlInitAnsiString(&AnsiString,lpFileName);
    Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
        }
    return ( GetFileSecurityW( (LPCWSTR)Unicode->Buffer,
                               RequestedInformation,
                               pSecurityDescriptor,
                               nLength,
                               lpnLengthNeeded
                        )
           );
}

 


BOOL
APIENTRY
SetKernelObjectSecurity (
    HANDLE Handle,
    SECURITY_INFORMATION SecurityInformation,
    PSECURITY_DESCRIPTOR SecurityDescriptor
    )
/*++

Routine Description:

    This API can be used to set the security of a kernel object
    (process, file, event, etc.).  This call is only successful if the
    following conditions are met:

    o If the object's owner or group is to be set, the caller must
      have WRITE_OWNER permission or have SeTakeOwnershipPrivilege.

    o If the object's DACL is to be set, the caller must have
      WRITE_DAC permission or be the object's owner.

    o If the object's SACL is to be set, the caller must have
      SeSecurityPrivilege.

Arguments:

    Handle - Represents a handle of a kernel object.

    SecurityInformation - A pointer to information describing the
        contents of the Security Descriptor.

    pSecurityDescriptor - A pointer to a well formed Security
        Descriptor.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/

{
    NTSTATUS Status;

    Status = NtSetSecurityObject(
                 Handle,
                 SecurityInformation,
                 SecurityDescriptor
                 );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

 


BOOL
APIENTRY
GetKernelObjectSecurity (
    HANDLE Handle,
    SECURITY_INFORMATION RequestedInformation,
    PSECURITY_DESCRIPTOR pSecurityDescriptor,
    DWORD nLength,
    LPDWORD lpnLengthNeeded
    )
/*++

Routine Description:

    This API returns top the caller a copy of the security descriptor
    protecting a kernel object.  Based on the caller's access rights
    and privileges, this procedure will return a security descriptor
    containing the requested security descriptor fields.  To read the
    handle's security descriptor the caller must be granted
    READ_CONTROL access or be the owner of the object.  In addition,
    the caller must have SeSecurityPrivilege privilege to read the
    system ACL.


Arguments:

    Handle - Represents a handle of a kernel object.

    RequestedInformation - A pointer to the security information being
        requested.

    pSecurityDescriptor - A pointer to the buffer to receive a copy of
        the secrity descriptor protecting the object that the caller
        has the rigth to view.  The security descriptor is returned in
        self-relative format.

    nLength - The size, in bytes, of the security descriptor buffer.

    lpnLengthNeeded - A pointer to the variable to receive the number
        of bytes needed to store the complete secruity descriptor.  If
        returned number of bytes is less than or equal to nLength then
        the entire security descriptor is returned in the output
        buffer, otherwise none of the descriptor is returned.


Return Value:

    return-value - Description of conditions needed to return value. - or -
    None.

--*/

{
    NTSTATUS Status;

    Status = NtQuerySecurityObject(
                 Handle,
                 RequestedInformation,
                 pSecurityDescriptor,
                 nLength,
                 lpnLengthNeeded
                 );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;

}


BOOL
APIENTRY
ImpersonateNamedPipeClient(
    IN HANDLE hNamedPipe
    )
/*++

Routine Description:

    Impersonate a named pipe client application.

Arguments:

    hNamedPipe - Handle to a named pipe.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.


--*/

{
    NTSTATUS Status;
    IO_STATUS_BLOCK IoStatusBlock;

    Status =  NtFsControlFile(
                  hNamedPipe,
                  NULL,
                  NULL,
                  NULL,
                  &IoStatusBlock,
                  FSCTL_PIPE_IMPERSONATE,
                  NULL,
                  0,
                  NULL,
                  0
                 );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;
}

BOOL
APIENTRY
ImpersonateSelf(
    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
    )

/*++

Routine Description:

    This routine may be used to obtain an Impersonation token representing
    your own process's context.  This may be useful for enabling a privilege
    for a single thread rather than for the entire process; or changing
    the default DACL for a single thread.

    The token is assigned to the callers thread.

 

Arguments:

    ImpersonationLevel - The level to make the impersonation token.

 

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/
{

    NTSTATUS Status;

    Status = RtlImpersonateSelf( ImpersonationLevel );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;


}

 

BOOL
APIENTRY
RevertToSelf (
    VOID
    )
/*++

Routine Description:

    Terminate impersonation of a named pipe client application.

Arguments:

    None.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/

{
    HANDLE NewToken;
    NTSTATUS Status;

    NewToken = NULL;
    Status = NtSetInformationThread(
                 NtCurrentThread(),
                 ThreadImpersonationToken,
                 (PVOID)&NewToken,
                 (ULONG)sizeof(HANDLE)
                 );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;

}

 

BOOL
APIENTRY
SetThreadToken (
    PHANDLE Thread,
    HANDLE Token
    )
/*++

Routine Description:

    Assigns the specified impersonation token to the specified
    thread.

Arguments:

    Thread - Specifies the thread whose token is to be assigned.
        If NULL is specified, then the caller's thread is assumed.

    Token - The token to assign.  Must be open for TOKEN_IMPERSONATE
        access.  If null, then causes the specified thread to stop
        impersonating.

Return Value:

    Returns TRUE for success, FALSE for failure.  Extended error status
    is available using GetLastError.

--*/

{
    NTSTATUS Status;
    HANDLE TargetThread;

    if (ARGUMENT_PRESENT(Thread)) {
        TargetThread = (*Thread);
    } else {
        TargetThread = NtCurrentThread();
    }


    Status = NtSetInformationThread(
                 TargetThread,
                 ThreadImpersonationToken,
                 (PVOID)&Token,
                 (ULONG)sizeof(HANDLE)
                 );

    if ( !NT_SUCCESS(Status) ) {
        BaseSetLastNTError(Status);
        return FALSE;
    }

    return TRUE;

}

 


BOOL
APIENTRY
LookupAccountNameA(
    LPCSTR lpSystemName,
    LPCSTR lpAccountName,
    PSID Sid,
    LPDWORD cbSid,
    LPSTR ReferencedDomainName,
    LPDWORD cbReferencedDomainName,
    PSID_NAME_USE peUse
    )

/*++

Routine Description:

    ANSI Thunk to LookupAccountNameW

Arguments:

    lpSystemName - Supplies the name of the system at which the lookup
        is to be performed.  If the null string is provided, the local
        system is assumed.

    lpAccountName - Supplies the account name.

    Sid - Returns the SID corresponding to the passed account name.

    cbSid - Supplies the size of the buffer passed in for Sid.  If
        the buffer size is not big enough, this parameter will
        return the size necessary to hold the output Sid.

    ReferencedDomainName - Returns the name of the domain in which the
        name was found.

    cbReferencedDomainName - Supplies the size (in Ansi characters) of the
        ReferencedDomainName buffer.  If the buffer size is not large
        enough, this parameter will return the size necessary to hold
        the null-terminated output domain name.  If the buffer size is
        large enough, tis parameter will return the size (in Ansi characters,
        excluding the terminating null) of the Referenced Domain name.

    peUse - Returns an enumerated type indicating the type of the
        account.

Return Value:

    BOOL - TRUE is returned if successful, else FALSE.

--*/

{
    UNICODE_STRING Unicode;
    UNICODE_STRING TmpUnicode;
    ANSI_STRING  AnsiString;
    PWSTR WReferencedDomainName = NULL;
    UNICODE_STRING SystemName;
    PWSTR pSystemName = NULL;
    NTSTATUS Status;
    BOOL rc = TRUE;
    DWORD cbInitReferencedDomainName;

    Unicode.Buffer = NULL;
    SystemName.Buffer = NULL;

    //
    // Save the original buffer size
    //

    cbInitReferencedDomainName = *cbReferencedDomainName;

    //
    // Convert the passed lpAccountName to a WCHAR string to be
    // passed to the ..W routine.  Note that we cannot use the
    // StaticUnicodeString in the Thread Environment Block because
    // this is used by LdrpWalkImportDescriptor, called from the
    // client RPC stub code of the LsaOpenPolicy() call in
    // LookupAccountNameW.
    //

    RtlInitAnsiString( &AnsiString, lpAccountName );
    Status = RtlAnsiStringToUnicodeString( &Unicode, &AnsiString, TRUE );

    if (!NT_SUCCESS(Status)) {

        rc = FALSE;
    }

    //
    // Allocate a temporary buffer for ReferencedDomainName that
    // is twice as large as what was passed to adjust for the
    // intermediate conversion to a WCHAR string.
    //

    if (rc) {

        WReferencedDomainName = LocalAlloc(
                                    LMEM_FIXED,
                                    sizeof(WCHAR) * (*cbReferencedDomainName)
                                    );

        if (WReferencedDomainName == NULL) {

            Status = STATUS_NO_MEMORY;
            rc = FALSE;
        }
    }

    //
    // If the target system name is non NULL, convert it to Unicode
    //

    if (rc) {

        if ( ARGUMENT_PRESENT( lpSystemName ) ) {

            RtlInitAnsiString( &AnsiString, lpSystemName );
            Status = RtlAnsiStringToUnicodeString( &SystemName, &AnsiString, TRUE );

            if (!NT_SUCCESS(Status)) {

                rc = FALSE;
            }

            pSystemName = SystemName.Buffer;
        }
    }

    //
    // Lookup the Account Sid and obtain its Unicode Account Name.
    //

    if (rc) {

        rc = LookupAccountNameW(
                 (LPCWSTR)pSystemName,
                 (LPCWSTR)Unicode.Buffer,
                 Sid,
                 cbSid,
                 WReferencedDomainName,
                 cbReferencedDomainName,
                 peUse
                 );
    }

    if ( SystemName.Buffer != NULL ) {

        RtlFreeUnicodeString( &SystemName );
    }

    //
    // Convert the returned null-terminated WCHAR string
    // back to a null-terminated CHAR string.
    //

    if (rc) {

        RtlInitUnicodeString( &TmpUnicode, WReferencedDomainName );
        AnsiString.Buffer = ReferencedDomainName;

        //
        // Watch for 16-bit overflow of MaximumLength
        //

        if (cbInitReferencedDomainName <= (DWORD) 65535) {

            AnsiString.MaximumLength = (USHORT) cbInitReferencedDomainName;

        } else {

            AnsiString.MaximumLength = (USHORT) 65535;
        }

        Status = RtlUnicodeStringToAnsiString( &AnsiString, &TmpUnicode, FALSE );

        if ( NT_SUCCESS( Status )) {

            ReferencedDomainName[AnsiString.Length] = 0;

        } else {

            rc = FALSE;
        }
    }

    if ( WReferencedDomainName != NULL) {

        LocalFree( WReferencedDomainName );
    }

    if (Unicode.Buffer != NULL) {

        RtlFreeUnicodeString(&Unicode);
    }

    if (!NT_SUCCESS(Status)) {

        BaseSetLastNTError( Status );
    }

    return( rc );
}

 



BOOL
APIENTRY
LookupAccountNameW(
    LPCWSTR lpSystemName,
    LPCWSTR lpAccountName,
    PSID Sid,
    LPDWORD cbSid,
    LPWSTR ReferencedDomainName,
    LPDWORD cbReferencedDomainName,
    PSID_NAME_USE peUse
    )

/*++

Routine Description:

    Translates a passed name into an account SID.  It will also return
    the name and SID of the first domain in which this name was found.

Arguments:

    lpSystemName - Supplies the name of the system at which the lookup
        is to be performed.  If the null string is provided, the local
        system is assumed.

    lpAccountName - Supplies the account name.

    Sid - Returns the SID corresponding to the passed account name.

    cbSid - Supplies the size of the buffer passed in for Sid.  If
        the buffer size is not big enough, this parameter will
        return the size necessary to hold the output Sid.

    ReferencedDomainName - Returns the name of the domain in which the
        name was found.

    cbReferencedDomainName - Supplies the size (in Wide characters) of the
        ReferencedDomainName buffer.  If the buffer size is not large
        enough, this parameter will return the size necessary to hold
        the null-terminated output domain name.  If the buffer size is
        large enough, tis parameter will return the size (in Ansi characters,
        excluding the terminating null) of the Referenced Domain name.

    peUse - Returns an enumerated type inidicating the type of the
        account.

Return Value:

    BOOL - TRUE is returned if successful, else FALSE.

--*/

{
    SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
    OBJECT_ATTRIBUTES ObjectAttributes;
    LSA_HANDLE PolicyHandle;
    NTSTATUS Status;
    NTSTATUS TmpStatus;
    UNICODE_STRING Name;
    PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains = NULL;
    PLSA_TRANSLATED_SID TranslatedSid = NULL;
    PSID ReturnedDomainSid;
    UCHAR nSubAuthorities;
    UNICODE_STRING TmpString;
    DWORD ReturnedDomainNameSize;
    DWORD SidLengthRequired;
    BOOL Rc;
    UNICODE_STRING SystemName;
    PUNICODE_STRING pSystemName = NULL;


    SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
    SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
    SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    SecurityQualityOfService.EffectiveOnly = FALSE;

    //
    // Set up the object attributes prior to opening the LSA.
    //

    InitializeObjectAttributes(
        &ObjectAttributes,
        NULL,
        0L,
        NULL,
        NULL
        );

    //
    // The InitializeObjectAttributes macro presently stores NULL for
    // the SecurityQualityOfService field, so we must manually copy that
    // structure for now.
    //

    ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;

    if ( ARGUMENT_PRESENT( lpSystemName )) {
        RtlInitUnicodeString( &SystemName, lpSystemName );
        pSystemName = &SystemName;
    }

    //
    // Open the LSA Policy Database for the target system.  This is the
    // starting point for the Name Lookup operation.
    //

    Status = LsaOpenPolicy(
                 pSystemName,
                 &ObjectAttributes,
                 POLICY_LOOKUP_NAMES,
                 &PolicyHandle
                 );

    if ( !NT_SUCCESS( Status )) {

        BaseSetLastNTError( Status );
        return( FALSE );
    }

    RtlInitUnicodeString( &Name, lpAccountName );

    //
    // Attempt to translate the Name to a Sid.
    //

    Status = LsaLookupNames(
                 PolicyHandle,
                 1,
                 &Name,
                 &ReferencedDomains,
                 &TranslatedSid
                 );

    //
    // Close the Policy Handle,  which is not needed after here.
    //

    TmpStatus = LsaClose( PolicyHandle );
    ASSERT( NT_SUCCESS( TmpStatus ));

    //
    // If an error was returned, check specifically for STATUS_NONE_MAPPED.
    // In this case, we may need to dispose of the returned Referenced Domain
    // List and Translated Sid structures.  For all other errors,
    // LsaLookupNames() frees these structures prior to exit.
    //

    if ( !NT_SUCCESS( Status )) {

        if (Status == STATUS_NONE_MAPPED) {

            if (ReferencedDomains != NULL) {

                TmpStatus = LsaFreeMemory( ReferencedDomains );
                ASSERT( NT_SUCCESS( TmpStatus ));
            }

            if (TranslatedSid != NULL) {

                TmpStatus = LsaFreeMemory( TranslatedSid );
                ASSERT( NT_SUCCESS( TmpStatus ));
            }
        }

        BaseSetLastNTError( Status );
        return( FALSE );
    }

    //
    // The Name was successfully translated.  There should be exactly
    // one Referenced Domain and its DomainIndex should be zero.
    //

    ASSERT ( TranslatedSid->DomainIndex == 0 );
    ASSERT ( ReferencedDomains != NULL);
    ASSERT ( ReferencedDomains->Domains != NULL );

    //
    // Calculate the lengths of the returned Sid and Domain Name (in Wide
    // Characters, excluding null).
    //

    ReturnedDomainNameSize =
        (ReferencedDomains->Domains->Name.Length / sizeof(WCHAR));
    ReturnedDomainSid = ReferencedDomains->Domains[ TranslatedSid->DomainIndex ].Sid;
    nSubAuthorities = (*GetSidSubAuthorityCount( ReturnedDomainSid )) + (UCHAR)1;
    SidLengthRequired = GetSidLengthRequired( nSubAuthorities );

    //
    // Check if buffer sizes are too small.  For the returned domain,
    // the size in Wide characters provided must allow for the null
    // terminator that will be appended to the returned name.
    //

    if ( (SidLengthRequired > *cbSid) ||
         (ReturnedDomainNameSize + 1 > *cbReferencedDomainName)
       ) {

        //
        // One or both buffers are too small.  Return sizes required for
        // both buffers.
        //

        *cbSid = SidLengthRequired;
        *cbReferencedDomainName = ReturnedDomainNameSize + 1;
        BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
        Rc = FALSE;

    } else {

        //
        // The provided buffers are large enough.  Build the SID in the
        // return buffer by combining the Domain Sid returned by
        // LsaLookupNames() with the Relative Id returned.  The final SID
        // will have one more SubAuthority than the Domain Sid.
        //

        CopySid( *cbSid, Sid, ReturnedDomainSid );
        *GetSidSubAuthorityCount( Sid ) = nSubAuthorities;
        *GetSidSubAuthority( Sid, (DWORD)(nSubAuthorities - 1) ) = TranslatedSid->RelativeId;

        //
        // Copy the Domain Name into the return buffer and NULL terminate it.
        //

        TmpString.Buffer = ReferencedDomainName;
        TmpString.Length = 0;

        //
        // Watch for overflow of 16-bit name length
        //

        if (*cbReferencedDomainName < (DWORD) 32767) {

            TmpString.MaximumLength = (USHORT)((*cbReferencedDomainName) * sizeof(WCHAR));

        } else {

            TmpString.MaximumLength = (USHORT) 65534;
        }

        RtlCopyUnicodeString( &TmpString, &ReferencedDomains->Domains->Name );

        TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;

        //
        // Copy the Sid Use field.
        //

        *peUse = TranslatedSid->Use;

        //
        // Return the size (in Wide Characters, excluding the terminating
        // null) of the returned Referenced Domain Name.
        //

        *cbReferencedDomainName = ReturnedDomainNameSize;

        Rc = TRUE;
    }

    //
    // If necessary, free the structures returned by the LsaLookupNames()
    // function.
    //

    if (ReferencedDomains !=  NULL) {

        Status = LsaFreeMemory( ReferencedDomains );
        ASSERT( NT_SUCCESS( Status ));
    }

    if (TranslatedSid != NULL) {

        Status = LsaFreeMemory( TranslatedSid );
        ASSERT( NT_SUCCESS( Status ));
    }

    return( Rc );
}



BOOL
APIENTRY
LookupAccountSidA(
    LPCSTR lpSystemName,
    PSID lpSid,
    LPSTR lpName,
    LPDWORD cbName,
    LPSTR lpReferencedDomainName,
    LPDWORD cbReferencedDomainName,
    PSID_NAME_USE peUse
    )
/*++

Routine Description:

    ANSI Thunk to LookupAccountSidW

Arguments:

    lpSystemName - Supplies the name of the system at which the lookup
        is to be performed.  If the null string is provided, the local
        system is assumed.

    lpSid - Supplies the account Sid.

    lpName - Returns the name corresponding to the passed account SID.

    cbName - Supplies the size (in Ansi characters) of the buffer passed in for
        lpName.  This size must allow one character for the null terminator
        that will be appended to the returned name.  If the buffer size is not
        large enough, this parameter will return the size necessary to hold
        the null-terminated output name.  If the buffer size is large enough,
        this parameter will return the size (in Ansi characters, excluding
        the null terminator) of the name returned.

    lpReferencedDomainName - Returns the name of the domain in which the
        name was found.

    cbReferencedDomainName - Supplies the size (in Ansi characters) of the
        ReferencedDomainName buffer.  This size must allow one charcter for the
        null terminator that will be appended to the returned name.  If the
        buffer size is not large enough, this parameter will return the size
        necessary to hold the output null-terminated domain name.  If the
        buffer size is large enough, the size of the returned name, excluding
        the terminating null will be returned.

    peUse - Returns an enumerated type indicating the type of the
        account.


Return Value:

    BOOL - TRUE if successful, else FALSE.

--*/

{
    NTSTATUS Status;
    LPWSTR WName = NULL;
    LPWSTR WReferencedDomainName = NULL;
    BOOL BoolStatus;
    ANSI_STRING AnsiString;
    UNICODE_STRING UnicodeString;
    UNICODE_STRING SystemName;
    PWSTR pSystemName = NULL;
    DWORD cbInitName, cbInitReferencedDomainName;

    //
    // Save the original buffer sizes specified for the returned account Name
    // and Referenced Domain Name.
    //

    cbInitName = *cbName;
    cbInitReferencedDomainName = *cbReferencedDomainName;

    //
    // Construct temporary buffers for the Name and Domain information
    // that are twice the size of those passed in to adjust for the
    // intermediate conversion to WCHAR strings.
    //

    if ( *cbName > 0 ) {
        WName = LocalAlloc( LMEM_FIXED, (*cbName) * sizeof(WCHAR));
    }

    if ( *cbReferencedDomainName > 0 ) {
        WReferencedDomainName =
            LocalAlloc( LMEM_FIXED, (*cbReferencedDomainName) * sizeof(WCHAR));
    }

    if ( ARGUMENT_PRESENT( lpSystemName ) ) {

        RtlInitAnsiString( &AnsiString, lpSystemName );
        RtlAnsiStringToUnicodeString( &SystemName, &AnsiString, TRUE );
        pSystemName = SystemName.Buffer;
    }

    BoolStatus = LookupAccountSidW(
                     (LPCWSTR)pSystemName,
                     lpSid,
                     WName,
                     cbName,
                     WReferencedDomainName,
                     cbReferencedDomainName,
                     peUse
                     );

    if ( ARGUMENT_PRESENT( lpSystemName ) ) {
        RtlFreeUnicodeString( &SystemName );
    }

    if ( BoolStatus ) {

        //
        // Copy the Name and DomainName information into the passed CHAR
        // buffers.
        //

        if ( ARGUMENT_PRESENT(lpName) ) {

            AnsiString.Buffer = lpName;

            //
            // Watch for 16-bit overflow on buffer size.  Clamp size to
            // 16 bits if necessary.
            //

            if (cbInitName <= (DWORD) 65535) {

                AnsiString.MaximumLength = (USHORT) cbInitName;

            } else {

                AnsiString.MaximumLength = (USHORT) 65535;
            }

            RtlInitUnicodeString( &UnicodeString, WName );
            Status = RtlUnicodeStringToAnsiString( &AnsiString,
                                                   &UnicodeString,
                                                   FALSE );
            ASSERT(NT_SUCCESS(Status));
            AnsiString.Buffer[AnsiString.Length] = 0;
        }

        if ( ARGUMENT_PRESENT(lpReferencedDomainName) ) {

            AnsiString.Buffer = lpReferencedDomainName;

            //
            // Watch for 16-bit overflow on buffer size.  Clamp size to
            // 16 bits if necessary.
            //

            if (cbInitReferencedDomainName <= (DWORD) 65535) {

                AnsiString.MaximumLength = (USHORT) cbInitReferencedDomainName;

            } else {

                AnsiString.MaximumLength = (USHORT) 65535;
            }

            RtlInitUnicodeString( &UnicodeString, WReferencedDomainName );
            Status = RtlUnicodeStringToAnsiString( &AnsiString,
                                                   &UnicodeString,
                                                   FALSE );
            ASSERT(NT_SUCCESS(Status));
            AnsiString.Buffer[AnsiString.Length] = 0;
        }

    }

    if (ARGUMENT_PRESENT(WName)) {
        LocalFree( WName );
    }
    if (ARGUMENT_PRESENT(WReferencedDomainName)) {
        LocalFree( WReferencedDomainName );
    }

    return( BoolStatus );
}

 


BOOL
APIENTRY
LookupAccountSidW(
    LPCWSTR lpSystemName,
    PSID lpSid,
    LPWSTR lpName,
    LPDWORD cbName,
    LPWSTR lpReferencedDomainName,
    LPDWORD cbReferencedDomainName,
    PSID_NAME_USE peUse
    )

/*++

Routine Description:

    Translates a passed SID into an account name.  It will also return
    the name and SID of the first domain in which this SID was found.

Arguments:

    lpSystemName - Supplies the name of the system at which the lookup
        is to be performed.  If the null string is provided, the local
        system is assumed.

    lpSid - Supplies the account Sid.

    lpName - Returns the name corresponding to the passed account SID.

    cbName - Supplies the size (in Wide characters) of the buffer passed in for
        lpName.  This size must allow one character for the null terminator
        that will be appended to the returned name.  If the buffer size is not
        large enough, this parameter will return the size necessary to hold
        the null-terminated output name.  If the buffer size is large enough,
        this parameter will return the size (in Ansi characters, excluding
        the null terminator) of the name returned.

    lpReferencedDomainName - Returns the name of the domain in which the
        name was found.

    cbReferencedDomainName - Supplies the size (in Wide characters) of the
        ReferencedDomainName buffer.  This size must allow one charcter for the
        null terminator that will be appended to the returned name.  If the
        buffer size is not large enough, this parameter will return the size
        necessary to hold the output null-terminated domain name.  If the
        buffer size is large enough, the size of the returned name, excluding
        the terminating null will be returned.

    peUse - Returns an enumerated type inidicating the type of the
        account.

Return Value:

    BOOL - TRUE if successful, else FALSE.

--*/

{
    PLSA_TRANSLATED_NAME Names;
    OBJECT_ATTRIBUTES ObjectAttributes;
    LSA_HANDLE PolicyHandle;
    PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains;
    DWORD ReturnedDomainNameSize;
    DWORD ReturnedNameSize;
    SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
    NTSTATUS Status;
    UNICODE_STRING TmpString;
    NTSTATUS TmpStatus;
    UNICODE_STRING SystemName;
    PUNICODE_STRING pSystemName = NULL;
    BOOLEAN Rc = FALSE;

    SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
    SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
    SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    SecurityQualityOfService.EffectiveOnly = FALSE;

    //
    // Set up the object attributes prior to opening the LSA.
    //

    InitializeObjectAttributes(
        &ObjectAttributes,
        NULL,
        0L,
        NULL,
        NULL
        );

    //
    // The InitializeObjectAttributes macro presently stores NULL for
    // the SecurityQualityOfService field, so we must manually copy that
    // structure for now.
    //

    ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;

    if ( ARGUMENT_PRESENT( lpSystemName )) {
        RtlInitUnicodeString( &SystemName, lpSystemName );
        pSystemName = &SystemName;
    }

    Status = LsaOpenPolicy(
                 pSystemName,
                 &ObjectAttributes,
                 POLICY_LOOKUP_NAMES,
                 &PolicyHandle
                 );

    if ( !NT_SUCCESS( Status )) {

        BaseSetLastNTError( Status );
        return( FALSE );
    }

    Status = LsaLookupSids(
                 PolicyHandle,
                 1,
                 &lpSid,
                 &ReferencedDomains,
                 &Names
                 );

    TmpStatus = LsaClose( PolicyHandle );

    if (!NT_SUCCESS( TmpStatus )) {
        RpcSsDestroyClientContext( &PolicyHandle );
    }

    //
    // If an error was returned, check specifically for STATUS_NONE_MAPPED.
    // In this case, we may need to dispose of the returned Referenced Domain
    // List and Names structures.  For all other errors, LsaLookupSids()
    // frees these structures prior to exit.
    //

    if ( !NT_SUCCESS( Status )) {

        if (Status == STATUS_NONE_MAPPED) {

            if (ReferencedDomains != NULL) {

                TmpStatus = LsaFreeMemory( ReferencedDomains );
                ASSERT( NT_SUCCESS( TmpStatus ));
            }

            if (Names != NULL) {

                TmpStatus = LsaFreeMemory( Names );
                ASSERT( NT_SUCCESS( TmpStatus ));
            }
        }

        BaseSetLastNTError( Status );
        return( FALSE );
    }

    //
    // The Sid was successfully translated.  There should be exactly
    // one Referenced Domain and its DomainIndex should be zero.
    //

    ReturnedNameSize = (Names->Name.Length / sizeof(WCHAR));

    ASSERT(Names->DomainIndex == 0);
    ASSERT(ReferencedDomains != NULL);
    ASSERT(ReferencedDomains->Domains != NULL);
    ReturnedDomainNameSize = (ReferencedDomains->Domains->Name.Length / sizeof(WCHAR));

    //
    // Check if buffer sizes  for the Name and Referenced Domain Name are too
    // small.  The sizes in Wide characters provided must allow for the null
    // terminator that will be appended to the returned names.
    //

    if ((ReturnedNameSize + 1 > *cbName) ||
        (ReturnedDomainNameSize + 1 > *cbReferencedDomainName)) {

        //
        // One or both buffers are too small.  Return sizes required for
        // both buffers, allowing one character for the null terminator.
        //

        *cbReferencedDomainName = ReturnedDomainNameSize + 1;
        *cbName = ReturnedNameSize + 1;
        BaseSetLastNTError( STATUS_BUFFER_TOO_SMALL );
        Rc = FALSE;

    } else {

        //
        // Both buffers are of sufficient size.  Copy in the Name
        // information and add NULL terminators.
        //

        TmpString.Buffer = lpName;
        TmpString.Length = 0;

        //
        // Watch for 16-bit overflow on buffer size.  Clamp size to
        // 16 bits if necessary.
        //

        if (*cbName <= 32766) {

            TmpString.MaximumLength = (USHORT)((*cbName) * sizeof(WCHAR));

        } else {

            TmpString.MaximumLength = (USHORT) 65532;
        }

        if ((*cbName) > 0) {

            RtlCopyUnicodeString( &TmpString, &Names->Name );
            TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;
        }

        //
        // Copy in the Referenced Domain information.
        //

        TmpString.Buffer = lpReferencedDomainName;
        TmpString.Length = 0;

        //
        // Watch for 16-bit overflow on buffer size.  Clamp size to
        // 16 bits if necessary.
        //

        if (*cbReferencedDomainName <= 32767) {

            TmpString.MaximumLength = (USHORT)((*cbReferencedDomainName) * sizeof(WCHAR));

        } else {

            TmpString.MaximumLength = (USHORT) 65534;
        }

        RtlCopyUnicodeString( &TmpString, &ReferencedDomains->Domains->Name );
        TmpString.Buffer[TmpString.Length/sizeof(WCHAR)] = (WCHAR) 0;

        //
        // Return the sizes (in Wide Characters, excluding the terminating
        // null) of the name and domain name.
        //

        *cbReferencedDomainName = ReturnedDomainNameSize;
        *cbName = ReturnedNameSize;

        // Copy in the Use field.
        //

        *peUse = Names->Use;
        Rc = TRUE;
    }

    //
    // If necessary, free output buffers returned by LsaLookupSids
    //

    if (Names != NULL) {

        Status = LsaFreeMemory( Names );
        ASSERT( NT_SUCCESS( Status ));
    }

    if (ReferencedDomains != NULL) {

        Status = LsaFreeMemory( ReferencedDomains );
        ASSERT( NT_SUCCESS( Status ));
    }

    return(Rc);
}


BOOL
APIENTRY
LookupPrivilegeValueA(
    LPCSTR lpSystemName,
    LPCSTR lpName,
    PLUID lpLuid
    )
/*++

Routine Description:

    ANSI Thunk to LookupPrivilegeValueW().

Arguments:


Return Value:


--*/
{
    NTSTATUS Status;
    UNICODE_STRING USystemName, UName;
    ANSI_STRING ASystemName, AName;
    BOOL bool;

    RtlInitAnsiString( &ASystemName, lpSystemName );
    RtlInitAnsiString( &AName, lpName );

    USystemName.Buffer = NULL;
    UName.Buffer = NULL;

    Status = RtlAnsiStringToUnicodeString( &USystemName, &ASystemName, TRUE );
    if (NT_SUCCESS(Status)) {

        Status = RtlAnsiStringToUnicodeString( &UName, &AName, TRUE );
        if (NT_SUCCESS(Status)) {


            bool = LookupPrivilegeValueW( (LPCWSTR)USystemName.Buffer,
                                          (LPCWSTR)UName.Buffer,
                                          lpLuid
                                          );

            RtlFreeUnicodeString( &UName );
        }

        RtlFreeUnicodeString( &USystemName );
    }

    if (!NT_SUCCESS(Status)) {

        BaseSetLastNTError( Status );
        return( FALSE );

    }

    return(bool);


}

BOOL
APIENTRY
LookupPrivilegeValueW(
    LPCWSTR lpSystemName,
    LPCWSTR lpName,
    PLUID  lpLuid
    )

/*++

Routine Description:


    This function retrieves the value used on the target system
    to locally represent the specified privilege.  The privilege
    is specified by programmatic name.


Arguments:

    lpSystemName - Supplies the name of the system at which the lookup
        is to be performed.  If the null string is provided, the local
        system is assumed.

    lpName - provides the privilege's programmatic name.

    lpLuid - Receives the locally unique ID the privilege is known by on the
        target machine.


Return Value:

 

--*/
{
    NTSTATUS                    Status,
                                TmpStatus;

    LSA_HANDLE                  PolicyHandle;

    OBJECT_ATTRIBUTES           ObjectAttributes;

    SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;

    UNICODE_STRING              USystemName,
                                UName;

    PUNICODE_STRING             SystemName = NULL;


    SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
    SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
    SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    SecurityQualityOfService.EffectiveOnly = FALSE;

    //
    // Set up the object attributes prior to opening the LSA.
    //

    InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
    ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;


    if ( ARGUMENT_PRESENT( lpSystemName )) {
        RtlInitUnicodeString( &USystemName, lpSystemName );
        SystemName = &USystemName;
    }

    Status = LsaOpenPolicy(
                 SystemName,
                 &ObjectAttributes,
                 POLICY_LOOKUP_NAMES,
                 &PolicyHandle
                 );

    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }

 

    RtlInitUnicodeString( &UName, lpName );
    Status = LsaLookupPrivilegeValue( PolicyHandle, &UName, lpLuid );

    TmpStatus = LsaClose( PolicyHandle );
    ASSERT( NT_SUCCESS( TmpStatus ));


    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }


    return(TRUE);
}



BOOL
APIENTRY
LookupPrivilegeNameA(
    LPCSTR   lpSystemName,
    PLUID   lpLuid,
    LPSTR   lpName,
    LPDWORD cchName
    )
/*++

Routine Description:

    ANSI Thunk to LookupPrivilegeValueW().

Arguments:


Return Value:


--*/
{
    NTSTATUS       Status;

    ANSI_STRING    AnsiName;
    LPWSTR         UnicodeBuffer;
    UNICODE_STRING UnicodeString;

    ANSI_STRING    AnsiSystemName;
    UNICODE_STRING UnicodeSystemName;
    DWORD          LengthRequired;

    //
    // Convert the passed SystemName to Unicode.  Let the Rtl function
    // allocate the memory we need.
    //

    RtlInitAnsiString( &AnsiSystemName, lpSystemName );
    Status = RtlAnsiStringToUnicodeString( &UnicodeSystemName, &AnsiSystemName, TRUE );

    if (!NT_SUCCESS( Status )) {

        BaseSetLastNTError( Status );
        return( FALSE );
    }

    //
    // Make sure we don't exceed the limits of a unicode string.
    //

    if (*cchName > 0xFFFC) {
        *cchName = 0xFFFC;
    }

    UnicodeBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, *cchName * sizeof(WCHAR) );

    if (UnicodeBuffer == NULL) {

        RtlFreeUnicodeString( &UnicodeSystemName );
        BaseSetLastNTError( STATUS_NO_MEMORY );
        return( FALSE );
    }

    //
    // Don't pass in cchName, since it will be overwritten by LookupPrivilegeNameW,
    // and we need it later.
    //

    LengthRequired = *cchName;

    if (!LookupPrivilegeNameW( (LPCWSTR)UnicodeSystemName.Buffer,
                               lpLuid,
                               UnicodeBuffer,
                               &LengthRequired
                               )) {

        RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
        RtlFreeUnicodeString( &UnicodeSystemName );
        *cchName = LengthRequired;
        return(FALSE);
    }

    //
    // Now convert back to ANSI for the caller
    //

    RtlInitUnicodeString(&UnicodeString, UnicodeBuffer);

    AnsiName.Buffer = lpName;
    AnsiName.Length = 0;
    AnsiName.MaximumLength = (USHORT)*cchName;

    Status = RtlUnicodeStringToAnsiString(&AnsiName, &UnicodeString, FALSE);

    ASSERT( NT_SUCCESS( Status ));

    *cchName = AnsiName.Length;

    RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
    RtlFreeUnicodeString( &UnicodeSystemName );

    return(TRUE);
}



BOOL
APIENTRY
LookupPrivilegeNameW(
    LPCWSTR  lpSystemName,
    PLUID   lpLuid,
    LPWSTR  lpName,
    LPDWORD cchName
    )
/*++

Routine Description:


    This function returns the programmatic name corresponding to
    the privilege represented on the target system by the provided
    LUID.


Arguments:


    lpSystemName - Supplies the name of the system at which the lookup
        is to be performed.  If the null string is provided, the local
        system is assumed.


    lpLuid - is the locally unique ID the privilege is known by on the
        target machine.

    lpName - Receives the privilege's programmatic name.

    cchName - indicates how large the buffer is (in characters).  This
        count does not include the null-terminator that is added at the
        end of the string.

 

Return Value:

 

--*/
{
    NTSTATUS                    Status,
                                TmpStatus;
    LSA_HANDLE                  PolicyHandle;
    OBJECT_ATTRIBUTES           ObjectAttributes;
    SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
    UNICODE_STRING              USystemName;
    PUNICODE_STRING             SystemName,
                                UName;


    SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
    SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
    SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    SecurityQualityOfService.EffectiveOnly = FALSE;

    //
    // Set up the object attributes prior to opening the LSA.
    //

    InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
    ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;


    SystemName = NULL;
    if ( ARGUMENT_PRESENT( lpSystemName )) {
        RtlInitUnicodeString( &USystemName, lpSystemName );
        SystemName = &USystemName;
    }

    Status = LsaOpenPolicy(
                 SystemName,
                 &ObjectAttributes,
                 POLICY_LOOKUP_NAMES,
                 &PolicyHandle
                 );

    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }


    UName = NULL;
    Status = LsaLookupPrivilegeName( PolicyHandle,lpLuid, &UName );

    if (NT_SUCCESS(Status) ) {

        if ((DWORD)UName->Length + sizeof( WCHAR) > (*cchName) * sizeof( WCHAR )) {
            Status = STATUS_BUFFER_TOO_SMALL;
            (*cchName) = ( UName->Length + sizeof( WCHAR) ) / sizeof( WCHAR );

        } else {

            RtlMoveMemory( lpName, UName->Buffer, UName->Length );
            lpName[UName->Length/sizeof(WCHAR)] = 0;  // NULL terminate it
            (*cchName) = UName->Length / sizeof( WCHAR );
        }

        LsaFreeMemory( UName->Buffer );
        LsaFreeMemory( UName );
    }

    TmpStatus = LsaClose( PolicyHandle );
    ASSERT( NT_SUCCESS( TmpStatus ));


    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }


    return(TRUE);
}



BOOL
APIENTRY
LookupPrivilegeDisplayNameA(
    LPCSTR   lpSystemName,
    LPCSTR   lpName,
    LPSTR   lpDisplayName,
    LPDWORD cchDisplayName,
    LPDWORD lpLanguageId
    )

/*++

Routine Description:

    ANSI Thunk to LookupPrivilegeValueW().

Arguments:


Return Value:


--*/
{
    NTSTATUS                Status;

    UNICODE_STRING          UnicodeSystemName;
    UNICODE_STRING          UnicodeString;
    UNICODE_STRING          UnicodeName;

    ANSI_STRING             AnsiSystemName;
    ANSI_STRING             AnsiDisplayName;
    ANSI_STRING             AnsiName;

    LPWSTR                  UnicodeBuffer;
    DWORD                   RequiredLength;


    RtlInitAnsiString( &AnsiSystemName, lpSystemName );
    Status = RtlAnsiStringToUnicodeString( &UnicodeSystemName, &AnsiSystemName, TRUE );

    if (!NT_SUCCESS( Status )) {

        BaseSetLastNTError( Status );
        return( FALSE );
    }

    //
    // Make sure we don't exceed that limits of a unicode string.
    //

    if (*cchDisplayName > 0xFFFC) {
        *cchDisplayName = 0xFFFC;
    }

    UnicodeBuffer =  RtlAllocateHeap( RtlProcessHeap(), 0, *cchDisplayName * sizeof(WCHAR));

    if (UnicodeBuffer == NULL) {

        RtlFreeUnicodeString( &UnicodeSystemName );
        BaseSetLastNTError( STATUS_NO_MEMORY );
        return( FALSE );
    }

    RtlInitAnsiString( &AnsiName, lpName );
    Status = RtlAnsiStringToUnicodeString( &UnicodeName, &AnsiName, TRUE );

    if (!NT_SUCCESS( Status )) {

        RtlFreeUnicodeString( &UnicodeSystemName );
        RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
        BaseSetLastNTError( Status );
        return( FALSE );
    }

    RequiredLength = *cchDisplayName;

    if (! LookupPrivilegeDisplayNameW( (LPCWSTR)UnicodeSystemName.Buffer,
                                       (LPCWSTR)UnicodeName.Buffer,
                                       UnicodeBuffer,
                                       &RequiredLength,
                                       lpLanguageId
                                       )) {

        //
        // No need to set last error here, we can assume the W routine did so.
        //

        *cchDisplayName = RequiredLength;

        RtlFreeUnicodeString( &UnicodeSystemName );
        RtlFreeUnicodeString( &UnicodeName );
        RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );
        return( FALSE );
    }

    //
    // Now convert back to ANSI for the caller
    //

    RtlInitUnicodeString( &UnicodeString, UnicodeBuffer );

    AnsiDisplayName.Buffer = lpDisplayName;
    AnsiDisplayName.Length = 0;
    AnsiDisplayName.MaximumLength = (USHORT)(*cchDisplayName);

    Status = RtlUnicodeStringToAnsiString( &AnsiDisplayName, &UnicodeString, FALSE );

    ASSERT( NT_SUCCESS( Status ));

    *cchDisplayName = AnsiDisplayName.Length;

    RtlFreeUnicodeString( &UnicodeSystemName );
    RtlFreeUnicodeString( &UnicodeName );
    RtlFreeHeap( RtlProcessHeap(), 0, UnicodeBuffer );

    return( TRUE );
}



BOOL
APIENTRY
LookupPrivilegeDisplayNameW(
    LPCWSTR  lpSystemName,
    LPCWSTR  lpName,
    LPWSTR  lpDisplayName,
    LPDWORD cchDisplayName,
    LPDWORD lpLanguageId
    )

/*++

Routine Description:

    This function retrieves a displayable name representing the
    specified privilege.


Arguments:

    lpSystemName - Supplies the name of the system at which the lookup
        is to be performed.  If the null string is provided, the local
        system is assumed.


    lpName - provides the privilege's programmatic name.


    lpDisplayName - Receives the privilege's displayable name.

    cchDisplayName - indicates how large the buffer is (in characters).  This
        count does not include the null-terminator that is added at the
        end of the string.

    lpLanguageId - Receives the language of the returned displayable
        name.


Return Value:


--*/

{
    NTSTATUS                    Status,
                                TmpStatus;

    LSA_HANDLE                  PolicyHandle;

    OBJECT_ATTRIBUTES           ObjectAttributes;

    SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;

    UNICODE_STRING              USystemName,
                                UName;

    PUNICODE_STRING             SystemName,
                                UDisplayName;

    SHORT                       LanguageId;


    SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
    SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
    SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    SecurityQualityOfService.EffectiveOnly = FALSE;

    //
    // Set up the object attributes prior to opening the LSA.
    //

    InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NULL );
    ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;


    SystemName = NULL;
    if ( ARGUMENT_PRESENT( lpSystemName )) {
        RtlInitUnicodeString( &USystemName, lpSystemName );
        SystemName = &USystemName;
    }

    Status = LsaOpenPolicy(
                 SystemName,
                 &ObjectAttributes,
                 POLICY_LOOKUP_NAMES,
                 &PolicyHandle
                 );

    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }

    RtlInitUnicodeString( &UName, lpName );


    UDisplayName = NULL;
    Status = LsaLookupPrivilegeDisplayName( PolicyHandle,
                                            &UName,
                                            &UDisplayName,
                                            &LanguageId
                                            );
    (*lpLanguageId) = LanguageId;

    if (NT_SUCCESS(Status)) {

        if (UDisplayName->Length + sizeof(WCHAR) > (*cchDisplayName) * sizeof(WCHAR)) {
            Status = STATUS_BUFFER_TOO_SMALL;
            (*cchDisplayName) = (UDisplayName->Length + sizeof( WCHAR )) / sizeof( WCHAR );

        } else {

            RtlMoveMemory( lpDisplayName,
                           UDisplayName->Buffer,
                           UDisplayName->Length
                           );
            lpDisplayName[UDisplayName->Length/sizeof(WCHAR)] = 0;  // Null terminate it.
            (*cchDisplayName) = UDisplayName->Length / sizeof( WCHAR );
        }

        LsaFreeMemory( UDisplayName->Buffer );
        LsaFreeMemory( UDisplayName );

    }
    TmpStatus = LsaClose( PolicyHandle );
    ASSERT( NT_SUCCESS( TmpStatus ));


    if ( !NT_SUCCESS( Status )) {
        BaseSetLastNTError( Status );
        return( FALSE );
    }


    return(TRUE);
}


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

VOID
SepFormatAccountSid(
    PSID Sid,
    LPWSTR OutputBuffer
    )
{
    UCHAR Buffer[128];
    UCHAR TmpBuffer[128];
    ANSI_STRING AccountName;
    UCHAR i;
    ULONG Tmp;
    UNICODE_STRING OutputString;
    PISID iSid;
    NTSTATUS Status;

    //
    // Do everything as ANSI for the time being, and then
    // convert to wide-char at the bottom.
    //
    // We need to do this until we have more complete c-runtime support
    // for w-char strings.
    //

    iSid = (PISID) Sid;

    OutputString.Buffer = OutputBuffer;
    OutputString.MaximumLength = 127;

    Buffer[0] = 0;
    TmpBuffer[0] = 0;

    AccountName.MaximumLength = 127;
    AccountName.Length = (USHORT)((GetLengthSid( Sid ) > MAXUSHORT) ? MAXUSHORT : GetLengthSid( Sid ));
    AccountName.Buffer = Buffer;

    sprintf(TmpBuffer, "S-%u-", (USHORT)iSid->Revision );
    lstrcpy(Buffer, TmpBuffer);

    if (  (iSid->IdentifierAuthority.Value[0] != 0)  ||
          (iSid->IdentifierAuthority.Value[1] != 0)     ){
        sprintf(TmpBuffer, "0x%02hx%02hx%02hx%02hx%02hx%02hx",
                    (USHORT)iSid->IdentifierAuthority.Value[0],
                    (USHORT)iSid->IdentifierAuthority.Value[1],
                    (USHORT)iSid->IdentifierAuthority.Value[2],
                    (USHORT)iSid->IdentifierAuthority.Value[3],
                    (USHORT)iSid->IdentifierAuthority.Value[4],
                    (USHORT)iSid->IdentifierAuthority.Value[5] );
        lstrcat(Buffer, TmpBuffer);
    } else {
        Tmp = (ULONG)iSid->IdentifierAuthority.Value[5]          +
              (ULONG)(iSid->IdentifierAuthority.Value[4] <<  8)  +
              (ULONG)(iSid->IdentifierAuthority.Value[3] << 16)  +
              (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
        sprintf(TmpBuffer, "%lu", Tmp);
        lstrcat(Buffer, TmpBuffer);
    }

    for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
        sprintf(TmpBuffer, "-%lu", iSid->SubAuthority[i]);
        lstrcat(Buffer, TmpBuffer);
    }

    Status = RtlAnsiStringToUnicodeString( &OutputString, &AccountName, FALSE );

    ASSERT( NT_SUCCESS( Status ));

    return;
}
 

原创粉丝点击