329 lines
8.2 KiB
C
329 lines
8.2 KiB
C
/*++
|
||
|
||
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;
|
||
}
|