windows-nt/Source/XPSP1/NT/ds/netapi/netlib/secobj2.c
2020-09-26 16:20:57 +08:00

329 lines
8.2 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}