/*++ 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 #include #include #include // DWORD. #include // NET_API_STATUS. #include #include #include #include #include #include #include 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; }