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;
|
|||
|
}
|