/*++

Copyright (c) 1992  Microsoft Corporation

Module Name:

    Regsckey.c

Abstract:

    This module contains the server side implementation for the Win32
    Registry APIs to set and get the SECURITY_DESCRIPTOR for a key.  That
    is:

        - BaseRegGetKeySecurity
        - BaseRegSetKeySecurity

Author:

    David J. Gilman (davegi) 10-Feb-1992

Notes:

    See the Notes in Regkey.c.

--*/

#include <rpc.h>
#include "regrpc.h"
#include "localreg.h"
#ifdef LOCAL
#include "tsappcmp.h"
#endif


error_status_t
BaseRegGetKeySecurity(
    HKEY hKey,
    SECURITY_INFORMATION RequestedInformation,
    PRPC_SECURITY_DESCRIPTOR pRpcSecurityDescriptor
    )

/*++

Routine Description:

    This API returns a copy of the security descriptor protecting a
    previously opened key.  Based on the caller's access rights and
    privileges, this API returns a security descriptor containing the
    requested security descriptor fields.  To read the supplied key'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:

    hKey - Supplies a handle to a previously opened key.

    SecurityInformation - Supplies the information needed to determine
        the type of security returned in the SECURITY_DESCRIPTOR.

    pSecurityDescriptor - Supplies a pointer to a buffer where the
        requested SECURITY_DESCRIPTOR will be written.

    lpcbSecurityDescriptor - Supplies a pointer to a DWORD which on input
        contains the size, in bytes, of the supplied SECURITY_DESCRIPTOR
        buffer. On output it contains the actual number of bytes required
        by the SECURITY_DESCRIPTOR.

Return Value:

    Returns ERROR_SUCCESS (0) for success; error-code for failure.

Notes:

    If the buffer size passed in is too small, the correct value will be
    returned through lpcbSecurityDescriptor and the API will return,
    ERROR_INVALID_PARAMETER.

--*/

{
    NTSTATUS                Status;
    PSECURITY_DESCRIPTOR    lpSD;
    DWORD                   cbLen;
    DWORD                   Error = ERROR_SUCCESS;
    HKEY                    hPerflibKey = 0;
    OBJECT_ATTRIBUTES       Obja;

    if (hKey == HKEY_PERFORMANCE_DATA ||
        hKey == HKEY_PERFORMANCE_TEXT ||
        hKey == HKEY_PERFORMANCE_NLSTEXT ) {
        //
        // For these special cases, get the hKey for Perflib
        // and return the Perflib's Security Info
        //
        UNICODE_STRING  PerflibSubKeyString;
        BOOL            bNeedSACL;

        bNeedSACL = RequestedInformation & SACL_SECURITY_INFORMATION;

        RtlInitUnicodeString (
            &PerflibSubKeyString,
            L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");


        //
        // Initialize the OBJECT_ATTRIBUTES structure and open the key.
        //
        InitializeObjectAttributes(
            &Obja,
            &PerflibSubKeyString,
            OBJ_CASE_INSENSITIVE,
            NULL,
            NULL
            );


        Status = NtOpenKey(
                &hPerflibKey,
                bNeedSACL ?
                    MAXIMUM_ALLOWED | ACCESS_SYSTEM_SECURITY :
                    MAXIMUM_ALLOWED,
                &Obja
                );

        if ( ! NT_SUCCESS( Status )) {

            Error = RtlNtStatusToDosError( Status );
            pRpcSecurityDescriptor->cbInSecurityDescriptor  = 0;
            pRpcSecurityDescriptor->cbOutSecurityDescriptor = 0;
            return (error_status_t)Error;
        }

        hKey = hPerflibKey;

    } else {
        ASSERT( IsPredefinedRegistryHandle( hKey ) == FALSE );
    }

    //
    //  Allocate space for the security descriptor
    //
    lpSD = (PSECURITY_DESCRIPTOR)
                RtlAllocateHeap(
                        RtlProcessHeap(), 0,
                        pRpcSecurityDescriptor->cbInSecurityDescriptor
                        );

    if ( !lpSD ) {

        Error = ERROR_OUTOFMEMORY;

    } else {

        Status = NtQuerySecurityObject(
                     hKey,
                     RequestedInformation,
                     lpSD,
                     pRpcSecurityDescriptor->cbInSecurityDescriptor,
                     &cbLen
                     );

        //
        // If the call fails, set the size of the buffer to zero so RPC
        // won't copy any data.
        //
        if( ! NT_SUCCESS( Status )) {

            Error = RtlNtStatusToDosError( Status );

        } else {

            //
            //  Convert the security descriptor to a Self-relative form
            //
            Error = MapSDToRpcSD (
                        lpSD,
                        pRpcSecurityDescriptor
                        );
        }

        if ( Error != ERROR_SUCCESS ) {
            pRpcSecurityDescriptor->cbInSecurityDescriptor  = cbLen;
            pRpcSecurityDescriptor->cbOutSecurityDescriptor = 0;
        }

        //
        //  Free the buffer that we allocated for the security descriptor
        //
        RtlFreeHeap(
                RtlProcessHeap(), 0,
                lpSD
                );
    }

    if (hPerflibKey) {
        // Close the Perflib that was created in the special cases
        NtClose(hPerflibKey);
    }

    return (error_status_t)Error;
}

error_status_t
BaseRegSetKeySecurity(
    HKEY hKey,
    SECURITY_INFORMATION SecurityInformation,
    PRPC_SECURITY_DESCRIPTOR pRpcSecurityDescriptor
    )

/*++

Routine Description:

    This API can be used to set the security of a previously opened key.
    This call is only successful if the following conditions are met:

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

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

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

Arguments:

    hKey - Supplies a handle to a previously opened key.

    SecurityInformation - Supplies a pointer to a SECURITY_INFORMATION
        structure that specifies the contents of the supplied
        SECURITY_DESCRIPTOR.

    pSecurityDescriptor - Supplies a pointer to the SECURITY_DESCRIPTOR
        to set on the supplied key.

Return Value:

    Returns ERROR_SUCCESS (0) for success; error-code for failure.

--*/

{
    NTSTATUS    Status;

    if (hKey == HKEY_PERFORMANCE_DATA ||
        hKey == HKEY_PERFORMANCE_TEXT ||
        hKey == HKEY_PERFORMANCE_NLSTEXT ) {
        //
        // these keys get their security descriptor from
        // other "real" registry keys.
        //
        Status = STATUS_INVALID_HANDLE;
    } else {
        ASSERT( IsPredefinedRegistryHandle( hKey ) == FALSE );

        RPC_IMPERSONATE_CLIENT( NULL );

        //
        // Validate the security descriptor.
        //
        if( RtlValidRelativeSecurityDescriptor((PSECURITY_DESCRIPTOR)(pRpcSecurityDescriptor->lpSecurityDescriptor),
                                                pRpcSecurityDescriptor->cbInSecurityDescriptor,
                                                SecurityInformation )) {
            Status = NtSetSecurityObject(
                        hKey,
                        SecurityInformation,
                        pRpcSecurityDescriptor->lpSecurityDescriptor
                        );
        } else {
            //
            //  We were passed a bogus security descriptor to set.  Bail out
            //

            Status = STATUS_INVALID_PARAMETER;
        }

        RPC_REVERT_TO_SELF();
    }

#ifdef LOCAL
    if (NT_SUCCESS(Status) && gpfnTermsrvSetKeySecurity) {
        gpfnTermsrvSetKeySecurity(hKey,
                                  SecurityInformation,
                                  pRpcSecurityDescriptor->lpSecurityDescriptor);
    }
#endif

    return (error_status_t)RtlNtStatusToDosError( Status );
}
