2573 lines
68 KiB
C
2573 lines
68 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
|
|||
|
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 <windef.h>
|
|||
|
#include <winnls.h>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// //
|
|||
|
// 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; i<LsapWellKnownPrivilegeCount; i++) {
|
|||
|
|
|||
|
if (RtlEqualLuid(Value, &LsapKnownPrivilege[i].LocalValue)) {
|
|||
|
|
|||
|
ReturnName = MIDL_user_allocate( sizeof(UNICODE_STRING) );
|
|||
|
if (ReturnName == NULL) {
|
|||
|
return(STATUS_NO_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
(*ReturnName) = LsapKnownPrivilege[i].Name;
|
|||
|
|
|||
|
ReturnName->Buffer = 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; i<LsapWellKnownPrivilegeCount; i++) {
|
|||
|
|
|||
|
Found = RtlEqualUnicodeString( Name, &LsapKnownPrivilege[i].Name, TRUE );
|
|||
|
|
|||
|
if (Found == TRUE) {
|
|||
|
|
|||
|
(*Value) = LsapKnownPrivilege[i].LocalValue;
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_NO_SUCH_PRIVILEGE);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
LsapLookupPrivilegeDisplayName(
|
|||
|
IN PUNICODE_STRING ProgrammaticName,
|
|||
|
IN WORD ClientLanguage,
|
|||
|
IN WORD ClientSystemDefaultLanguage,
|
|||
|
OUT PUNICODE_STRING *DisplayName,
|
|||
|
OUT PWORD LanguageReturned
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine looks through each of the privilege DLLs for the
|
|||
|
specified privilege. If found, its displayable name is returned.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ProgrammaticName - The programmatic name of the privilege to look up.
|
|||
|
E.g., "SeTakeOwnershipPrivilege".
|
|||
|
|
|||
|
ClientLanguage - The prefered language to be returned.
|
|||
|
|
|||
|
ClientSystemDefaultLanguage - The alternate prefered language
|
|||
|
to be returned.
|
|||
|
|
|||
|
DisplayName - receives a pointer to a buffer containing the displayable
|
|||
|
name associated with the privilege.
|
|||
|
E.g., "Take ownership of files or other objects".
|
|||
|
|
|||
|
The UNICODE_STRING and the buffer pointed to by that structure
|
|||
|
are individually allocated using MIDL_user_allocate() and must
|
|||
|
be freed using MIDL_user_free().
|
|||
|
|
|||
|
LanguageReturned - The language actually returned.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The name have been successfully retrieved.
|
|||
|
|
|||
|
STATUS_NO_MEMORY - Not enough heap was available to return the
|
|||
|
information.
|
|||
|
|
|||
|
STATUS_NO_SUCH_PRIVILEGE - The privilege could not be located
|
|||
|
in any of the privilege DLLs.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG DllIndex, PrivilegeIndex;
|
|||
|
|
|||
|
for ( DllIndex=0; DllIndex<LsapPrivilegeDllCount; DllIndex++) {
|
|||
|
|
|||
|
Status = LsapGetPrivilegeIndex( (PUNICODE_STRING)ProgrammaticName,
|
|||
|
DllIndex,
|
|||
|
&PrivilegeIndex
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
Status = LsapGetPrivilegeDisplayName( DllIndex,
|
|||
|
PrivilegeIndex,
|
|||
|
ClientLanguage,
|
|||
|
ClientSystemDefaultLanguage,
|
|||
|
DisplayName,
|
|||
|
LanguageReturned
|
|||
|
);
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return(Status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
LsapGetPrivilegeDisplayName(
|
|||
|
IN ULONG DllIndex,
|
|||
|
IN ULONG PrivilegeIndex,
|
|||
|
IN WORD ClientLanguage,
|
|||
|
IN WORD ClientSystemDefaultLanguage,
|
|||
|
OUT PUNICODE_STRING *DisplayName,
|
|||
|
OUT PWORD LanguageReturned
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns a copy of the specified privilege's display name.
|
|||
|
|
|||
|
The copy of the name is returned in two buffers allocated using
|
|||
|
MIDL_user_allocate(). This allows the information to be returned
|
|||
|
via an RPC service so that RPC generated stubs will correctly free
|
|||
|
the buffers.
|
|||
|
|
|||
|
Every attempt is made to retrieve a language that the client prefers
|
|||
|
(first the client, then the client's system). Failing this, this
|
|||
|
routine may return another language (such as the server's default
|
|||
|
language).
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DllIndex - The index of the privilege DLL to use.
|
|||
|
|
|||
|
PrivilegeIndex - The index of the privilege entry in the DLL whose
|
|||
|
display name is to be returned.
|
|||
|
|
|||
|
ClientLanguage - The language to return if possible.
|
|||
|
|
|||
|
ClientSystemDefaultLanguage - If ClientLanguage couldn't be found, then
|
|||
|
return this language if possible.
|
|||
|
|
|||
|
DisplayName - receives a pointer to a buffer containing the displayable
|
|||
|
name associated with the privilege.
|
|||
|
|
|||
|
The UNICODE_STRING and the buffer pointed to by that structure
|
|||
|
are individually allocated using MIDL_user_allocate() and must
|
|||
|
be freed using MIDL_user_free().
|
|||
|
|
|||
|
LanguageReturned - Receives the language actually retrieved.
|
|||
|
If neither ClientLanguage nor ClientSystemDefaultLanguage could be
|
|||
|
found, then this value may contain yet another value.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The display name has been successfully returned.
|
|||
|
|
|||
|
STATUS_NO_MEMORY - Not enough heap was available to return the
|
|||
|
information.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PWORD DisplayTable;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// get a pointer to the DISPLAYABLE_PRIVILEGE_TEXT table for
|
|||
|
// the appropriate language.
|
|||
|
//
|
|||
|
|
|||
|
LsapGetDisplayTable( DllIndex,
|
|||
|
ClientLanguage,
|
|||
|
ClientSystemDefaultLanguage,
|
|||
|
LanguageReturned,
|
|||
|
&DisplayTable
|
|||
|
);
|
|||
|
|
|||
|
Status = LsapCopyDisplayPrivilegeText( DisplayTable,
|
|||
|
PrivilegeIndex,
|
|||
|
DisplayName
|
|||
|
);
|
|||
|
|
|||
|
return(Status);
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
LsapGetPrivilegeIndex(
|
|||
|
IN PUNICODE_STRING Name,
|
|||
|
IN ULONG DllIndex,
|
|||
|
OUT PULONG PrivilegeIndex
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine looks through a single privilege DLL for the privilege
|
|||
|
with the name matching that specified by the Name parameter.
|
|||
|
If found, its index in this DLL is returned.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Name - The programmatic name of the privilege to look up.
|
|||
|
E.g., "SeTakeOwnershipPrivilege".
|
|||
|
|
|||
|
DllIndex - The index of the privilege DLL to look in.
|
|||
|
|
|||
|
PrivilegeIndex - Receives the index of the privilege entry in this
|
|||
|
resource file.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The pivilege has been successfully located.
|
|||
|
|
|||
|
STATUS_NO_SUCH_PRIVILEGE - The privilege could not be located.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
|
|||
|
{
|
|||
|
WORD i;
|
|||
|
HANDLE ProgrammaticResource, ProgrammaticLoad, ProgrammaticLock;
|
|||
|
PWORD NextWord;
|
|||
|
WORD OffsetToNextEntry;
|
|||
|
UNICODE_STRING TmpName;
|
|||
|
BOOLEAN NameFound;
|
|||
|
|
|||
|
|
|||
|
//DbgPrint("Searching DLL[%ld] for *%Z*...\n", DllIndex, Name);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
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<LsapPrivilegeDlls[ DllIndex ].Count; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// Skip index
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( i == (*NextWord) ); // Expect this to be the index;
|
|||
|
NextWord++;
|
|||
|
NextWord++;
|
|||
|
|
|||
|
//
|
|||
|
// Save offset to next entry and then
|
|||
|
// set up a unicode string representing the privilege
|
|||
|
// name. Make sure NextWord is left pointing at the
|
|||
|
// beginning of the name buffer.
|
|||
|
//
|
|||
|
|
|||
|
OffsetToNextEntry = (*NextWord);
|
|||
|
|
|||
|
TmpName.MaximumLength = (*NextWord++); // Skip the NextOffset field
|
|||
|
TmpName.Length = (*NextWord++); // Skip the Length field
|
|||
|
TmpName.Buffer = (PVOID)NextWord;
|
|||
|
|
|||
|
//DbgPrint(" Comparing to *%Z*\n", &TmpName);
|
|||
|
|
|||
|
NameFound = RtlEqualUnicodeString( Name, &TmpName, TRUE );
|
|||
|
|
|||
|
if (NameFound == TRUE) {
|
|||
|
(*PrivilegeIndex) = i;
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NextWord = (PWORD)( (PUCHAR)NextWord + OffsetToNextEntry );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_NO_SUCH_PRIVILEGE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
LsapGetDisplayTable(
|
|||
|
IN ULONG DllIndex,
|
|||
|
IN WORD ClientLanguage,
|
|||
|
IN WORD ClientSystemDefaultLanguage,
|
|||
|
OUT PWORD LanguageReturned,
|
|||
|
OUT PWORD *DisplayTable
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine gets a pointer to a display table of the specified
|
|||
|
privilege DLL. In selecting a language to use, the following
|
|||
|
preference is given:
|
|||
|
|
|||
|
ClientLanguage
|
|||
|
ClientSystemDefaultLanguage
|
|||
|
The default language of the privilege DLL
|
|||
|
|
|||
|
The last one of these MUST be present in the DLL and so failure
|
|||
|
is not possible.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DllIndex - The index of the privilege DLL to use.
|
|||
|
|
|||
|
ClientLanguage - The first choice language to locate. If the
|
|||
|
exact language can't be found, then a neutral form of the
|
|||
|
language is looked for.
|
|||
|
|
|||
|
ClientSystemDefaultLanguage - The second choice language to locate.
|
|||
|
If the exact language can't be found, then a neutral form of
|
|||
|
the language is looked for.
|
|||
|
|
|||
|
LanguageReturned - Receives the language actually located.
|
|||
|
|
|||
|
DisplayTable - Receives a pointer to the display table.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
HANDLE DisplayResource, DisplayLoad, DisplayLock;
|
|||
|
WORD NeutralLanguage;
|
|||
|
|
|||
|
|
|||
|
//DbgPrint("Searching DLL[%ld] for display table for language %ld...\n", (ULONG)ClientLanguage);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DisplayResource = FindResourceEx(
|
|||
|
LsapPrivilegeDlls[ DllIndex ].DllHandle,
|
|||
|
RT_RCDATA,
|
|||
|
MAKEINTRESOURCE(LSA_PRIVILEGE_DISPLAY_NAMES),
|
|||
|
ClientLanguage
|
|||
|
);
|
|||
|
(*LanguageReturned) = ClientLanguage;
|
|||
|
|
|||
|
|
|||
|
if (DisplayResource == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// How about a neutral form of the language?
|
|||
|
//
|
|||
|
|
|||
|
NeutralLanguage = MAKELANGID( PRIMARYLANGID(ClientLanguage),
|
|||
|
SUBLANG_NEUTRAL);
|
|||
|
|
|||
|
if (NeutralLanguage != ClientLanguage) {
|
|||
|
|
|||
|
DisplayResource = FindResourceEx(
|
|||
|
LsapPrivilegeDlls[ DllIndex ].DllHandle,
|
|||
|
RT_RCDATA,
|
|||
|
MAKEINTRESOURCE(LSA_PRIVILEGE_DISPLAY_NAMES),
|
|||
|
NeutralLanguage
|
|||
|
);
|
|||
|
(*LanguageReturned) = NeutralLanguage;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (DisplayResource == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Well, ok. How about the client's system's default lang?
|
|||
|
//
|
|||
|
|
|||
|
if (ClientLanguage != ClientSystemDefaultLanguage) {
|
|||
|
|
|||
|
DisplayResource = FindResourceEx(
|
|||
|
LsapPrivilegeDlls[ DllIndex ].DllHandle,
|
|||
|
RT_RCDATA,
|
|||
|
MAKEINTRESOURCE(LSA_PRIVILEGE_DISPLAY_NAMES),
|
|||
|
ClientSystemDefaultLanguage
|
|||
|
);
|
|||
|
(*LanguageReturned) = ClientSystemDefaultLanguage;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (DisplayResource == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Not very lucky so far. How about a neutral form
|
|||
|
// of the system's default language?
|
|||
|
//
|
|||
|
|
|||
|
NeutralLanguage = MAKELANGID( PRIMARYLANGID(ClientSystemDefaultLanguage),
|
|||
|
SUBLANG_NEUTRAL);
|
|||
|
|
|||
|
if (NeutralLanguage != ClientLanguage) {
|
|||
|
|
|||
|
DisplayResource = FindResourceEx(
|
|||
|
LsapPrivilegeDlls[ DllIndex ].DllHandle,
|
|||
|
RT_RCDATA,
|
|||
|
MAKEINTRESOURCE(LSA_PRIVILEGE_DISPLAY_NAMES),
|
|||
|
NeutralLanguage
|
|||
|
);
|
|||
|
(*LanguageReturned) = NeutralLanguage;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (DisplayResource == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Hmmm - ok, go with the DLL default language (must exist)
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
DisplayResource = FindResourceEx(
|
|||
|
LsapPrivilegeDlls[ DllIndex ].DllHandle,
|
|||
|
RT_RCDATA,
|
|||
|
MAKEINTRESOURCE(LSA_PRIVILEGE_DISPLAY_NAMES),
|
|||
|
LsapPrivilegeDlls[ DllIndex ].Language
|
|||
|
);
|
|||
|
(*LanguageReturned) = LsapPrivilegeDlls[ DllIndex ].Language;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(DisplayResource != NULL);
|
|||
|
|
|||
|
DisplayLoad = LoadResource(
|
|||
|
LsapPrivilegeDlls[ DllIndex ].DllHandle,
|
|||
|
DisplayResource
|
|||
|
);
|
|||
|
ASSERT (DisplayLoad != NULL);
|
|||
|
|
|||
|
DisplayLock = LockResource(DisplayLoad);
|
|||
|
|
|||
|
ASSERT (DisplayLock != NULL);
|
|||
|
|
|||
|
(*DisplayTable) = (PWORD)DisplayLock;
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
LsapCopyDisplayPrivilegeText(
|
|||
|
IN PWORD DisplayTable,
|
|||
|
IN ULONG PrivilegeIndex,
|
|||
|
OUT PUNICODE_STRING *DisplayName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DisplayTable - A pointer to the display table to reference.
|
|||
|
|
|||
|
PrivilegeIndex - The index of the privilege entry in the DLL whose
|
|||
|
display name is to be returned.
|
|||
|
|
|||
|
DisplayName - receives a pointer to a buffer containing the displayable
|
|||
|
name associated with the privilege.
|
|||
|
|
|||
|
The UNICODE_STRING and the buffer pointed to by that structure
|
|||
|
are individually allocated using MIDL_user_allocate() and must
|
|||
|
be freed using MIDL_user_free().
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The pivilege has been successfully located.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
ULONG i;
|
|||
|
PWORD NextWord;
|
|||
|
UNICODE_STRING NameInTable;
|
|||
|
WORD OffsetToNextEntry;
|
|||
|
PUNICODE_STRING ReturnName;
|
|||
|
|
|||
|
NextWord = DisplayTable;
|
|||
|
|
|||
|
//
|
|||
|
// Walk through the display table until we get the right
|
|||
|
// privilege entry.
|
|||
|
//
|
|||
|
|
|||
|
for ( i=0; i<PrivilegeIndex; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// Skip index
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( i == (ULONG)(*NextWord) ); // Expect this to be the index;
|
|||
|
NextWord++; // Skip index
|
|||
|
NextWord++; // both words of it.
|
|||
|
|
|||
|
//
|
|||
|
// Add offset to next element
|
|||
|
//
|
|||
|
|
|||
|
OffsetToNextEntry = (*NextWord);
|
|||
|
NextWord++; // Skip the NextOffset field
|
|||
|
NextWord++; // Skip the Length field
|
|||
|
|
|||
|
NextWord = (PWORD)( (PUCHAR)NextWord + OffsetToNextEntry );
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// OK, now we are at the right element
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( PrivilegeIndex == (ULONG)(*NextWord) );
|
|||
|
NextWord++; // Skip index
|
|||
|
NextWord++; // both words of it.
|
|||
|
|
|||
|
NameInTable.MaximumLength = (*NextWord++);
|
|||
|
NameInTable.Length = (*NextWord++);
|
|||
|
NameInTable.Buffer = NextWord;
|
|||
|
|
|||
|
ReturnName = MIDL_user_allocate( sizeof(UNICODE_STRING) );
|
|||
|
if (ReturnName == NULL) {
|
|||
|
return(STATUS_NO_MEMORY);
|
|||
|
}
|
|||
|
|
|||
|
ReturnName->Buffer = 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; i<PotentialDlls; i++) {
|
|||
|
Status = LdrLoadDll(
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&DllNames[i],
|
|||
|
&LsapPrivilegeDlls[FoundDlls].DllHandle
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
FoundDlls++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LsapPrivilegeDllCount = FoundDlls;
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (FoundDlls == 0) {
|
|||
|
DbgPrint("\n");
|
|||
|
DbgPrint("LSASS: Zero privilege DLLs loaded. We expected at\n");
|
|||
|
DbgPrint(" least msvprivs.dll to be loaded. Privilege\n");
|
|||
|
DbgPrint(" names will not be displayed at UI properly.\n\n");
|
|||
|
|
|||
|
}
|
|||
|
#endif //DBG
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// !!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!
|
|||
|
//
|
|||
|
// Before supporting user loadable privilege DLLs, we must add
|
|||
|
// code here to validate the structure of the loaded DLL. This
|
|||
|
// is necessary to prevent an invalid privilege DLL structure
|
|||
|
// from causing us to crash.
|
|||
|
//
|
|||
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// This routine validates the structure of each loaded DLL.
|
|||
|
// Any found to be invalid will be logged and discarded.
|
|||
|
//
|
|||
|
|
|||
|
Status = LsapValidatePrivilegeDlls();
|
|||
|
|
|||
|
|
|||
|
return(Status);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
LsapGetPrivilegeDllNames(
|
|||
|
OUT PUNICODE_STRING *DllNames,
|
|||
|
OUT PULONG DllCount
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function obtains the names of DLLs containing privilege
|
|||
|
definitions from the registry.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DllNames - Receives a pointer to an array of UNICODE_STRINGs
|
|||
|
This buffer must be freed using LsapFreePrivilegeDllNames.
|
|||
|
|
|||
|
DllCount - Receives the number of DLL names returned.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The names have been successfully retrieved.
|
|||
|
|
|||
|
STATUS_NO_MEMORY - Not enough heap was available to return the
|
|||
|
information.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// For the time being, just hard-code our one, known privilege DLL
|
|||
|
// name as a return value.
|
|||
|
|
|||
|
(*DllCount) = 1;
|
|||
|
|
|||
|
MsDllName.Length = 14;
|
|||
|
MsDllName.MaximumLength = 14;
|
|||
|
MsDllName.Buffer = &MsDllNameString[0];
|
|||
|
|
|||
|
(*DllNames) = &MsDllName;
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
LsapValidatePrivilegeDlls()
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine walks each loaded privilege DLL and validates
|
|||
|
its structure. It also collects some information from each
|
|||
|
DLL for later use.
|
|||
|
|
|||
|
Any DLLs found to have an invalid structure or revision are
|
|||
|
discarded and an error log entry is made describing the
|
|||
|
problem.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None - This operates off the global privilege dll data.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The DLLs have been validated.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
// !!!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!
|
|||
|
//
|
|||
|
// Before supported user loadable privilege DLLs, we must add
|
|||
|
// code here to validate the structure of the loaded DLL. This
|
|||
|
// is necessary to prevent an invalid privilege DLL structure
|
|||
|
// from causing us to crash. Mostly, make sure all the lengths
|
|||
|
// fall within the DLL. The SizeofResource() routine will be
|
|||
|
// usefull for this.
|
|||
|
//
|
|||
|
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|||
|
//
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG i, RemainingCount, CurrentIndex;
|
|||
|
HANDLE InfoResource, InfoLoad, InfoLock;
|
|||
|
PWORD NextWord;
|
|||
|
WORD MajorLanguage, MinorLanguage;
|
|||
|
BOOLEAN Discard;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//DbgPrint("Checking validity of %ld DLLS...\n", (ULONG)LsapPrivilegeDllCount);
|
|||
|
|
|||
|
RemainingCount = LsapPrivilegeDllCount;
|
|||
|
CurrentIndex = 0;
|
|||
|
for ( i=0; i<RemainingCount; i++) {
|
|||
|
|
|||
|
Discard = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Check the revision levels, get the privilege count,
|
|||
|
// and get the default language.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
InfoResource = FindResourceEx(
|
|||
|
LsapPrivilegeDlls[ CurrentIndex ].DllHandle,
|
|||
|
RT_RCDATA,
|
|||
|
MAKEINTRESOURCE(LSA_PRIVILEGE_DLL_INFO),
|
|||
|
(WORD)LsapNeutralEnglish
|
|||
|
);
|
|||
|
if (InfoResource != NULL) {
|
|||
|
|
|||
|
InfoLoad = LoadResource(
|
|||
|
LsapPrivilegeDlls[ CurrentIndex ].DllHandle,
|
|||
|
InfoResource
|
|||
|
);
|
|||
|
if (InfoLoad != NULL) {
|
|||
|
|
|||
|
InfoLock = LockResource(InfoLoad);
|
|||
|
|
|||
|
if (InfoLock != NULL) {
|
|||
|
NextWord = (PWORD)InfoLock;
|
|||
|
|
|||
|
//
|
|||
|
// First word is major revision.
|
|||
|
//
|
|||
|
|
|||
|
if ((*NextWord++) == LSA_PRIVILEGE_DLL_MAJOR_REV_1) {
|
|||
|
if ((*NextWord++) == LSA_PRIVILEGE_DLL_MINOR_REV_0) {
|
|||
|
Discard = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if (Discard == FALSE) {
|
|||
|
|
|||
|
//
|
|||
|
// Now get the privilege count and default language.
|
|||
|
//
|
|||
|
|
|||
|
MajorLanguage = (*NextWord++);
|
|||
|
MinorLanguage = (*NextWord++);
|
|||
|
LsapPrivilegeDlls[ CurrentIndex ].Language =
|
|||
|
MAKELANGID( MajorLanguage, MinorLanguage);
|
|||
|
|
|||
|
LsapPrivilegeDlls[ CurrentIndex ].Count = (*NextWord++);
|
|||
|
//DbgPrint(" DLL[%ld]:\n", i);
|
|||
|
//DbgPrint(" PrivilegeCount = %ld\n",(ULONG)LsapPrivilegeDlls[ CurrentIndex ].Count);
|
|||
|
//DbgPrint(" Language = 0x%lx\n",(ULONG)LsapPrivilegeDlls[ CurrentIndex ].Language);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Discard = FALSE; //Default for next segment of code
|
|||
|
|
|||
|
//
|
|||
|
// Walk each table in the DLL making sure their lengths don't exceed
|
|||
|
// the range of the DLL.
|
|||
|
//
|
|||
|
|
|||
|
Status = LsapValidateProgrammaticNames( CurrentIndex );
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Make sure one of the languages present is the default language.
|
|||
|
//
|
|||
|
|
|||
|
//FIX, FIX - do this before allowing user-produced DLLs.
|
|||
|
// This is NOT a product 1 required fix.
|
|||
|
// How do we know which languages have been loaded
|
|||
|
// into this DLL? This is NOT a product 1 required fix.
|
|||
|
|
|||
|
Discard = FALSE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if (Discard == TRUE) {
|
|||
|
|
|||
|
#if DBG
|
|||
|
DbgPrint("\nLSASS: Discarding privilege display name DLL[%ld].\n\n", i);
|
|||
|
#endif
|
|||
|
//
|
|||
|
// Discard it.
|
|||
|
//
|
|||
|
|
|||
|
LsapPrivilegeDlls[CurrentIndex] =
|
|||
|
LsapPrivilegeDlls[LsapPrivilegeDllCount];
|
|||
|
LsapPrivilegeDllCount--;
|
|||
|
|
|||
|
//
|
|||
|
// LOG AN ERROR - This is the only way for developers to determine
|
|||
|
// why their privileges didn't load. Should log
|
|||
|
// an error when we discovered the problem too,
|
|||
|
// giving as clear a description of the problem
|
|||
|
// as we can. Again, this is not a product 1
|
|||
|
// requirement.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
CurrentIndex++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
LsapValidateProgrammaticNames(
|
|||
|
ULONG DllIndex
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine validates the structure of a programmatic names
|
|||
|
table in a privilege dll.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DllIndex - The index of the DLL to validate. This operates off
|
|||
|
the global privilege dll data.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS - The table has been validated.
|
|||
|
|
|||
|
STATUS_UNSUCCESSFUL - The DLL has a problem. A message will be
|
|||
|
logged.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
WORD i;
|
|||
|
HANDLE ProgrammaticResource, ProgrammaticLoad, ProgrammaticLock;
|
|||
|
PWORD NextWord;
|
|||
|
WORD OffsetToNextEntry;
|
|||
|
|
|||
|
|
|||
|
ProgrammaticResource = FindResourceEx(
|
|||
|
LsapPrivilegeDlls[ DllIndex ].DllHandle,
|
|||
|
RT_RCDATA,
|
|||
|
MAKEINTRESOURCE(LSA_PRIVILEGE_PROGRAM_NAMES),
|
|||
|
(WORD)LsapNeutralEnglish
|
|||
|
);
|
|||
|
if (ProgrammaticResource == NULL) {
|
|||
|
|
|||
|
#if DBG
|
|||
|
DbgPrint("\n");
|
|||
|
DbgPrint("Lsa Server: Can't find programmatic name table in privilege\n");
|
|||
|
DbgPrint(" DLL. DLL index = %ld\n\n", DllIndex);
|
|||
|
#endif //DBG
|
|||
|
|
|||
|
return(STATUS_UNSUCCESSFUL);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ProgrammaticLoad = LoadResource(
|
|||
|
LsapPrivilegeDlls[ DllIndex ].DllHandle,
|
|||
|
ProgrammaticResource
|
|||
|
);
|
|||
|
if (ProgrammaticLoad == NULL) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("\n");
|
|||
|
DbgPrint("Lsa Server: Can't load programmatic name table in privilege\n");
|
|||
|
DbgPrint(" DLL. DLL index = %ld\n\n", DllIndex);
|
|||
|
#endif //DBG
|
|||
|
|
|||
|
return(STATUS_UNSUCCESSFUL);
|
|||
|
}
|
|||
|
|
|||
|
ProgrammaticLock = LockResource(ProgrammaticLoad);
|
|||
|
|
|||
|
if (ProgrammaticLock == NULL) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("\n");
|
|||
|
DbgPrint("Lsa Server: Can't lock programmatic name table in privilege\n");
|
|||
|
DbgPrint(" DLL. DLL index = %ld\n\n", DllIndex);
|
|||
|
#endif //DBG
|
|||
|
|
|||
|
return(STATUS_UNSUCCESSFUL);
|
|||
|
}
|
|||
|
|
|||
|
NextWord = (PWORD)ProgrammaticLock;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Walk the list of defined privileges in this DLL looking for
|
|||
|
// a match.
|
|||
|
//
|
|||
|
|
|||
|
for ( i=0; i<LsapPrivilegeDlls[ DllIndex ].Count; i++) {
|
|||
|
|
|||
|
//
|
|||
|
// Skip index
|
|||
|
//
|
|||
|
if (i != (*NextWord)) {
|
|||
|
#if DBG
|
|||
|
DbgPrint("\n");
|
|||
|
DbgPrint("Lsa Server: Error while processing privilege DLL: %ld\n", DllIndex);
|
|||
|
DbgPrint(" Privilege Name Table Structure flaw.\n");
|
|||
|
DbgPrint(" Privilege Index not found where expected. This\n");
|
|||
|
DbgPrint(" is typically caused by a message length being specified\n");
|
|||
|
DbgPrint(" incorrectly. Please check programmatic privilege name\n");
|
|||
|
DbgPrint(" lengths at or around the definition of privilege %d\n\n",i);
|
|||
|
|
|||
|
#endif //DBG
|
|||
|
return(STATUS_UNSUCCESSFUL);
|
|||
|
}
|
|||
|
|
|||
|
NextWord++;
|
|||
|
NextWord++;
|
|||
|
|
|||
|
//
|
|||
|
// Save offset to next entry and skip the actual string length
|
|||
|
//
|
|||
|
|
|||
|
OffsetToNextEntry = (*NextWord++);
|
|||
|
(NextWord++);
|
|||
|
|
|||
|
//
|
|||
|
// calculate address of next index
|
|||
|
//
|
|||
|
|
|||
|
NextWord = (PWORD)( (PUCHAR)NextWord + OffsetToNextEntry );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
LsapBuildPrivilegeAuditString(
|
|||
|
IN PPRIVILEGE_SET PrivilegeSet,
|
|||
|
OUT PUNICODE_STRING ResultantString,
|
|||
|
OUT PBOOLEAN FreeWhenDone
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
|
|||
|
This function builds a unicode string representing the specified
|
|||
|
privileges. The privilege strings returned are program names.
|
|||
|
These are not as human-friendly as the display names, but I don't
|
|||
|
think we stand a chance of actually showing several display names
|
|||
|
in an audit viewer.
|
|||
|
|
|||
|
if no privileges are present in the privilege set, then a string
|
|||
|
containing a dash is returned.
|
|||
|
|
|||
|
|
|||
|
!! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
|
|||
|
!! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
|
|||
|
!! WARNING WARNING !!
|
|||
|
!! WARNING For performance sake, this routine modifies WARNING !!
|
|||
|
!! WARNING the privilege set passed as an IN parameter. WARNING !!
|
|||
|
!! WARNING It does this so that it doesn't have to walk WARNING !!
|
|||
|
!! WARNING through the list of privileges twice. In the WARNING !!
|
|||
|
!! WARNING first pass through the privileges (adding up WARNING !!
|
|||
|
!! WARNING lengths needed) it stores the address of the WARNING !!
|
|||
|
!! WARNING corresponding string in the PrivilegeSet's WARNING !!
|
|||
|
!! WARNING Attributes field. WARNING !!
|
|||
|
!! WARNING WARNING !!
|
|||
|
!! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
|
|||
|
!! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !!
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PrivilegeSet - points to the privilege set to be converted to string
|
|||
|
format.
|
|||
|
|
|||
|
ResultantString - Points to the unicode string header. The body of this
|
|||
|
unicode string will be set to point to the resultant output value
|
|||
|
if successful. Otherwise, the Buffer field of this parameter
|
|||
|
will be set to NULL.
|
|||
|
|
|||
|
FreeWhenDone - If TRUE, indicates that the body of ResultantString
|
|||
|
must be freed to process heap when no longer needed.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
STATUS_NO_MEMORY - indicates memory could not be allocated
|
|||
|
for the string body.
|
|||
|
|
|||
|
All other Result Codes are generated by called routines.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
USHORT LengthNeeded;
|
|||
|
ULONG j;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
PLUID Privilege;
|
|||
|
|
|||
|
UNICODE_STRING LineFormatting;
|
|||
|
UNICODE_STRING QuestionMark;
|
|||
|
|
|||
|
PUNICODE_STRING * PrivName;
|
|||
|
|
|||
|
PWSTR NextName;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// we are using a field in the IN PrivilegeSet parameter to
|
|||
|
// avoid a second pass through the privileges. Make an assertion
|
|||
|
// that the field we are using is the same size as a pointer.
|
|||
|
// Note that this will not be the case in a 64-bit system, and
|
|||
|
// so this code will need to be modified to run in such an environment.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT ( sizeof(ULONG) == sizeof(PULONG) );
|
|||
|
|
|||
|
|
|||
|
RtlInitUnicodeString( &LineFormatting, L"\r\n\t\t\t");
|
|||
|
RtlInitUnicodeString( &QuestionMark, L"?");
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if (PrivilegeSet->PrivilegeCount == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// No privileges. Return a dash
|
|||
|
//
|
|||
|
|
|||
|
Status = LsapAdtBuildDashString( ResultantString, FreeWhenDone );
|
|||
|
return(Status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LengthNeeded = 0;
|
|||
|
|
|||
|
for (j=0; j<PrivilegeSet->PrivilegeCount; j++) {
|
|||
|
|
|||
|
Privilege = &(PrivilegeSet->Privilege[j].Luid);
|
|||
|
PrivName = ((PUNICODE_STRING *)&(PrivilegeSet->Privilege[j].Attributes));
|
|||
|
|
|||
|
for ( i=0; i<LsapWellKnownPrivilegeCount; i++) {
|
|||
|
|
|||
|
if (RtlEqualLuid(Privilege, &LsapKnownPrivilege[i].LocalValue)) {
|
|||
|
|
|||
|
(*PrivName) = &LsapKnownPrivilege[i].Name;
|
|||
|
|
|||
|
//
|
|||
|
// Add in the length and the line formatting length.
|
|||
|
// We'll subtract off the line formatting length for the
|
|||
|
// last line.
|
|||
|
//
|
|||
|
|
|||
|
LengthNeeded += (*PrivName)->Length +
|
|||
|
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; j<PrivilegeSet->PrivilegeCount; 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 (j<PrivilegeSet->PrivilegeCount-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<LsapPrivilegeDlls[ DllIndex ].Count; i++) {
|
|||
|
|
|||
|
ASSERT( i == (*NextWord) ); // Expect this to be the index;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Skip index
|
|||
|
//
|
|||
|
|
|||
|
NextWord++;
|
|||
|
NextWord++;
|
|||
|
|
|||
|
//
|
|||
|
// Save offset to next entry and then
|
|||
|
// set up a unicode string representing the privilege
|
|||
|
// name. Make sure NextWord is left pointing at the
|
|||
|
// beginning of the name buffer.
|
|||
|
//
|
|||
|
|
|||
|
OffsetToNextEntry = (*NextWord);
|
|||
|
|
|||
|
TmpName.MaximumLength = (*NextWord++); // Skip the NextOffset field
|
|||
|
TmpName.Length = (*NextWord++); // Skip the Length field
|
|||
|
TmpName.Buffer = (PVOID)NextWord;
|
|||
|
if ( (i+SE_MIN_WELL_KNOWN_PRIVILEGE) == (WORD)Index ) {
|
|||
|
(*Name) = TmpName;
|
|||
|
//DbgPrint(" Assigning to *%Z*\n", Name);
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NextWord = (PWORD)( (PUCHAR)NextWord + OffsetToNextEntry );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return(STATUS_NO_SUCH_PRIVILEGE);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|