/****************************************************************************

   PROGRAM: ACLEDIT.C

   PURPOSE: Contains routines that edit security on Nt objects

****************************************************************************/

#include "pviewp.h"
#include <sedapi.h>


//
// Define the type of a pointer to the DACL editor fn
//

typedef DWORD (*LPFNDACLEDITOR) (   HWND,
                                    HANDLE,
                                    LPWSTR,
                                    PSED_OBJECT_TYPE_DESCRIPTOR,
                                    PSED_APPLICATION_ACCESSES,
                                    LPWSTR,
                                    PSED_FUNC_APPLY_SEC_CALLBACK,
                                    ULONG_PTR,
                                    PSECURITY_DESCRIPTOR,
                                    BOOLEAN,
                                    BOOLEAN,    // CantWriteDacl
                                    LPDWORD,
                                    DWORD  );


//
// Declare globals used to reference dynamically loaded ACLEditor module
//

HMODULE hModAclEditor = NULL;
LPFNDACLEDITOR lpfnDaclEditor = NULL;






//
// Define security information for each type of object
//



//
// Define the maximum number of accesses per object type
//

#define MAX_ACCESSES    30


//
// Define structure to contain the security information for
// an object type
//

typedef struct _OBJECT_TYPE_SECURITY_INFO {
    LPWSTR  TypeName;
    SED_HELP_INFO HelpInfo ;
    SED_OBJECT_TYPE_DESCRIPTOR SedObjectTypeDescriptor;
    GENERIC_MAPPING GenericMapping;
    SED_APPLICATION_ACCESSES AppAccesses ;
    SED_APPLICATION_ACCESS AppAccess[MAX_ACCESSES];

} OBJECT_TYPE_SECURITY_INFO, *POBJECT_TYPE_SECURITY_INFO;


//
// Define name of help file
//

#define HELP_FILENAME   L"pview.hlp"



//
// Define dummy access (used as filler)
//

#define DUMMY_ACCESS                                                \
    {                                                               \
        0,                                                          \
        0,                                                          \
        0,                                                          \
        NULL                                                        \
    }



//
// Define generic accesses
//

#define GENERIC_ACCESSES_5(Type)                                    \
    {                                                               \
        Type,                                                       \
        GENERIC_ALL,                                                \
        0,                                                          \
        L"All Access"                                               \
    },                                                              \
    {                                                               \
        Type,                                                       \
        GENERIC_READ,                                               \
        0,                                                          \
        L"Read"                                                     \
    },                                                              \
    {                                                               \
        Type,                                                       \
        GENERIC_WRITE,                                              \
        0,                                                          \
        L"Write"                                                    \
    },                                                              \
    {                                                               \
        Type,                                                       \
        GENERIC_EXECUTE,                                            \
        0,                                                          \
        L"Execute"                                                  \
    },                                                              \
    {                                                               \
        Type,                                                       \
        0,                                                          \
        0,                                                          \
        L"None"                                                     \
    }


//
// Define generic accesses to be shown in special access dialog
//

#define SPECIAL_GENERIC_ACCESSES_4(Type)                            \
    {                                                               \
        Type,                                                       \
        GENERIC_ALL,                                                \
        0,                                                          \
        L"Generic All"                                              \
    },                                                              \
    {                                                               \
        Type,                                                       \
        GENERIC_READ,                                               \
        0,                                                          \
        L"Generic Read"                                             \
    },                                                              \
    {                                                               \
        Type,                                                       \
        GENERIC_WRITE,                                              \
        0,                                                          \
        L"Generic Write"                                            \
    },                                                              \
    {                                                               \
        Type,                                                       \
        GENERIC_EXECUTE,                                            \
        0,                                                          \
        L"Generic Execute"                                          \
    }


//
// Define standard accesses
//

#define STANDARD_ACCESSES_5(Type)                                   \
    {                                                               \
        Type,                                                       \
        DELETE,                                                     \
        0,                                                          \
        L"Delete"                                                   \
    },                                                              \
    {                                                               \
        Type,                                                       \
        READ_CONTROL,                                               \
        0,                                                          \
        L"Read Control"                                             \
    },                                                              \
    {                                                               \
        Type,                                                       \
        WRITE_DAC,                                                  \
        0,                                                          \
        L"Write DAC"                                                \
    },                                                              \
    {                                                               \
        Type,                                                       \
        WRITE_OWNER,                                                \
        0,                                                          \
        L"Write Owner"                                              \
    },                                                              \
    {                                                               \
        Type,                                                       \
        SYNCHRONIZE,                                                \
        0,                                                          \
        L"Synchronize"                                              \
    }




//
// Define security info for 'DEFAULT' ACLs found in tokens
//

OBJECT_TYPE_SECURITY_INFO DefaultSecurityInfo = {

    //
    // Type name
    //

    L"DEFAULT",

    //
    // Help info
    //

    {
        HELP_FILENAME,
        {0, 0, 0, 0, 0, 0, 0}
    },



    //
    // Acleditor object type descriptor
    //

    {
        SED_REVISION1,          // Revision
        FALSE,                  // Is container
        FALSE,                  // AllowNewObjectPermissions
        FALSE,                  // MapSpecificPermsToGeneric
        NULL,                   // Pointer to generic mapping
        NULL,                   // Pointer to generic mapping for new objects
        L"Default",             // Object type name
        NULL,                   // Pointer to help info
        NULL,                   // ApplyToSubContainerTitle
        NULL,                   // ApplyToObjectsTitle
        NULL,                   // ApplyToSubContainerConfirmation
        L"Special...",          // SpecialObjectAccessTitle
        NULL                    // SpecialNewObjectAccessTitle
    },



    //
    // Generic mapping
    //

    {
        STANDARD_RIGHTS_READ,
        STANDARD_RIGHTS_WRITE,
        STANDARD_RIGHTS_EXECUTE,
        STANDARD_RIGHTS_ALL
    },


    //
    // Application access structure
    //

    {
        14,                 // Access count (must match list below)
        NULL,               // Pointer to accesses
        L"Read",            // Default new access
    },


    //
    // Application accesses
    //

    {
        GENERIC_ACCESSES_5(SED_DESC_TYPE_RESOURCE),
        STANDARD_ACCESSES_5(SED_DESC_TYPE_RESOURCE_SPECIAL),
        SPECIAL_GENERIC_ACCESSES_4(SED_DESC_TYPE_RESOURCE_SPECIAL),

        DUMMY_ACCESS, // 15
        DUMMY_ACCESS, // 16
        DUMMY_ACCESS, // 17
        DUMMY_ACCESS, // 18
        DUMMY_ACCESS, // 19
        DUMMY_ACCESS, // 20
        DUMMY_ACCESS, // 21
        DUMMY_ACCESS, // 22
        DUMMY_ACCESS, // 23
        DUMMY_ACCESS, // 24
        DUMMY_ACCESS, // 25
        DUMMY_ACCESS, // 26
        DUMMY_ACCESS, // 27
        DUMMY_ACCESS, // 28
        DUMMY_ACCESS, // 29
        DUMMY_ACCESS  // 30
    }
};





//
// Define security info for each type of object
//

OBJECT_TYPE_SECURITY_INFO ObjectTypeSecurityInfo[] = {

    //
    // PROCESS
    //

    {
        //
        // Type name
        //

        L"Process",

        //
        // Help info
        //

        {
            HELP_FILENAME,
            {0, 0, 0, 0, 0, 0, 0}
        },



        //
        // Acleditor object type descriptor
        //

        {
            SED_REVISION1,          // Revision
            FALSE,                  // Is container
            FALSE,                  // AllowNewObjectPermissions
            FALSE,                  // MapSpecificPermsToGeneric
            NULL,                   // Pointer to generic mapping
            NULL,                   // Pointer to generic mapping for new objects
            L"Process",             // Object type name
            NULL,                   // Pointer to help info
            NULL,                   // ApplyToSubContainerTitle
            NULL,                   // ApplyToObjectsTitle
            NULL,                   // ApplyToSubContainerConfirmation
            L"Special...",          // SpecialObjectAccessTitle
            NULL                    // SpecialNewObjectAccessTitle
        },



        //
        // Generic mapping
        //

        {
            PROCESS_QUERY_INFORMATION | STANDARD_RIGHTS_READ,
            PROCESS_SET_INFORMATION | STANDARD_RIGHTS_WRITE,
            STANDARD_RIGHTS_EXECUTE,
            PROCESS_ALL_ACCESS
        },


        //
        // Application access structure
        //

        {
            21,                 // Access count (must match list below)
            NULL,               // Pointer to accesses
            L"Read",            // Default new access
        },


        //
        // Application accesses
        //

        {
            GENERIC_ACCESSES_5(SED_DESC_TYPE_RESOURCE),
            STANDARD_ACCESSES_5(SED_DESC_TYPE_RESOURCE_SPECIAL),

            { // 11
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_TERMINATE,
                0,
                L"Terminate"
            },
            { // 12
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_CREATE_THREAD,
                0,
                L"Create thread"
            },
            { // 13
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_VM_OPERATION,
                0,
                L"VM Operation"
            },
            { // 14
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_VM_READ,
                0,
                L"VM Read"
            },
            { // 15
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_VM_WRITE,
                0,
                L"VM Write"
            },
            { // 16
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_DUP_HANDLE,
                0,
                L"Duplicate handle"
            },
            { // 17
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_CREATE_PROCESS,
                0,
                L"Create process",
            },
            { // 18
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_SET_QUOTA,
                0,
                L"Set quota"
            },
            { // 19
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_SET_INFORMATION,
                0,
                L"Set information"
            },
            { // 20
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_QUERY_INFORMATION,
                0,
                L"Query information"
            },
            { // 21
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                PROCESS_SET_PORT,
                0,
                L"Set port"
            },

            DUMMY_ACCESS, // 22
            DUMMY_ACCESS, // 23
            DUMMY_ACCESS, // 24
            DUMMY_ACCESS, // 25
            DUMMY_ACCESS, // 26
            DUMMY_ACCESS, // 27
            DUMMY_ACCESS, // 28
            DUMMY_ACCESS, // 29
            DUMMY_ACCESS  // 30
        }
    },







    //
    // THREAD
    //

    {
        //
        // Type name
        //

        L"Thread",

        //
        // Help info
        //

        {
            HELP_FILENAME,
            {0, 0, 0, 0, 0, 0, 0}
        },



        //
        // Acleditor object type descriptor
        //

        {
            SED_REVISION1,          // Revision
            FALSE,                  // Is container
            FALSE,                  // AllowNewObjectPermissions
            FALSE,                  // MapSpecificPermsToGeneric
            NULL,                   // Pointer to generic mapping
            NULL,                   // Pointer to generic mapping for new objects
            L"Thread",              // Object type name
            NULL,                   // Pointer to help info
            NULL,                   // ApplyToSubContainerTitle
            NULL,                   // ApplyToObjectsTitle
            NULL,                   // ApplyToSubContainerConfirmation
            L"Special...",          // SpecialObjectAccessTitle
            NULL                    // SpecialNewObjectAccessTitle
        },



        //
        // Generic mapping
        //

        {
            THREAD_QUERY_INFORMATION | STANDARD_RIGHTS_READ,
            THREAD_SET_INFORMATION | STANDARD_RIGHTS_WRITE,
            STANDARD_RIGHTS_EXECUTE,
            THREAD_ALL_ACCESS
        },


        //
        // Application access structure
        //

        {
            20,                 // Access count (must match list below)
            NULL,               // Pointer to accesses
            L"Read",            // Default new access
        },


        //
        // Application accesses
        //

        {
            GENERIC_ACCESSES_5(SED_DESC_TYPE_RESOURCE),
            STANDARD_ACCESSES_5(SED_DESC_TYPE_RESOURCE_SPECIAL),

            { // 11
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_TERMINATE,
                0,
                L"Terminate"
            },
            { // 12
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_SUSPEND_RESUME,
                0,
                L"Suspend/Resume"
            },
            { // 13
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_ALERT,
                0,
                L"Alert"
            },
            { // 14
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_GET_CONTEXT,
                0,
                L"Get context"
            },
            { // 15
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_SET_CONTEXT,
                0,
                L"Set context"
            },
            { // 16
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_SET_INFORMATION,
                0,
                L"Set information"
            },
            { // 17
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_QUERY_INFORMATION,
                0,
                L"Query information"
            },
            { // 18
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_SET_THREAD_TOKEN,
                0,
                L"Set token"
            },
            { // 19
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_IMPERSONATE,
                0,
                L"Impersonate"
            },
            { // 20
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                THREAD_DIRECT_IMPERSONATION,
                0,
                L"Direct impersonation"
            },

            DUMMY_ACCESS, // 21
            DUMMY_ACCESS, // 22
            DUMMY_ACCESS, // 23
            DUMMY_ACCESS, // 24
            DUMMY_ACCESS, // 25
            DUMMY_ACCESS, // 26
            DUMMY_ACCESS, // 27
            DUMMY_ACCESS, // 28
            DUMMY_ACCESS, // 29
            DUMMY_ACCESS  // 30
        }
    },





    //
    // TOKEN
    //

    {
        //
        // Type name
        //

        L"Token",

        //
        // Help info
        //

        {
            HELP_FILENAME,
            {0, 0, 0, 0, 0, 0, 0}
        },



        //
        // Acleditor object type descriptor
        //

        {
            SED_REVISION1,          // Revision
            FALSE,                  // Is container
            FALSE,                  // AllowNewObjectPermissions
            FALSE,                  // MapSpecificPermsToGeneric
            NULL,                   // Pointer to generic mapping
            NULL,                   // Pointer to generic mapping for new objects
            L"Token",               // Object type name
            NULL,                   // Pointer to help info
            NULL,                   // ApplyToSubContainerTitle
            NULL,                   // ApplyToObjectsTitle
            NULL,                   // ApplyToSubContainerConfirmation
            L"Special...",          // SpecialObjectAccessTitle
            NULL                    // SpecialNewObjectAccessTitle
        },



        //
        // Generic mapping
        //

        {
            TOKEN_READ,
            TOKEN_WRITE,
            TOKEN_EXECUTE,
            TOKEN_ALL_ACCESS
        },


        //
        // Application access structure
        //

        {
            18,                 // Access count (must match list below)
            NULL,               // Pointer to accesses
            L"Read",            // Default new access
        },


        //
        // Application accesses
        //

        {
            GENERIC_ACCESSES_5(SED_DESC_TYPE_RESOURCE),
            STANDARD_ACCESSES_5(SED_DESC_TYPE_RESOURCE_SPECIAL),

            { // 11
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                TOKEN_ASSIGN_PRIMARY,
                0,
                L"Assign primary"
            },
            { // 12
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                TOKEN_DUPLICATE,
                0,
                L"Duplicate"
            },
            { // 13
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                TOKEN_IMPERSONATE,
                0,
                L"Impersonate"
            },
            { // 14
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                TOKEN_QUERY,
                0,
                L"Query"
            },
            { // 15
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                TOKEN_QUERY_SOURCE,
                0,
                L"Query source"
            },
            { // 16
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                TOKEN_ADJUST_PRIVILEGES,
                0,
                L"Adjust Privileges"
            },
            { // 17
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                TOKEN_ADJUST_GROUPS,
                0,
                L"Adjust Groups"
            },
            { // 18
                SED_DESC_TYPE_RESOURCE_SPECIAL,
                TOKEN_ADJUST_DEFAULT,
                0,
                L"Adjust Default"
            },

            DUMMY_ACCESS, // 19
            DUMMY_ACCESS, // 20
            DUMMY_ACCESS, // 21
            DUMMY_ACCESS, // 22
            DUMMY_ACCESS, // 23
            DUMMY_ACCESS, // 24
            DUMMY_ACCESS, // 25
            DUMMY_ACCESS, // 26
            DUMMY_ACCESS, // 27
            DUMMY_ACCESS, // 28
            DUMMY_ACCESS, // 29
            DUMMY_ACCESS  // 30
        }
    }

};


/***************************************************************************\
* InitializeACLEditor
*
* Purpose : Initializes this module.
*
* Returns TRUE on success, FALSE on failure
*
* History:
* 09-17-92 Davidc       Created.
\***************************************************************************/

BOOL
InitializeAclEditor(
    VOID
    )
{
    //
    // Load the acleditor module and get the proc addresses we need
    //

    hModAclEditor = LoadLibrary(TEXT("acledit.dll"));
    if (hModAclEditor == NULL) {
        return(FALSE);
    }

    lpfnDaclEditor = (LPFNDACLEDITOR)GetProcAddress(hModAclEditor,
                            TEXT("SedDiscretionaryAclEditor"));
    if (lpfnDaclEditor == NULL) {
        return(FALSE);
    }

    return(TRUE);
}


/***************************************************************************\
* FindObjectSecurityInfo
*
* Purpose : Searches for object type in our security info table and
*           returns pointer to security info if found.
*           Any pointers in the security info are initialized by this routine.
*
* Returns pointer to security info or NULL on failure
*
* History:
* 09-17-92 Davidc       Created.
\***************************************************************************/

POBJECT_TYPE_SECURITY_INFO
FindObjectSecurityInfo(
    HANDLE  Object
    )
{
    NTSTATUS Status;
    POBJECT_TYPE_SECURITY_INFO SecurityInfo;
    POBJECT_TYPE_INFORMATION TypeInfo;
    ULONG Length;
    BOOL Found;
    ULONG i;

    //
    // Get the object type
    //

    Status = NtQueryObject(
                            Object,
                            ObjectTypeInformation,
                            NULL,
                            0,
                            &Length
                            );
    if (Status != STATUS_INFO_LENGTH_MISMATCH) {
        DbgPrint("NtQueryObject failed, status = 0x%lx\n", Status);
        return(NULL);
    }

    TypeInfo = Alloc(Length);
    if (TypeInfo == NULL) {
        DbgPrint("Failed to allocate %ld bytes for object type\n", Length);
        return(NULL);
    }


    Status = NtQueryObject(
                            Object,
                            ObjectTypeInformation,
                            TypeInfo,
                            Length,
                            NULL
                            );
    if (!NT_SUCCESS(Status)) {
        DbgPrint("NtQueryObject failed, status = 0x%lx\n", Status);
        Free(TypeInfo);
        return(NULL);
    }


    //
    // Search for the type in our array of security info
    //

    Found = FALSE;
    for ( i=0;
          i < (sizeof(ObjectTypeSecurityInfo) / sizeof(*ObjectTypeSecurityInfo));
          i++
          ) {

        UNICODE_STRING FoundType;

        SecurityInfo = &ObjectTypeSecurityInfo[i];

        RtlInitUnicodeString(&FoundType, SecurityInfo->TypeName);

        if (RtlEqualUnicodeString(&TypeInfo->TypeName, &FoundType, TRUE)) {
            Found = TRUE;
            break;
        }
    }

    Free(TypeInfo);

    return(Found ? SecurityInfo : NULL);
}




/***************************************************************************\
* EditObjectDacl
*
* Purpose : Displays and allows the user to edit the Dacl on an object
*
* Returns TRUE on success, FALSE on failure (Use GetLastError for detail)
*
* History:
* 09-17-92 Davidc       Created.
\***************************************************************************/

BOOL
EditObjectDacl(
    HWND Owner,
    LPWSTR ObjectName,
    HANDLE Object,
    PSECURITY_DESCRIPTOR SecurityDescriptor,
    POBJECT_TYPE_SECURITY_INFO SecurityInfo,
    PSED_FUNC_APPLY_SEC_CALLBACK SetSecurityCallback,
    DWORD *EditResult
    )
{
    DWORD Result;
    HANDLE Instance;

    //
    // Initialize the pointer fields in the security info structure
    //

    SecurityInfo->AppAccesses.AccessGroup = SecurityInfo->AppAccess;
    SecurityInfo->SedObjectTypeDescriptor.GenericMapping =
                                    &SecurityInfo->GenericMapping;
    SecurityInfo->SedObjectTypeDescriptor.GenericMappingNewObjects =
                                    &SecurityInfo->GenericMapping;
    SecurityInfo->SedObjectTypeDescriptor.HelpInfo =
                                    &SecurityInfo->HelpInfo;

    //
    // Get the application instance handle
    //

    Instance = (HANDLE)(NtCurrentPeb()->ImageBaseAddress);
    ASSERT(Instance != 0);


    //
    // Call the ACL editor, it will call our ApplyNtObjectSecurity function
    // to store any ACL changes in the token.
    //

    Result = (*lpfnDaclEditor)(
                        Owner,
                        Instance,
                        NULL,               // server
                        &SecurityInfo->SedObjectTypeDescriptor, // object type
                        &SecurityInfo->AppAccesses, // application accesses
                        ObjectName,
                        SetSecurityCallback, // Callback
                        (ULONG_PTR)Object,    // Context
                        SecurityDescriptor,
                        (BOOLEAN)(SecurityDescriptor == NULL), // Couldn't read DACL
                        FALSE, // CantWriteDacl
                        EditResult,
                        0
                        );

    if (Result != ERROR_SUCCESS) {
        DbgPrint("DAcleditor failed, error = %d\n", Result);
        SetLastError(Result);
    }

    return (Result == ERROR_SUCCESS);

}








/***************************************************************************\
* ApplyNtObjectSecurity
*
* Purpose : Called by ACL editor to set new security on an object
*
* Returns ERROR_SUCCESS or win error code.
*
* History:
* 09-17-92 Davidc       Created.
\***************************************************************************/

DWORD
ApplyNtObjectSecurity(
    HWND    hwndParent,
    HANDLE  hInstance,
    ULONG_PTR   CallbackContext,
    PSECURITY_DESCRIPTOR SecDesc,
    PSECURITY_DESCRIPTOR SecDescNewObjects,
    BOOLEAN ApplyToSubContainers,
    BOOLEAN ApplyToSubObjects,
    LPDWORD StatusReturn
    )
{
    HANDLE Object = (HANDLE)CallbackContext;
    NTSTATUS Status;

    *StatusReturn = SED_STATUS_FAILED_TO_MODIFY;

    //
    // Set the new DACL on the object
    //

    Status = NtSetSecurityObject(Object,
                                 DACL_SECURITY_INFORMATION,
                                 SecDesc);
    if (NT_SUCCESS(Status)) {
        *StatusReturn = SED_STATUS_MODIFIED;
    } else {
        DbgPrint("Failed to set new ACL on object, status = 0x%lx\n", Status);
        if (Status == STATUS_ACCESS_DENIED) {
            MessageBox(hwndParent,
                       "You do not have permission to set the permissions on this object",
                       NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
        } else {
            MessageBox(hwndParent,
                       "Unable to set object security",
                       NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
        }
    }

    return(ERROR_SUCCESS);
}


/***************************************************************************\
* EditNtObjectDacl
*
* Purpose : Displays and allows the user to edit the Dacl on an NT object
*
* Returns TRUE on success, FALSE on failure (Use GetLastError for detail)
*
* History:
* 09-17-92 Davidc       Created.
\***************************************************************************/

BOOL
EditNtObjectDacl(
    HWND Owner,
    LPWSTR ObjectName,
    HANDLE Object,
    PSECURITY_DESCRIPTOR SecurityDescriptor,
    DWORD *EditResult
    )
{
    BOOL Result;
    POBJECT_TYPE_SECURITY_INFO SecurityInfo;


    //
    // Lookup our security info for an object of this type
    //

    SecurityInfo = FindObjectSecurityInfo(Object);
    if (SecurityInfo == NULL) {
        MessageBox(Owner, "Unable to edit the security on an object of this type",
                                NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
        return(FALSE);
    }


    //
    // Edit the ACL. Our callback function will be called to change the
    // new permissions
    //

    Result = EditObjectDacl(
                        Owner,
                        ObjectName,
                        Object,
                        SecurityDescriptor,
                        SecurityInfo,
                        ApplyNtObjectSecurity,
                        EditResult
                        );
    return (Result);

}


/***************************************************************************\
* EditNtObjectSecurity
*
* Purpose : Displays and allows the user to edit the protection on an NT object
*
* Parameters:
*
*   hwndOwner - Owner window for dialog
*   Object - handle to NT object. Should have been opened for MAXIMUM_ALLOWED
*   Name - Name of object
*
* Returns TRUE on success, FALSE on failure (Use GetLastError for detail)
*
* History:
* 09-17-92 Davidc       Created.
\***************************************************************************/

BOOL
EditNtObjectSecurity(
    HWND    hwndOwner,
    HANDLE  Object,
    LPWSTR  ObjectName
    )
{
    NTSTATUS Status;
    BOOL Success = FALSE;
    DWORD EditResult;
    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
    ULONG Length;

    //
    // If we don't have an address for the DACL editor, we can't do anything
    //

    if (lpfnDaclEditor == NULL) {
        DbgPrint("EditNtObjectSecurity - no ACL editor loaded\n");
        return(FALSE);
    }

    //
    // Read the existing security from the object
    //

    Status = NtQuerySecurityObject(Object,
                                   OWNER_SECURITY_INFORMATION |
                                   GROUP_SECURITY_INFORMATION |
                                   DACL_SECURITY_INFORMATION,
                                   NULL,
                                   0,
                                   &Length);
    ASSERT(!NT_SUCCESS(Status));

    if (Status != STATUS_BUFFER_TOO_SMALL) {
        DbgPrint("Failed to query object security, status = 0x%lx\n", Status);
    } else {

        SecurityDescriptor = Alloc(Length);
        if (SecurityDescriptor == NULL) {
            DbgPrint("Failed to allocate %ld bytes for object SD\n", Length);
            goto CleanupAndExit;
        }

        Status = NtQuerySecurityObject(Object,
                                       OWNER_SECURITY_INFORMATION |
                                       GROUP_SECURITY_INFORMATION |
                                       DACL_SECURITY_INFORMATION,
                                       SecurityDescriptor,
                                       Length,
                                       &Length);
        if (!NT_SUCCESS(Status)) {
            DbgPrint("Failed to query object security, status = 0x%lx\n", Status);
            goto CleanupAndExit;
        }

        ASSERT(RtlValidSecurityDescriptor(SecurityDescriptor));
    }

    //
    // Call the ACL editor, it will call our ApplyNtObjectSecurity function
    // to store any ACL changes in the object.
    //

    Success = EditNtObjectDacl(
                        hwndOwner,
                        ObjectName,
                        Object,
                        SecurityDescriptor,
                        &EditResult
                        );
    if (!Success) {
        DbgPrint("PVIEW: Failed to edit object DACL\n");
    }

CleanupAndExit:

    if (SecurityDescriptor != NULL) {
        Free(SecurityDescriptor);
    }

    return(Success);
}





/***************************************************************************\
* ApplyTokenDefaultDacl
*
* Purpose : Called by ACL editor to set new security on an object
*
* Returns ERROR_SUCCESS or win error code.
*
* History:
* 09-17-92 Davidc       Created.
\***************************************************************************/

DWORD
ApplyTokenDefaultDacl(
    HWND    hwndParent,
    HANDLE  hInstance,
    ULONG_PTR   CallbackContext,
    PSECURITY_DESCRIPTOR SecDesc,
    PSECURITY_DESCRIPTOR SecDescNewObjects,
    BOOLEAN ApplyToSubContainers,
    BOOLEAN ApplyToSubObjects,
    LPDWORD StatusReturn
    )
{
    HANDLE Token = (HANDLE)CallbackContext;
    TOKEN_DEFAULT_DACL DefaultDacl;
    NTSTATUS Status;
    BOOLEAN DaclPresent;
    BOOLEAN DaclDefaulted;

    Status = RtlGetDaclSecurityDescriptor (
                    SecDesc,
                    &DaclPresent,
                    &DefaultDacl.DefaultDacl,
                    &DaclDefaulted
                    );
    ASSERT(NT_SUCCESS(Status));

    ASSERT(DaclPresent);


    Status = NtSetInformationToken(
                 Token,                    // Handle
                 TokenDefaultDacl,         // TokenInformationClass
                 &DefaultDacl,             // TokenInformation
                 sizeof(DefaultDacl)       // TokenInformationLength
                 );
    if (NT_SUCCESS(Status)) {
        *StatusReturn = SED_STATUS_MODIFIED;
    } else {
        DbgPrint("SetInformationToken failed, status = 0x%lx\n", Status);
        *StatusReturn = SED_STATUS_FAILED_TO_MODIFY;

        if (Status == STATUS_ACCESS_DENIED) {
            MessageBox(hwndParent,
                       "You do not have permission to set the default ACL in this token",
                       NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
        } else {
            MessageBox(hwndParent,
                       "Unable to set default ACL in token",
                       NULL, MB_ICONSTOP | MB_APPLMODAL | MB_OK);
        }
    }

    return(ERROR_SUCCESS);
}


/***************************************************************************\
* EditTokenDefaultAcl
*
* Purpose : Displays and allows the user to edit the default ACL in a token
*
* Parameters:
*
*   hwndOwner - Owner window for dialog
*   Object - handle to token - opened for TOKEN_QUERY access
*   Name - Name of token
*
* Returns TRUE on success, FALSE on failure (Use GetLastError for detail)
*
* History:
* 09-17-92 Davidc       Created.
\***************************************************************************/

BOOL
EditTokenDefaultDacl(
    HWND    hwndOwner,
    HANDLE  Token,
    LPWSTR  ObjectName
    )
{
    NTSTATUS Status;
    BOOL Result = FALSE;
    DWORD EditResult;
    PTOKEN_DEFAULT_DACL DefaultDacl = NULL;
    PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
    ULONG   InfoLength;

    //
    // If we don't have an address for the DACL editor, we can't do anything
    //

    if (lpfnDaclEditor == NULL) {
        DbgPrint("EditNtObjectSecurity - no ACL editor loaded\n");
        return(FALSE);
    }

    //
    // Read the default DACL from the token
    //

    Status = NtQueryInformationToken(
                 Token,                    // Handle
                 TokenDefaultDacl,         // TokenInformationClass
                 NULL,                     // TokenInformation
                 0,                        // TokenInformationLength
                 &InfoLength               // ReturnLength
                 );

    ASSERT(!NT_SUCCESS(Status));

    if (Status == STATUS_BUFFER_TOO_SMALL) {

        DefaultDacl = Alloc(InfoLength);
        if (DefaultDacl == NULL) {
            goto CleanupAndExit;
        }

        Status = NtQueryInformationToken(
                     Token,                    // Handle
                     TokenDefaultDacl,         // TokenInformationClass
                     DefaultDacl,              // TokenInformation
                     InfoLength,               // TokenInformationLength
                     &InfoLength               // ReturnLength
                     );

        if (!NT_SUCCESS(Status)) {
            DbgPrint("NtQueryInformationToken failed, status = 0x%lx\n", Status);
            goto CleanupAndExit;
        }


        //
        // Create a security descriptor
        //

        SecurityDescriptor = Alloc(SECURITY_DESCRIPTOR_MIN_LENGTH);

        if (SecurityDescriptor == NULL) {
            DbgPrint("Failed to allocate security descriptor\n");
            goto CleanupAndExit;
        }

        Status = RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
        ASSERT(NT_SUCCESS(Status));


        //
        // Set the DACL on the security descriptor
        //

        Status = RtlSetDaclSecurityDescriptor(
                            SecurityDescriptor,
                            TRUE,   // DACL present
                            DefaultDacl->DefaultDacl,
                            FALSE   // DACL defaulted
                            );
        ASSERT(NT_SUCCESS(Status));

        ASSERT(RtlValidSecurityDescriptor(SecurityDescriptor));
    }



    //
    // Call the ACL editor, it will call our ApplyTokenDefaultAcl function
    // to store any default ACL changes in the token.
    //

    Result = EditObjectDacl(
                        hwndOwner,
                        ObjectName,
                        Token,
                        SecurityDescriptor,
                        &DefaultSecurityInfo,
                        ApplyTokenDefaultDacl,
                        &EditResult
                        );
    if (!Result) {
        DbgPrint("Failed to edit token default ACL\n");
    }

CleanupAndExit:

    if (SecurityDescriptor != NULL) {
        Free(SecurityDescriptor);
    }
    if (DefaultDacl != NULL) {
        Free(DefaultDacl);
    }

    return(Result);
}