|
|
/*++
Copyright (c) 1991-1992 Microsoft Corporation
Module Name:
secobj.c
Abstract:
This module provides support routines to simplify the creation of security descriptors for user-mode objects.
Author:
Cliff Van Dyke (CliffV) 09-Feb-1994
Environment:
Contains NT specific code.
Revision History:
Cliff Van Dyke (CliffV) 09-Feb-1994 Split off from secobj.c so NtLmSsp can reference secobj.c without loading the rpc libaries.
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h> // DWORD.
#include <lmcons.h> // NET_API_STATUS.
#include <netlib.h>
#include <lmerr.h>
#include <netdebug.h>
#include <debuglib.h>
#include <rpc.h>
#include <rpcutil.h>
#include <secobj.h>
NET_API_STATUS NetpAccessCheckAndAudit( IN LPTSTR SubsystemName, IN LPTSTR ObjectTypeName, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN ACCESS_MASK DesiredAccess, IN PGENERIC_MAPPING GenericMapping ) /*++
Routine Description:
This function impersonates the caller so that it can perform access validation using NtAccessCheckAndAuditAlarm; and reverts back to itself before returning.
Arguments:
SubsystemName - Supplies a name string identifying the subsystem calling this routine.
ObjectTypeName - Supplies the name of the type of the object being accessed.
SecurityDescriptor - A pointer to the Security Descriptor against which acccess is to be checked.
DesiredAccess - Supplies 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.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/ {
NTSTATUS NtStatus; RPC_STATUS RpcStatus; BOOLEAN fWasEnabled;
UNICODE_STRING Subsystem; UNICODE_STRING ObjectType; UNICODE_STRING ObjectName;
#ifndef UNICODE
OEM_STRING AnsiString; #endif
ACCESS_MASK GrantedAccess; BOOLEAN GenerateOnClose; NTSTATUS AccessStatus;
#ifdef UNICODE
RtlInitUnicodeString(&Subsystem, SubsystemName); RtlInitUnicodeString(&ObjectType, ObjectTypeName); #else
NetpInitOemString( &AnsiString, SubsystemName ); NtStatus = RtlOemStringToUnicodeString( &Subsystem, &AnsiString, TRUE );
if ( !NT_SUCCESS( NtStatus )) { NetpKdPrint(("[Netlib] Error calling RtlOemStringToUnicodeString %08lx\n", NtStatus)); return NetpNtStatusToApiStatus( NtStatus ); }
NetpInitOemString( &AnsiString, ObjectTypeName );
NtStatus = RtlOemStringToUnicodeString(&ObjectType, &AnsiString, TRUE);
if ( !NT_SUCCESS( NtStatus )) { NetpKdPrint(("[Netlib] Error calling RtlOemStringToUnicodeString %08lx\n", NtStatus)); RtlFreeUnicodeString( &Subsystem ); return NetpNtStatusToApiStatus( NtStatus ); } #endif
//
// Make sure SE_AUDIT_PRIVILEGE is enabled for this process (rather
// than the thread) since the audit privilege is checked in the process
// token (and not the thread token). Leave it enabled since there's
// no harm in doing so once it's been enabled (since the process needs
// to have the privilege in the first place).
//
RtlAdjustPrivilege(SE_AUDIT_PRIVILEGE, TRUE, FALSE, &fWasEnabled);
RtlInitUnicodeString(&ObjectName, NULL); // No object name
if ((RpcStatus = RpcImpersonateClient(NULL)) != RPC_S_OK) { NetpKdPrint(("[Netlib] Failed to impersonate client %08lx\n", RpcStatus)); return NetpRpcStatusToApiStatus(RpcStatus); }
NtStatus = NtAccessCheckAndAuditAlarm( &Subsystem, NULL, // No handle for object
&ObjectType, &ObjectName, SecurityDescriptor, DesiredAccess, GenericMapping, FALSE, &GrantedAccess, &AccessStatus, &GenerateOnClose );
#ifndef UNICODE
RtlFreeUnicodeString( &Subsystem ); RtlFreeUnicodeString( &ObjectType ); #endif
if ((RpcStatus = RpcRevertToSelf()) != RPC_S_OK) { NetpKdPrint(("[Netlib] Fail to revert to self %08lx\n", RpcStatus)); NetpAssert(FALSE); }
if (! NT_SUCCESS(NtStatus)) { NetpKdPrint(("[Netlib] Error calling NtAccessCheckAndAuditAlarm %08lx\n", NtStatus)); return ERROR_ACCESS_DENIED; }
if (AccessStatus != STATUS_SUCCESS) { IF_DEBUG(SECURITY) { NetpKdPrint(("[Netlib] Access status is %08lx\n", AccessStatus)); } return ERROR_ACCESS_DENIED; }
return NERR_Success; }
NET_API_STATUS NetpAccessCheck( IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN ACCESS_MASK DesiredAccess, IN PGENERIC_MAPPING GenericMapping ) /*++
Routine Description:
This function impersonates the caller so that it can perform access validation using NtAccessCheck; and reverts back to itself before returning.
This routine differs from NetpAccessCheckAndAudit in that it doesn't require the caller to have SE_AUDIT_PRIVILEGE nor does it generate audits. That is typically fine since the passed in security descriptor typically doesn't have a SACL requesting an audit.
Arguments:
SecurityDescriptor - A pointer to the Security Descriptor against which acccess is to be checked.
DesiredAccess - Supplies 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.
Return Value:
NET_API_STATUS - NERR_Success or reason for failure.
--*/ { NET_API_STATUS NetStatus; NET_API_STATUS TempStatus;
HANDLE ClientToken = NULL;
DWORD GrantedAccess; BOOL AccessStatus; BYTE PrivilegeSet[500]; // Large buffer
DWORD PrivilegeSetSize;
//
// Impersonate the client.
//
NetStatus = RpcImpersonateClient(NULL);
if ( NetStatus != RPC_S_OK ) { NetpKdPrint(("[Netlib] Failed to impersonate client %08lx\n", NetStatus)); return NetpRpcStatusToApiStatus(NetStatus); }
//
// Open the impersonated token.
//
if ( !OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, // Use NtLmSvc security context to open token
&ClientToken )) {
NetStatus = GetLastError(); NetpKdPrint(("[Netlib] Error calling GetCurrentThread %ld\n", NetStatus));
goto Cleanup; }
//
// Check if the client has the required access.
//
PrivilegeSetSize = sizeof(PrivilegeSet);
if ( !AccessCheck( SecurityDescriptor, ClientToken, DesiredAccess, GenericMapping, (PPRIVILEGE_SET) PrivilegeSet, &PrivilegeSetSize, &GrantedAccess, &AccessStatus ) ) {
NetStatus = GetLastError(); NetpKdPrint(("[Netlib] Error calling AccessCheck %ld\n", NetStatus));
goto Cleanup;
}
if ( !AccessStatus ) { NetStatus = GetLastError(); IF_DEBUG(SECURITY) { NetpKdPrint(("[Netlib] Access status is %ld\n", NetStatus )); } goto Cleanup; }
//
// Success
//
NetStatus = NERR_Success;
//
// Free locally used resources
//
Cleanup: TempStatus = RpcRevertToSelf(); if ( TempStatus != RPC_S_OK ) { NetpKdPrint(("[Netlib] Fail to revert to self %08lx\n", TempStatus)); NetpAssert(FALSE); }
if ( ClientToken != NULL ) { CloseHandle( ClientToken ); }
return NetStatus; }
|