/*++ Copyright (c) 1991 Microsoft Corporation Module Name: dbpriv.c Abstract: LSA - Database - Privilege Object Private API Workers NOTE: This module should remain as portable code that is independent of the implementation of the LSA Database. As such, it is permitted to use only the exported LSA Database interfaces contained in db.h and NOT the private implementation dependent functions in dbp.h. Author: Jim Kelly (JimK) March 24, 1992 Environment: Revision History: --*/ #include "lsasrvp.h" #include "dbp.h" #include "adtp.h" #include #include /////////////////////////////////////////////////////////////////////////// // // // // // Module-wide data types // // // // // /////////////////////////////////////////////////////////////////////////// typedef struct _LSAP_DLL_DESCRIPTOR { WORD Count; WORD Language; PVOID DllHandle; } LSAP_DLL_DESCRIPTOR, *PLSAP_DLL_DESCRIPTOR; /////////////////////////////////////////////////////////////////////////// // // // // // Module-wide variables // // // // // /////////////////////////////////////////////////////////////////////////// // // Neutral English language value // WORD LsapNeutralEnglish; // // Until we actually have a privilege object, keep well known privilege // information as global data. The information for each privilege is // kept in a an array POLICY_PRIVILEGE_DEFINITION structures. // ULONG LsapWellKnownPrivilegeCount; POLICY_PRIVILEGE_DEFINITION LsapKnownPrivilege[SE_MAX_WELL_KNOWN_PRIVILEGE]; // // Array of handles to DLLs containing privilege definitions // ULONG LsapPrivilegeDllCount; PLSAP_DLL_DESCRIPTOR LsapPrivilegeDlls; //Array // // TEMPORARY: Name of Microsoft's standard privilege names DLL // WCHAR MsDllNameString[] = L"msprivs"; UNICODE_STRING MsDllName; /////////////////////////////////////////////////////////////////////////// // // // // // Module Wide Macros // // // // // /////////////////////////////////////////////////////////////////////////// // //NTSTATUS //LsapFreePrivilegeDllNames( // IN PUNICODE_STRING DllNames // ) // #define LsapFreePrivilegeDllNames( D ) (STATUS_SUCCESS) /////////////////////////////////////////////////////////////////////////// // // // // // Internal routine templates // // // // // /////////////////////////////////////////////////////////////////////////// NTSTATUS LsapLookupKnownPrivilegeName( PLUID Value, PUNICODE_STRING *Name ); NTSTATUS LsapLookupKnownPrivilegeValue( PUNICODE_STRING Name, PLUID Value ); NTSTATUS LsapLookupPrivilegeDisplayName( IN PUNICODE_STRING ProgrammaticName, IN WORD ClientLanguage, IN WORD ClientSystemDefaultLanguage, OUT PUNICODE_STRING *DisplayName, OUT PWORD LanguageReturned ); NTSTATUS LsapGetPrivilegeDisplayName( IN ULONG DllIndex, IN ULONG PrivilegeIndex, IN WORD ClientLanguage, IN WORD ClientSystemDefaultLanguage, OUT PUNICODE_STRING *DisplayName, OUT PWORD LanguageReturned ); NTSTATUS LsapGetPrivilegeIndex( IN PUNICODE_STRING Name, IN ULONG DllIndex, OUT PULONG PrivilegeIndex ); VOID LsapGetDisplayTable( IN ULONG DllIndex, IN WORD ClientLanguage, IN WORD ClientSystemDefaultLanguage, OUT PWORD LanguageReturned, OUT PWORD *DisplayTable ); NTSTATUS LsapCopyDisplayPrivilegeText( IN PWORD DisplayTable, IN ULONG PrivilegeIndex, OUT PUNICODE_STRING *DisplayName ); NTSTATUS LsapOpenPrivilegeDlls( VOID ); NTSTATUS LsapGetPrivilegeDllNames( OUT PUNICODE_STRING *DllNames, OUT PULONG DllCount ); NTSTATUS LsapValidatePrivilegeDlls( VOID ); NTSTATUS LsapValidateProgrammaticNames( ULONG DllIndex ); NTSTATUS LsapDbInitWellKnownPrivilegeName( IN ULONG Index, IN PUNICODE_STRING Name ); /////////////////////////////////////////////////////////////////////////// // // // // // RPC stub-called routines // // // // // /////////////////////////////////////////////////////////////////////////// NTSTATUS LsarEnumeratePrivileges( IN LSAPR_HANDLE PolicyHandle, IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext, OUT PLSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer, IN ULONG PreferedMaximumLength ) /*++ Routine Description: This function returnes information about privileges known on this system. This call requires POLICY_VIEW_LOCAL_INFORMATION access to the Policy Object. Since there may be more information than can be returned in a single call of the routine, multiple calls can be made to get all of the information. To support this feature, the caller is provided with a handle that can be used across calls to the API. On the initial call, EnumerationContext should point to a variable that has been initialized to 0. WARNING! CURRENTLY, THIS FUNCTION ONLY RETURNS INFORMATION ABOUT WELL-KNOWN PRIVILEGES. LATER, IT WILL RETURN INFORMATION ABOUT LOADED PRIVILEGES. Arguments: PolicyHandle - Handle from an LsarOpenPolicy() call. EnumerationContext - API specific handle to allow multiple calls (see Routine Description). EnumerationBuffer - Pointer to structure that will be initialized to contain a count of the privileges returned and a pointer to an array of structures of type LSAPR_POLICY_PRIVILEGE_DEF describing the privileges. PreferedMaximumLength - Prefered maximim length of returned data (in 8-bit bytes). This is not a hard upper limit, but serves as a guide. Due to data conversion between systems with different natural data sizes, the actual amount of data returned may be greater than this value. CountReturned - Number of entries returned. Return Values: NTSTATUS - Standard Nt Result Code. STATUS_SUCCESS - The call completed successfully. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources, such as memory, to complete the call. STATUS_INVALID_HANDLE - PolicyHandle is not a valid handle to a Policy object. STATUS_ACCESS_DENIED - The caller does not have the necessary access to perform the operation. STATUS_MORE_ENTRIES - There are more entries, so call again. This is an informational status only. STATUS_NO_MORE_ENTRIES - No entries were returned because there are no more. --*/ { NTSTATUS Status, PreliminaryStatus; BOOLEAN ObjectReferenced = FALSE; // // Acquire the Lsa Database lock. Verify that PolicyHandle is a valid // hadnle to a Policy Object and is trusted or has the necessary accesses. // Reference the handle. // Status = LsapDbReferenceObject( PolicyHandle, POLICY_VIEW_LOCAL_INFORMATION, PolicyObject, LSAP_DB_ACQUIRE_LOCK ); if (!NT_SUCCESS(Status)) { goto EnumeratePrivilegesError; } ObjectReferenced = TRUE; // // Call Privilege Enumeration Routine. // Status = LsapDbEnumeratePrivileges( EnumerationContext, EnumerationBuffer, PreferedMaximumLength ); if (!NT_SUCCESS(Status)) { goto EnumeratePrivilegesError; } EnumeratePrivilegesFinish: // // If necessary, dereference the Policy Object, release the LSA Database // lock and return. Preserve current Status where appropriate. // if (ObjectReferenced) { PreliminaryStatus = Status; Status = LsapDbDereferenceObject( &PolicyHandle, PolicyObject, LSAP_DB_RELEASE_LOCK, (SECURITY_DB_DELTA_TYPE) 0, PreliminaryStatus ); ObjectReferenced = FALSE; if ((!NT_SUCCESS(Status)) && NT_SUCCESS(PreliminaryStatus)) { goto EnumeratePrivilegesError; } } return(Status); EnumeratePrivilegesError: goto EnumeratePrivilegesFinish; } NTSTATUS LsapDbEnumeratePrivileges( IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext, OUT PLSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer, IN ULONG PreferedMaximumLength ) /*++ Routine Description: This function returnes information about the Privileges that exist in the system.access to the Policy Object. Since there may be more information than can be returned in a single call of the routine, multiple calls can be made to get all of the information. To support this feature, the caller is provided with a handle that can be used across calls to the API. On the initial call, EnumerationContext should point to a variable that has been initialized to 0. WARNING! CURRENTLY, THIS FUNCTION ONLY RETURNS INFORMATION ABOUT WELL-KNOWN PRIVILEGES. LATER, IT WILL RETURN INFORMATION ABOUT LOADED PRIVILEGES. Arguments: EnumerationContext - API specific handle to allow multiple calls (see Routine Description). EnumerationBuffer - Pointer to structure that will be initialized to contain a count of the privileges returned and a pointer to an array of structures of type LSAPR_POLICY_PRIVILEGE_DEF describing the privileges. PreferedMaximumLength - Prefered maximim length of returned data (in 8-bit bytes). This is not a hard upper limit, but serves as a guide. Due to data conversion between systems with different natural data sizes, the actual amount of data returned may be greater than this value. CountReturned - Number of entries returned. Return Values: NTSTATUS - Standard Nt Result Code. STATUS_SUCCESS - The call completed successfully. STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources, such as memory, to complete the call. STATUS_INVALID_HANDLE - PolicyHandle is not a valid handle to a Policy object. STATUS_ACCESS_DENIED - The caller does not have the necessary access to perform the operation. STATUS_MORE_ENTRIES - There are more entries, so call again. This is an informational status only. STATUS_NO_MORE_ENTRIES - No entries were returned because there are no more. --*/ { NTSTATUS Status; ULONG WellKnownPrivilegeCount = (SE_MAX_WELL_KNOWN_PRIVILEGE - SE_MIN_WELL_KNOWN_PRIVILEGE + 1); ULONG Index; Status = STATUS_INVALID_PARAMETER; // // If the Enumeration Context Value given exceeds the total count of // Privileges, return an error. // Status = STATUS_NO_MORE_ENTRIES; if (*EnumerationContext >= WellKnownPrivilegeCount) { goto EnumeratePrivilegesError; } // // Since there are only a small number of privileges, we will // return all of the information in one go, so allocate memory // for output array of Privilege Definition structures. // EnumerationBuffer->Entries = WellKnownPrivilegeCount; EnumerationBuffer->Privileges = MIDL_user_allocate( WellKnownPrivilegeCount * sizeof (POLICY_PRIVILEGE_DEFINITION) ); Status = STATUS_INSUFFICIENT_RESOURCES; if (EnumerationBuffer->Privileges == NULL) { goto EnumeratePrivilegesError; } RtlZeroMemory( EnumerationBuffer->Privileges, WellKnownPrivilegeCount * sizeof (POLICY_PRIVILEGE_DEFINITION) ); // // Now lookup each of the Well Known Privileges. // for( Index = *EnumerationContext; Index < (SE_MAX_WELL_KNOWN_PRIVILEGE - SE_MIN_WELL_KNOWN_PRIVILEGE + 1); Index++) { EnumerationBuffer->Privileges[ Index ].LocalValue = LsapKnownPrivilege[ Index ].LocalValue; Status = LsapRpcCopyUnicodeString( NULL, (PUNICODE_STRING) &EnumerationBuffer->Privileges[ Index].Name, &LsapKnownPrivilege[ Index ].Name ); if (!NT_SUCCESS(Status)) { break; } } if (!NT_SUCCESS(Status)) { goto EnumeratePrivilegesError; } *EnumerationContext = Index; EnumeratePrivilegesFinish: return(Status); EnumeratePrivilegesError: // // If necessary, free any memory buffers allocated for Well Known Privilege // Programmatic Names. // if (EnumerationBuffer->Privileges != NULL) { for( Index = 0; Index < SE_MAX_WELL_KNOWN_PRIVILEGE - SE_MIN_WELL_KNOWN_PRIVILEGE; Index++) { if ( EnumerationBuffer->Privileges[ Index].Name.Buffer != NULL) { MIDL_user_free( EnumerationBuffer->Privileges[ Index ].Name.Buffer ); } } MIDL_user_free( EnumerationBuffer->Privileges ); EnumerationBuffer->Privileges = NULL; } EnumerationBuffer->Entries = 0; *EnumerationContext = 0; goto EnumeratePrivilegesFinish; UNREFERENCED_PARAMETER( PreferedMaximumLength ); } NTSTATUS LsarLookupPrivilegeValue( IN LSAPR_HANDLE PolicyHandle, IN PLSAPR_UNICODE_STRING Name, OUT PLUID Value ) /*++ Routine Description: This function is the LSA server RPC worker routine for the LsaLookupPrivilegeValue() API. Arguments: PolicyHandle - Handle from an LsaOpenPolicy() call. This handle must be open for POLICY_LOOKUP_NAMES access. Name - Is the privilege's programmatic name. Value - Receives the locally unique ID the privilege is known by on the target machine. Return Value: NTSTATUS - The privilege was found and returned. STATUS_ACCESS_DENIED - Caller does not have the appropriate access to complete the operation. STATUS_NO_SUCH_PRIVILEGE - The specified privilege could not be found. --*/ { NTSTATUS Status; LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) PolicyHandle; // // Make sure we know what RPC is doing to/for us // ASSERT( Name != NULL ); // // make sure the caller has the appropriate access // Status = LsapDbReferenceObject( PolicyHandle, POLICY_LOOKUP_NAMES, PolicyObject, LSAP_DB_ACQUIRE_LOCK ); if (!NT_SUCCESS(Status)) { return(Status); } // // No need to hold onto the Policy object after this.. // We just needed it for access validation purposes. // Status = LsapDbDereferenceObject( &PolicyHandle, PolicyObject, LSAP_DB_RELEASE_LOCK, (SECURITY_DB_DELTA_TYPE) 0, Status ); if (NT_SUCCESS(Status)) { if (Name->Buffer == 0 || Name->Length == 0) { return(STATUS_NO_SUCH_PRIVILEGE); } Status = LsapLookupKnownPrivilegeValue( (PUNICODE_STRING) Name, Value ); } return(Status); } NTSTATUS LsarLookupPrivilegeName( IN LSAPR_HANDLE PolicyHandle, IN PLUID Value, OUT PLSAPR_UNICODE_STRING *Name ) /*++ Routine Description: This function is the LSA server RPC worker routine for the LsaLookupPrivilegeName() API. Arguments: PolicyHandle - Handle from an LsaOpenPolicy() call. This handle must be open for POLICY_LOOKUP_NAMES access. Value - is the locally unique ID the privilege is known by on the target machine. Name - Receives the privilege's programmatic name. Return Value: NTSTATUS - Standard Nt Result Code STATUS_SUCCESS - The privilege was found and returned. STATUS_ACCESS_DENIED - Caller does not have the appropriate access to complete the operation. STATUS_NO_SUCH_PRIVILEGE - The specified privilege could not be found. --*/ { NTSTATUS Status; LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) PolicyHandle; // // make sure we know what RPC is doing to/for us // ASSERT( Name != NULL ); ASSERT( (*Name) == NULL ); // // make sure the caller has the appropriate access // Status = LsapDbReferenceObject( PolicyHandle, POLICY_LOOKUP_NAMES, PolicyObject, LSAP_DB_ACQUIRE_LOCK ); if (!NT_SUCCESS(Status)) { return(Status); } // // No need to hold onto the Policy object after this.. // We just needed it for access validation purposes. // Status = LsapDbDereferenceObject( &PolicyHandle, PolicyObject, LSAP_DB_RELEASE_LOCK, (SECURITY_DB_DELTA_TYPE) 0, Status ); if (NT_SUCCESS(Status)) { Status = LsapLookupKnownPrivilegeName( Value,(PUNICODE_STRING *) Name ); } return(Status); } NTSTATUS LsarLookupPrivilegeDisplayName( IN LSAPR_HANDLE PolicyHandle, IN PLSAPR_UNICODE_STRING Name, IN SHORT ClientLanguage, IN SHORT ClientSystemDefaultLanguage, OUT PLSAPR_UNICODE_STRING *DisplayName, OUT PWORD LanguageReturned ) /*++ Routine Description: This function is the LSA server RPC worker routine for the LsaLookupPrivilegeDisplayName() API. Arguments: PolicyHandle - Handle from an LsaOpenPolicy() call. This handle must be open for POLICY_LOOKUP_NAMES access. Name - The programmatic privilege name to look up. ClientLanguage - The prefered language to be returned. ClientSystemDefaultLanguage - The alternate prefered language to be returned. DisplayName - Receives the privilege's displayable name. LanguageReturned - The language actually returned. Return Value: NTSTATUS - The privilege text was found and returned. STATUS_ACCESS_DENIED - Caller does not have the appropriate access to complete the operation. STATUS_NO_SUCH_PRIVILEGE - The specified privilege could not be found. --*/ { NTSTATUS Status; LSAP_DB_HANDLE Handle = (LSAP_DB_HANDLE) PolicyHandle; // // make sure we know what RPC is doing to/for us // ASSERT( DisplayName != NULL ); ASSERT( (*DisplayName) == NULL ); ASSERT( LanguageReturned != NULL ); // // make sure the caller has the appropriate access // Status = LsapDbReferenceObject( PolicyHandle, POLICY_LOOKUP_NAMES, PolicyObject, LSAP_DB_ACQUIRE_LOCK ); if (!NT_SUCCESS(Status)) { return(Status); } // // No need to hold onto the Policy object after this.. // We just needed it for access validation purposes. // Status = LsapDbDereferenceObject( &PolicyHandle, PolicyObject, LSAP_DB_RELEASE_LOCK, (SECURITY_DB_DELTA_TYPE) 0, Status ); if (NT_SUCCESS(Status)) { if (Name->Buffer == 0 || Name->Length == 0) { return(STATUS_NO_SUCH_PRIVILEGE); } Status = LsapLookupPrivilegeDisplayName( (PUNICODE_STRING)Name, (WORD)ClientLanguage, (WORD)ClientSystemDefaultLanguage, (PUNICODE_STRING *)DisplayName, LanguageReturned ); } return(Status); } /////////////////////////////////////////////////////////////////////////// // // // // // Internal Routines // // // // // /////////////////////////////////////////////////////////////////////////// NTSTATUS LsapLookupKnownPrivilegeName( IN PLUID Value, OUT PUNICODE_STRING *Name ) /*++ Routine Description: Look up the specified LUID and return the corresponding privilege's programmatic name (if found). FOR NOW, WE ONLY SUPPORT WELL-KNOWN MICROSOFT PRIVILEGES. THESE ARE HARD-CODED HERE. IN THE FUTURE, WE MUST ALSO SEARCH A LIST OF LOADED PRIVILEGES. Arguments: Value - Value to look up. Name - Receives the corresponding name - allocated with MIDL_user_allocate() and ready to return via an RPC stub. Return Value: STATUS_SUCCESS - Succeeded. STATUS_NO_MEMORY - Indicates there was not enough heap memory available to produce the final TokenInformation structure. STATUS_NO_SUCH_PRIVILEGE - The specified privilege could not be found. --*/ { ULONG i; PUNICODE_STRING ReturnName; for ( i=0; iBuffer = MIDL_user_allocate( ReturnName->MaximumLength ); if (ReturnName->Buffer == NULL) { MIDL_user_free( ReturnName ); return(STATUS_NO_MEMORY); } RtlCopyUnicodeString( ReturnName, &LsapKnownPrivilege[i].Name ); (*Name) = ReturnName; return(STATUS_SUCCESS); } } return(STATUS_NO_SUCH_PRIVILEGE); } NTSTATUS LsapLookupKnownPrivilegeValue( PUNICODE_STRING Name, PLUID Value ) /*++ Routine Description: Look up the specified name and return the corresponding privilege's locally assigned value (if found). FOR NOW, WE ONLY SUPPORT WELL-KNOWN MICROSOFT PRIVILEGES. THESE ARE HARD-CODED HERE. IN THE FUTURE, WE MUST ALSO SEARCH A LIST OF LOADED PRIVILEGES. Arguments: Name - The name to look up. Value - Receives the corresponding locally assigned value. Return Value: STATUS_SUCCESS - Succeeded. STATUS_NO_SUCH_PRIVILEGE - The specified privilege could not be found. --*/ { ULONG i; BOOLEAN Found; for ( i=0; iBuffer = MIDL_user_allocate( NameInTable.MaximumLength ); if (ReturnName->Buffer == NULL) { MIDL_user_free( ReturnName ); return(STATUS_NO_MEMORY); } ReturnName->MaximumLength = NameInTable.Length; RtlCopyUnicodeString( ReturnName, &NameInTable ); (*DisplayName) = ReturnName; return(STATUS_SUCCESS); } NTSTATUS LsapDbInitializePrivilegeObject( VOID ) /*++ Routine Description: This function performs initialization functions related to the LSA privilege object. This includes: Initializing some variables. Loading DLLs containing displayable privilege names. Arguments: None. Return Value: STATUS_SUCCESS - The names have been successfully retrieved. STATUS_NO_MEMORY - Not enough memory was available to initialize. --*/ { NTSTATUS Status, NtStatus; ULONG i; LsapNeutralEnglish = MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL); Status = LsapOpenPrivilegeDlls( ); if (!NT_SUCCESS(Status)) { #if DBG DbgPrint("\n"); DbgPrint(" LSASS: Failed loading privilege display name DLLs.\n"); DbgPrint(" This is not fatal, but may cause some peculiarities\n"); DbgPrint(" in User Interfaces that display privileges.\n\n"); #endif //DBG return(Status); } // // Now set up our internal well-known privilege LUID to programmatic name // mapping. // i=0; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_CREATE_TOKEN_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_CREATE_TOKEN_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, &LsapKnownPrivilege[i].Name); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_LOCK_MEMORY_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_LOCK_MEMORY_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_INCREASE_QUOTA_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_INCREASE_QUOTA_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_MACHINE_ACCOUNT_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_MACHINE_ACCOUNT_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_TCB_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_TCB_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_SECURITY_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_SECURITY_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_TAKE_OWNERSHIP_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_TAKE_OWNERSHIP_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_LOAD_DRIVER_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_LOAD_DRIVER_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_SYSTEM_PROFILE_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_SYSTEM_PROFILE_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_SYSTEMTIME_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_SYSTEMTIME_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_PROF_SINGLE_PROCESS_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_PROF_SINGLE_PROCESS_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_INC_BASE_PRIORITY_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_INC_BASE_PRIORITY_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_CREATE_PAGEFILE_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_CREATE_PAGEFILE_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_CREATE_PERMANENT_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_CREATE_PERMANENT_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_BACKUP_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_BACKUP_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_RESTORE_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_RESTORE_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_SHUTDOWN_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_SHUTDOWN_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_DEBUG_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_DEBUG_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_AUDIT_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_AUDIT_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_SYSTEM_ENVIRONMENT_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_SYSTEM_ENVIRONMENT_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_CHANGE_NOTIFY_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_CHANGE_NOTIFY_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapKnownPrivilege[i].LocalValue = RtlConvertLongToLuid(SE_REMOTE_SHUTDOWN_PRIVILEGE); NtStatus = LsapDbInitWellKnownPrivilegeName( SE_REMOTE_SHUTDOWN_PRIVILEGE, &LsapKnownPrivilege[i].Name ); ASSERT(NT_SUCCESS(NtStatus)); i++; LsapWellKnownPrivilegeCount = i; ASSERT( i == (SE_MAX_WELL_KNOWN_PRIVILEGE - SE_MIN_WELL_KNOWN_PRIVILEGE +1)); return(Status); } NTSTATUS LsapOpenPrivilegeDlls( ) /*++ Routine Description: This function opens all the privilege DLLs that it can. Arguments: None. Return Value: STATUS_SUCCESS - The names have been successfully retrieved. STATUS_NO_MEMORY - Not enough heap was available to return the information. --*/ { NTSTATUS Status; ULONG PotentialDlls, FoundDlls, i; PUNICODE_STRING DllNames; // // Get the names of the DLLs out of the registry // Status = LsapGetPrivilegeDllNames( &DllNames, &PotentialDlls ); if (!NT_SUCCESS(Status)) { return(Status); } // // Allocate enough memory to hold handles to all potential DLLs. // LsapPrivilegeDlls = RtlAllocateHeap( RtlProcessHeap(), 0, PotentialDlls*sizeof(LSAP_DLL_DESCRIPTOR) ); if (LsapPrivilegeDlls == NULL) { return(STATUS_NO_MEMORY); } FoundDlls = 0; for ( i=0; iPrivilegeCount == 0) { // // No privileges. Return a dash // Status = LsapAdtBuildDashString( ResultantString, FreeWhenDone ); return(Status); } LengthNeeded = 0; for (j=0; jPrivilegeCount; j++) { Privilege = &(PrivilegeSet->Privilege[j].Luid); PrivName = ((PUNICODE_STRING *)&(PrivilegeSet->Privilege[j].Attributes)); for ( i=0; iLength + LineFormatting.Length; break; } } // // There is a possibility that there is no such privilege with // the specified value. In this case, generate a "?". // if (i >= LsapWellKnownPrivilegeCount) { (*PrivName) = &QuestionMark; LengthNeeded += QuestionMark.Length + LineFormatting.Length; } } // // Subtract off the length of the last line-formatting. // It isn't needed for the last line. // BUT! Add in enough for a null termination. // LengthNeeded = LengthNeeded - LineFormatting.Length + sizeof( WCHAR ); // // We now have the length we need. // Allocate the buffer and go through the list again copying names. // ResultantString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, (ULONG)LengthNeeded); if (ResultantString->Buffer == NULL) { return(STATUS_NO_MEMORY); } ResultantString->Length = LengthNeeded - (USHORT)sizeof(UNICODE_NULL); ResultantString->MaximumLength = LengthNeeded; NextName = ResultantString->Buffer; for (j=0; jPrivilegeCount; j++) { // // Copy the privilege name // PrivName = ((PUNICODE_STRING *)&(PrivilegeSet->Privilege[j].Attributes)); RtlCopyMemory( NextName, (*PrivName)->Buffer, (*PrivName)->Length ); NextName = (PWSTR)((PCHAR)NextName + (*PrivName)->Length); // // Copy the line formatting string, unless this is the last priv. // if (jPrivilegeCount-1) { RtlCopyMemory( NextName, LineFormatting.Buffer, LineFormatting.Length ); NextName = (PWSTR)((PCHAR)NextName + LineFormatting.Length); } } // // Add a null to the end // (*NextName) = (UNICODE_NULL); (*FreeWhenDone) = TRUE; return(STATUS_SUCCESS); } NTSTATUS LsapDbInitWellKnownPrivilegeName( IN ULONG Index, IN PUNICODE_STRING Name ) /*++ Routine Description: This function initializes the Name string to point to the well-known privilege name specified by Index. NOTE: This routine is a bit of a hack. It assumes that we have a fixed number of privileges in the system (which is true for Daytona) and that these privileges are in a loaded DLL which will not be unloaded until the system is shutdown. The privileges are expected to be arranged in the DLL in order of their LUIDs. That is, the low part of their LUID is an index into the array of privileges in the DLL. Arguments: Index - Index of privilege in MSPRIVS.DLL. Name - The unicode string to be initialized. Return Value: STATUS_SUCCESS - The privilege was found and Name is initialized. STATUS_NO_SUCH_PRIVILEGE - There is no privilege with the specified LUID. Other values, the privilege was not found, the name has been set to zero length. All Result Codes are generated by called routines. --*/ { HANDLE ProgrammaticResource, ProgrammaticLoad, ProgrammaticLock; PWORD NextWord; UNICODE_STRING TmpName; WORD i, DllIndex = 0, OffsetToNextEntry; //DbgPrint("Searching DLL[0] for privilege: [0, %d]...\n", Index); // // Prepare for failure // Name->MaximumLength = 0; Name->Length = 0; Name->Buffer = NULL; ProgrammaticResource = FindResourceEx( LsapPrivilegeDlls[ DllIndex ].DllHandle, RT_RCDATA, MAKEINTRESOURCE(LSA_PRIVILEGE_PROGRAM_NAMES), (WORD)LsapNeutralEnglish ); if (ProgrammaticResource == NULL) { ASSERT( NT_SUCCESS(STATUS_INTERNAL_DB_CORRUPTION) ); return(STATUS_INTERNAL_DB_CORRUPTION); } ProgrammaticLoad = LoadResource( LsapPrivilegeDlls[ DllIndex ].DllHandle, ProgrammaticResource ); if (ProgrammaticLoad == NULL) { ASSERT( NT_SUCCESS(STATUS_INTERNAL_DB_CORRUPTION) ); return(STATUS_INTERNAL_DB_CORRUPTION); } ProgrammaticLock = LockResource(ProgrammaticLoad); if (ProgrammaticLock == NULL) { ASSERT( NT_SUCCESS(STATUS_INTERNAL_DB_CORRUPTION) ); return(STATUS_INTERNAL_DB_CORRUPTION); } NextWord = (PWORD)ProgrammaticLock; // // Walk the list of defined privileges in this DLL looking for // a match. // for ( i=0; i