5479 lines
154 KiB
C
5479 lines
154 KiB
C
|
||
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
rpcapi.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the routines for the LSA API that use RPC. The
|
||
routines in this module are merely wrappers that work as follows:
|
||
|
||
o Client program calls LsaFoo in this module
|
||
o LsaFoo calls RPC client stub interface routine LsapFoo with
|
||
similar parameters. Some parameters are translated from types
|
||
(e.g structures containing PVOIDs or certain kinds of variable length
|
||
parameters such as pointers to SID's) that are not specifiable on an
|
||
RPC interface, to specifiable form.
|
||
o RPC client stub LsapFoo calls interface specific marshalling routines
|
||
and RPC runtime to marshal parameters into a buffer and send them over
|
||
to the server side of the LSA.
|
||
o Server side calls RPC runtime and interface specific unmarshalling
|
||
routines to unmarshal parameters.
|
||
o Server side calls worker LsapFoo to perform API function.
|
||
o Server side marshals response/output parameters and communicates these
|
||
back to client stub LsapFoo
|
||
o LsapFoo exits back to LsaFoo which returns to client program.
|
||
|
||
Author:
|
||
|
||
Scott Birrell (ScottBi) April 24, 1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "lsaclip.h"
|
||
#include <align.h>
|
||
#include <rpcasync.h>
|
||
|
||
//
|
||
// The following limit on the maximum number of Sids or Names is tentative,
|
||
// so it is not being published.
|
||
//
|
||
|
||
#define LSAP_DB_TRIAL_MAXIMUM_SID_COUNT ((ULONG) 0x00005000L)
|
||
#define LSAP_DB_TRIAL_MAXIMUM_NAME_COUNT ((ULONG) 0x00005000L)
|
||
|
||
|
||
//
|
||
// Functions private to this module
|
||
//
|
||
|
||
NTSTATUS
|
||
LsapApiReturnResult(
|
||
IN ULONG ExceptionCode
|
||
);
|
||
|
||
BOOLEAN
|
||
LsapNeutralizeNt4Emulation()
|
||
{
|
||
BOOLEAN Result = FALSE;
|
||
NTSTATUS Status;
|
||
HKEY hkey;
|
||
DWORD Type;
|
||
DWORD Value;
|
||
DWORD Size = sizeof( Value );
|
||
static DWORD AmIDC = 0xFFFFFFFF;
|
||
ULONG i;
|
||
CHAR * Paths[] = {
|
||
"SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters\\GpParameters",
|
||
"SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters"
|
||
};
|
||
|
||
//
|
||
// NT4 emulation is always disabled on domain controllers
|
||
//
|
||
|
||
if ( AmIDC == 0xFFFFFFFF ) {
|
||
|
||
NT_PRODUCT_TYPE ProductType = NtProductWinNt;
|
||
|
||
if ( TRUE == RtlGetNtProductType( &ProductType )) {
|
||
|
||
if ( ProductType == NtProductLanManNt ) {
|
||
|
||
AmIDC = TRUE;
|
||
|
||
} else {
|
||
|
||
AmIDC = FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( AmIDC == TRUE ) {
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// This is not a DC; must go to the registry for the special "neutralize" value
|
||
// which could be either under NetLogon or NetLogon/GroupPolicy parameters key
|
||
//
|
||
|
||
for ( i = 0; i < sizeof( Paths ) / sizeof( Paths[0] ); i++ ) {
|
||
|
||
if ( ERROR_SUCCESS != RegOpenKeyEx(
|
||
HKEY_LOCAL_MACHINE,
|
||
Paths[i],
|
||
0,
|
||
KEY_READ,
|
||
&hkey )) {
|
||
|
||
continue;
|
||
}
|
||
|
||
if ( ERROR_SUCCESS != RegQueryValueEx(
|
||
hkey,
|
||
"NeutralizeNt4Emulator",
|
||
NULL,
|
||
&Type,
|
||
(LPBYTE)&Value,
|
||
&Size ) ||
|
||
Type != REG_DWORD ||
|
||
Size != sizeof( DWORD )) {
|
||
|
||
RegCloseKey( hkey );
|
||
continue;
|
||
|
||
} else {
|
||
|
||
RegCloseKey( hkey );
|
||
Result = ( Value != 0 );
|
||
break;
|
||
}
|
||
}
|
||
|
||
return Result;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Local Security Policy Administration API function prototypes //
|
||
// //
|
||
////////////////////////////////////////////////////////////////////////////
|
||
|
||
NTSTATUS
|
||
LsaOpenPolicy(
|
||
IN PUNICODE_STRING SystemName OPTIONAL,
|
||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
IN OUT PLSA_HANDLE PolicyHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
To administer the Local Security Policy of a local or remote system,
|
||
this API must be called to establish a session with that system's
|
||
Local Security Authority (LSA) subsystem. This API connects to
|
||
the LSA of the target system and opens the object representing
|
||
the target system's Local Security Policy database. A handle to
|
||
the object is returned. This handle must be used on all subsequent API
|
||
calls to administer the Local Security Policy information for the
|
||
target system.
|
||
|
||
Arguments:
|
||
|
||
SystemName - Name of the target system to be administered.
|
||
Administration of the local system is assumed if NULL is specified.
|
||
|
||
ObjectAttributes - Pointer to the set of attributes to use for this
|
||
connection. The security Quality Of Service information is used and
|
||
normally should provide Security Identification level of
|
||
impersonation. Some operations, however, require Security
|
||
Impersonation level of impersonation.
|
||
|
||
DesiredAccess - This is an access mask indicating accesses being
|
||
requested for the LSA Subsystem's LSA Database. These access types
|
||
are reconciled with the Discretionary Access Control List of the
|
||
target LsaDatabase object to determine whether the
|
||
accesses will be granted or denied.
|
||
|
||
PolicyHandle - Receives a handle to be used in future requests to
|
||
access the Local Security Policy of the target system. This handle
|
||
represents both the handle to the LsaDatabase object and
|
||
the RPC Context Handle for the connection to the target LSA
|
||
susbsystem.
|
||
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have access to the target
|
||
system's LSA Database, or does not have other desired accesses.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PLSAPR_SERVER_NAME ServerName = NULL;
|
||
USHORT NullTerminatedServerNameLength;
|
||
LSA_HANDLE LocalHandle = NULL ;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Get the Server Name as a Unicode String buffer. Set it to
|
||
// NULL (i.e. local machine) if a zero length or NULL Unicode String
|
||
// structure us passed. If a non NULL server name is given, we must
|
||
// ensure that it is terminated with a NULL wide character. Allocate
|
||
// a buffer that is one wide character longer than the server name
|
||
// buffer, copy the server name to that buffer and append a trailing
|
||
// NULL wide character.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(SystemName) &&
|
||
(SystemName->Buffer != NULL) &&
|
||
(SystemName->Length > 0)) {
|
||
|
||
NullTerminatedServerNameLength = SystemName->Length + (USHORT) sizeof (WCHAR);
|
||
|
||
ServerName = MIDL_user_allocate( NullTerminatedServerNameLength );
|
||
|
||
if (ServerName != NULL) {
|
||
|
||
RtlZeroMemory( ServerName, NullTerminatedServerNameLength );
|
||
|
||
RtlMoveMemory(
|
||
ServerName,
|
||
SystemName->Buffer,
|
||
SystemName->Length
|
||
);
|
||
|
||
} else {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
*PolicyHandle = NULL;
|
||
|
||
ObjectAttributes->RootDirectory = NULL;
|
||
|
||
Status = LsarOpenPolicy2(
|
||
ServerName,
|
||
(PLSAPR_OBJECT_ATTRIBUTES) ObjectAttributes,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE)&LocalHandle
|
||
);
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
//
|
||
// If the open failed because the new API doesn't exist, try the
|
||
// old one.
|
||
//
|
||
|
||
if ((Status == RPC_NT_UNKNOWN_IF) ||
|
||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
|
||
|
||
RpcTryExcept {
|
||
ASSERT(*PolicyHandle == NULL);
|
||
ASSERT(ObjectAttributes->RootDirectory == NULL);
|
||
|
||
Status = LsarOpenPolicy(
|
||
ServerName,
|
||
(PLSAPR_OBJECT_ATTRIBUTES) ObjectAttributes,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE)&LocalHandle
|
||
);
|
||
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
}
|
||
|
||
//
|
||
// If necessary, free the NULL-terminated server name buffer.
|
||
//
|
||
|
||
if (ServerName != NULL) {
|
||
|
||
MIDL_user_free( ServerName );
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
*PolicyHandle = LocalHandle;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaOpenPolicySce(
|
||
IN PUNICODE_STRING SystemName OPTIONAL,
|
||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
IN OUT PLSA_HANDLE PolicyHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Essentially the same as LsaOpenPolicy, except used only by SCE
|
||
to obtain a special "synchronized" policy handle that would serialize
|
||
access to policy operations.
|
||
|
||
Arguments:
|
||
|
||
Same as LsaOpenPolicy
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have access to the target
|
||
system's LSA Database, or does not have other desired accesses.
|
||
|
||
STATUS_PRIVILEGE_NOT_HELD - Caller must come in with TCB privilege.
|
||
|
||
STATUS_TIMEOUT - Timed out waiting on SCE to send pending changes
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PLSAPR_SERVER_NAME ServerName = NULL;
|
||
USHORT NullTerminatedServerNameLength;
|
||
LSA_HANDLE LocalHandle = NULL ;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Get the Server Name as a Unicode String buffer. Set it to
|
||
// NULL (i.e. local machine) if a zero length or NULL Unicode String
|
||
// structure us passed. If a non NULL server name is given, we must
|
||
// ensure that it is terminated with a NULL wide character. Allocate
|
||
// a buffer that is one wide character longer than the server name
|
||
// buffer, copy the server name to that buffer and append a trailing
|
||
// NULL wide character.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(SystemName) &&
|
||
(SystemName->Buffer != NULL) &&
|
||
(SystemName->Length > 0)) {
|
||
|
||
NullTerminatedServerNameLength = SystemName->Length + (USHORT) sizeof (WCHAR);
|
||
|
||
ServerName = MIDL_user_allocate( NullTerminatedServerNameLength );
|
||
|
||
if (ServerName != NULL) {
|
||
|
||
RtlZeroMemory( ServerName, NullTerminatedServerNameLength );
|
||
|
||
RtlMoveMemory(
|
||
ServerName,
|
||
SystemName->Buffer,
|
||
SystemName->Length
|
||
);
|
||
|
||
} else {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
*PolicyHandle = NULL;
|
||
|
||
ObjectAttributes->RootDirectory = NULL;
|
||
|
||
Status = LsarOpenPolicySce(
|
||
ServerName,
|
||
(PLSAPR_OBJECT_ATTRIBUTES) ObjectAttributes,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE)&LocalHandle
|
||
);
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
//
|
||
// If necessary, free the NULL-terminated server name buffer.
|
||
//
|
||
|
||
if (ServerName != NULL) {
|
||
|
||
MIDL_user_free( ServerName );
|
||
}
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
|
||
*PolicyHandle = LocalHandle;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaQueryInformationPolicy(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
OUT PVOID *Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaQueryInformationPolicy API obtains information from the Policy
|
||
object. The caller must have access appropriate to the information
|
||
being requested (see InformationClass parameter).
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
InformationClass - Specifies the information to be returned. The
|
||
Information Classes and accesses required are as follows:
|
||
|
||
Information Class Required Access Type
|
||
|
||
PolicyAuditLogInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyAuditEventsInformation POLICY_VIEW_AUDIT_INFORMATION
|
||
PolicyPrimaryDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyAccountDomainInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyPdAccountInformation POLICY_GET_PRIVATE_INFORMATION
|
||
PolicyLsaServerRoleInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyReplicaSourceInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
PolicyDefaultQuotaInformation POLICY_VIEW_LOCAL_INFORMATION
|
||
|
||
Buffer - receives a pointer to the buffer returned comtaining the
|
||
requested information. This buffer is allocated by this service
|
||
and must be freed when no longer needed by passing the returned
|
||
value to LsaFreeMemory().
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
||
access to complete the operation.
|
||
|
||
Others TBS
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PLSAPR_POLICY_INFORMATION PolicyInformation;
|
||
|
||
if ( InformationClass == PolicyDnsDomainInformationInt ) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
Retry:
|
||
|
||
PolicyInformation = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaQueryInformationPolicy.
|
||
//
|
||
|
||
switch (InformationClass)
|
||
{
|
||
case PolicyDnsDomainInformation:
|
||
case PolicyDnsDomainInformationInt:
|
||
Status = LsarQueryInformationPolicy2(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
InformationClass,
|
||
&PolicyInformation
|
||
);
|
||
break;
|
||
|
||
default:
|
||
Status = LsarQueryInformationPolicy(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
InformationClass,
|
||
&PolicyInformation
|
||
);
|
||
}
|
||
|
||
//
|
||
// Return pointer to Policy Information for the given class, or NULL.
|
||
//
|
||
|
||
*Buffer = PolicyInformation;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the returned Policy Information,
|
||
// free it.
|
||
//
|
||
|
||
if (PolicyInformation != NULL) {
|
||
|
||
MIDL_user_free(PolicyInformation);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
//
|
||
// If we suspect that the call failed due to NT4 emulation by the server,
|
||
// and we're configured to neutralize emulation, try the call again, neutralizing
|
||
//
|
||
|
||
if ( Status == RPC_NT_PROCNUM_OUT_OF_RANGE &&
|
||
InformationClass == PolicyDnsDomainInformation &&
|
||
LsapNeutralizeNt4Emulation()) {
|
||
|
||
InformationClass = PolicyDnsDomainInformationInt;
|
||
goto Retry;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaSetInformationPolicy(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN POLICY_INFORMATION_CLASS InformationClass,
|
||
IN PVOID Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaSetInformationPolicy API modifies information in the Policy Object.
|
||
The caller must have access appropriate to the information to be changed
|
||
in the Policy Object, see the InformationClass parameter.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
InformationClass - Specifies the type of information being changed.
|
||
The information types and accesses required to change them are as
|
||
follows:
|
||
|
||
PolicyAuditLogInformation POLICY_AUDIT_LOG_ADMIN
|
||
PolicyAuditEventsInformation POLICY_SET_AUDIT_REQUIREMENTS
|
||
PolicyPrimaryDomainInformation POLICY_TRUST_ADMIN
|
||
PolicyAccountDomainInformation POLICY_TRUST_ADMIN
|
||
PolicyPdAccountInformation Not settable by this API
|
||
PolicyLsaServerRoleInformation POLICY_SERVER_ADMIN
|
||
PolicyReplicaSourceInformation POLICY_SERVER_ADMIN
|
||
PolicyDefaultQuotaInformation POLICY_SET_DEFAULT_QUOTA_LIMITS
|
||
PolicyDnsDomainInformation POLICY_DNS_DOMAIN_INFO
|
||
PolicyDnsDomainInformationInt POLICY_DNS_DOMAIN_INFO
|
||
|
||
Buffer - Points to a structure containing the information appropriate
|
||
to the information type specified by the InformationClass parameter.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
Others TBS
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
if ( InformationClass == PolicyDnsDomainInformationInt ) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
Retry:
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaSetInformationPolicy.
|
||
//
|
||
|
||
switch (InformationClass)
|
||
{
|
||
case PolicyDnsDomainInformation:
|
||
case PolicyDnsDomainInformationInt:
|
||
Status = LsarSetInformationPolicy2(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
InformationClass,
|
||
(PLSAPR_POLICY_INFORMATION) Buffer
|
||
);
|
||
break;
|
||
|
||
default:
|
||
Status = LsarSetInformationPolicy(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
InformationClass,
|
||
(PLSAPR_POLICY_INFORMATION) Buffer
|
||
);
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
//
|
||
// If we suspect that the call failed due to NT4 emulation by the server,
|
||
// and we're configured to neutralize emulation, try the call again, neutralizing
|
||
//
|
||
|
||
if ( Status == RPC_NT_PROCNUM_OUT_OF_RANGE &&
|
||
InformationClass == PolicyDnsDomainInformation &&
|
||
LsapNeutralizeNt4Emulation()) {
|
||
|
||
InformationClass = PolicyDnsDomainInformationInt;
|
||
goto Retry;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaClearAuditLog(
|
||
IN LSA_HANDLE PolicyHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function clears the Audit Log. Caller must have POLICY_AUDIT_LOG_ADMIN
|
||
access to the Policy Object to perform this operation.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - handle from an LsaOpenPolicy call.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code.
|
||
|
||
STATUS_SUCCESS - The call completed successfully.
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the required access
|
||
to perform the operation.
|
||
|
||
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.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaClearAuditLog.
|
||
//
|
||
|
||
Status = LsarClearAuditLog(
|
||
(LSAPR_HANDLE) PolicyHandle
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsaLookupPrivilegeValue(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PUNICODE_STRING Name,
|
||
OUT PLUID Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function retrieves the value used on the target system
|
||
to locally represent the specified privilege. The privilege
|
||
is specified by programmatic name.
|
||
|
||
|
||
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;
|
||
LUID Buffer;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaLookupPrivilegeValue.
|
||
//
|
||
|
||
Status = LsarLookupPrivilegeValue(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
(PLSAPR_UNICODE_STRING)Name,
|
||
&Buffer
|
||
);
|
||
|
||
*Value = Buffer;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaLookupPrivilegeName(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PLUID Value,
|
||
OUT PUNICODE_STRING *Name
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function programmatic name corresponding to the privilege
|
||
represented on the target system by the provided LUID.
|
||
|
||
|
||
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 - 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;
|
||
PLSAPR_UNICODE_STRING Buffer = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaLookupPrivilegeName.
|
||
//
|
||
|
||
Status = LsarLookupPrivilegeName(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
Value,
|
||
&Buffer
|
||
);
|
||
|
||
(*Name) = (PUNICODE_STRING)Buffer;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the return buffer, free it.
|
||
//
|
||
|
||
if (Buffer != NULL) {
|
||
|
||
MIDL_user_free(Buffer);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
return(Status);
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsaLookupPrivilegeDisplayName(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PUNICODE_STRING Name,
|
||
OUT PUNICODE_STRING *DisplayName,
|
||
OUT PSHORT LanguageReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function retrieves a displayable name representing the
|
||
specified privilege.
|
||
|
||
|
||
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.
|
||
|
||
DisplayName - Receives a pointer to the privilege's displayable
|
||
name.
|
||
|
||
LanguageReturned - Receives the language of the returned displayable
|
||
name.
|
||
|
||
|
||
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;
|
||
SHORT ClientLanguage, ClientSystemDefaultLanguage;
|
||
PLSAPR_UNICODE_STRING Buffer = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaLookupPrivilegeDisplayName.
|
||
//
|
||
|
||
ClientLanguage = (SHORT)NtCurrentTeb()->CurrentLocale;
|
||
ClientSystemDefaultLanguage = ClientLanguage; //no sys default yet
|
||
Status = LsarLookupPrivilegeDisplayName(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
(PLSAPR_UNICODE_STRING)Name,
|
||
ClientLanguage,
|
||
ClientSystemDefaultLanguage,
|
||
&Buffer,
|
||
(PWORD)LanguageReturned
|
||
);
|
||
|
||
(*DisplayName) = (PUNICODE_STRING)Buffer;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the return buffer, free it.
|
||
//
|
||
|
||
if (Buffer != NULL) {
|
||
|
||
MIDL_user_free(Buffer);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsaClose(
|
||
IN LSA_HANDLE ObjectHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This API closes a handle to the LsaDatabase object or open object within
|
||
the database. If a handle to the LsaDatabase object is closed and there
|
||
are no objects still open within the current connection to the LSA, the
|
||
connection is closed. If a handle to an object within the database is
|
||
closed and the object is marked for DELETE access, the object will be
|
||
deleted when the last handle to that object is closed.
|
||
|
||
Arguments:
|
||
|
||
ObjectHandle - This parameter is either a handle to the LsaDatabase
|
||
object, which represents the entire LSA Database and also a
|
||
connection to the LSA of a target system, or a handle to an
|
||
object within the database.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
LSAPR_HANDLE Handle = (LSAPR_HANDLE) ObjectHandle;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaClose. Note that an additional
|
||
// level of indirection for the context handle parameter is required
|
||
// for the stub, because the server returns a NULL pointer to the handle
|
||
// so that the handle will be unbound by the stub.
|
||
//
|
||
|
||
Status = LsarClose( &Handle );
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
ULONG Code = RpcExceptionCode();
|
||
// Don't assert on bad handles -- this will cause bogus stress breaks
|
||
// ASSERT(Code != RPC_X_SS_CONTEXT_MISMATCH);
|
||
ASSERT(Code != RPC_S_INVALID_BINDING);
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
if ( !NT_SUCCESS(Status)
|
||
&& (0 != Handle)) {
|
||
//
|
||
// Make sure in all error cases to remove the client side resources
|
||
// consumed by this handle.
|
||
//
|
||
RpcTryExcept {
|
||
(void) RpcSsDestroyClientContext(&Handle);
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
//
|
||
// The try/except is for app compat so that bad handles don't bring
|
||
// the process down
|
||
//
|
||
NOTHING;
|
||
} RpcEndExcept;
|
||
}
|
||
|
||
ASSERT( Status != STATUS_INVALID_PARAMETER_12 );
|
||
ASSERT( Status != STATUS_INVALID_HANDLE );
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsaDelete(
|
||
IN LSA_HANDLE ObjectHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaDelete API deletes an object. The object must be
|
||
open for DELETE access.
|
||
|
||
Arguments:
|
||
|
||
ObjectHandle - Handle from an LsaOpen<object-type> call.
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_INVALID_HANDLE - The specified handle is not valid.
|
||
|
||
Result codes from RPC.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Try calling the new worker routine LsarDeleteObject(). If
|
||
// this fails because it does not exist (versions 1.369 and earlier)
|
||
// then call the old routine LsarDelete().
|
||
//
|
||
|
||
Status = LsarDeleteObject((LSAPR_HANDLE *) &ObjectHandle);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if ((Status == RPC_NT_UNKNOWN_IF) ||
|
||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE)) {
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarDelete((LSAPR_HANDLE) ObjectHandle);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaQuerySecurityObject(
|
||
IN LSA_HANDLE ObjectHandle,
|
||
IN SECURITY_INFORMATION SecurityInformation,
|
||
OUT PSECURITY_DESCRIPTOR *SecurityDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaQuerySecurityObject API returns security information assigned
|
||
to an LSA Database object.
|
||
|
||
Based on the caller's access rights and privileges, this procedure will
|
||
return a security descriptor containing any or all of the object's owner
|
||
ID, group ID, discretionary ACL or system ACL. To read the owner ID,
|
||
group ID, or the discretionary ACL, the caller must be granted
|
||
READ_CONTROL access to the object. To read the system ACL, the caller must
|
||
have SeSecurityPrivilege privilege.
|
||
|
||
This API is modelled after the NtQuerySecurityObject() system service.
|
||
|
||
Arguments:
|
||
|
||
ObjectHandle - A handle to an existing object in the LSA Database.
|
||
|
||
SecurityInformation - Supplies a value describing which pieces of
|
||
security information are being queried. The values that may be
|
||
specified are the same as those defined in the NtSetSecurityObject()
|
||
API section.
|
||
|
||
SecurityDescriptor - receives a pointer to a buffer containing the
|
||
requested security information. This information is returned in
|
||
the form of a security descriptor. The caller is responsible for
|
||
freeing the returned buffer using LsaFreeMemory() when no longer
|
||
needed.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_INVALID_PARAMETER - An invalid parameter has been specified.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
LSAPR_SR_SECURITY_DESCRIPTOR ReturnedSD;
|
||
PLSAPR_SR_SECURITY_DESCRIPTOR PReturnedSD;
|
||
|
||
//
|
||
// The retrieved security descriptor is returned via a data structure that
|
||
// looks like:
|
||
//
|
||
// +-----------------------+
|
||
// | Length (bytes) |
|
||
// |-----------------------| +--------------+
|
||
// | SecurityDescriptor ---|--------->| Self-Relative|
|
||
// +-----------------------+ | Security |
|
||
// | Descriptor |
|
||
// +--------------+
|
||
//
|
||
// The first of these buffers is a local stack variable. The buffer containing
|
||
// the self-relative security descriptor is allocated by the RPC runtime. The
|
||
// pointer to the self-relative security descriptor is what is passed back to our
|
||
// caller.
|
||
//
|
||
//
|
||
|
||
//
|
||
// To prevent RPC from trying to marshal a self-relative security descriptor,
|
||
// make sure its field values are appropriately initialized to zero and null.
|
||
//
|
||
|
||
ReturnedSD.Length = 0;
|
||
ReturnedSD.SecurityDescriptor = NULL;
|
||
|
||
//
|
||
// Call the server ...
|
||
//
|
||
|
||
|
||
RpcTryExcept{
|
||
|
||
PReturnedSD = &ReturnedSD;
|
||
|
||
Status = LsarQuerySecurityObject(
|
||
(LSAPR_HANDLE) ObjectHandle,
|
||
SecurityInformation,
|
||
&PReturnedSD
|
||
);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
(*SecurityDescriptor) = ReturnedSD.SecurityDescriptor;
|
||
|
||
} else {
|
||
|
||
(*SecurityDescriptor) = NULL;
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QuerySecurityObjectError;
|
||
}
|
||
|
||
QuerySecurityObjectFinish:
|
||
|
||
return(Status);
|
||
|
||
QuerySecurityObjectError:
|
||
|
||
goto QuerySecurityObjectFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaSetSecurityObject(
|
||
IN LSA_HANDLE ObjectHandle,
|
||
IN SECURITY_INFORMATION SecurityInformation,
|
||
IN PSECURITY_DESCRIPTOR SecurityDescriptor
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaSetSecurityObject API takes a well formaed Security Descriptor
|
||
and assigns specified portions of it to an object. Based on the flags set
|
||
in the SecurityInformation parameter and the caller's access rights, this
|
||
procedure will replace any or alll of the security information associated
|
||
with the object.
|
||
|
||
The caller must have WRITE_OWNER access to the object to change the
|
||
owner or Primary group of the object. The caller must have WRITE_DAC
|
||
access to the object to change the Discretionary ACL. The caller must
|
||
have SeSecurityPrivilege to assign a system ACL to an object.
|
||
|
||
This API is modelled after the NtSetSecurityObject() system service.
|
||
|
||
Arguments:
|
||
|
||
ObjectHandle - A handle to an existing object in the LSA Database.
|
||
|
||
SecurityInformation - Indicates which security information is to be
|
||
applied to the object. The values that may be specified are the
|
||
same as those defined in the NtSetSecurityObject() API section.
|
||
The value(s) to be assigned are passed in the SecurityDescriptor
|
||
parameter.
|
||
|
||
SecurityDescriptor - A pointer to a well formed Security Descriptor.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_INVALID_PARAMETER - An invalid parameter has been specified.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG SDLength;
|
||
LSAPR_SR_SECURITY_DESCRIPTOR DescriptorToPass = { 0 };
|
||
|
||
//
|
||
// Make a self relative security descriptor for use in the RPC call..
|
||
//
|
||
|
||
SDLength = 0;
|
||
|
||
Status = RtlMakeSelfRelativeSD( SecurityDescriptor, NULL, &SDLength);
|
||
|
||
if (Status != STATUS_BUFFER_TOO_SMALL) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto SetSecurityObjectError;
|
||
}
|
||
|
||
DescriptorToPass.SecurityDescriptor = MIDL_user_allocate( SDLength );
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
if (DescriptorToPass.SecurityDescriptor == NULL) {
|
||
|
||
goto SetSecurityObjectError;
|
||
|
||
}
|
||
|
||
//
|
||
// Make an appropriate self-relative security descriptor
|
||
//
|
||
|
||
Status = RtlMakeSelfRelativeSD(
|
||
SecurityDescriptor,
|
||
(PSECURITY_DESCRIPTOR)DescriptorToPass.SecurityDescriptor,
|
||
&SDLength
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetSecurityObjectError;
|
||
}
|
||
|
||
DescriptorToPass.Length = SDLength;
|
||
|
||
RpcTryExcept{
|
||
|
||
Status = LsarSetSecurityObject(
|
||
(LSAPR_HANDLE) ObjectHandle,
|
||
SecurityInformation,
|
||
&DescriptorToPass
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetSecurityObjectError;
|
||
}
|
||
|
||
SetSecurityObjectFinish:
|
||
|
||
//
|
||
// If necessary, free the Self Relative SD passed to the worker.
|
||
//
|
||
|
||
if (DescriptorToPass.SecurityDescriptor != NULL) {
|
||
|
||
MIDL_user_free( DescriptorToPass.SecurityDescriptor );
|
||
|
||
DescriptorToPass.SecurityDescriptor = NULL;
|
||
}
|
||
|
||
return(Status);
|
||
|
||
SetSecurityObjectError:
|
||
|
||
goto SetSecurityObjectFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaChangePassword(
|
||
IN PUNICODE_STRING ServerName,
|
||
IN PUNICODE_STRING DomainName,
|
||
IN PUNICODE_STRING AccountName,
|
||
IN PUNICODE_STRING OldPassword,
|
||
IN PUNICODE_STRING NewPassword
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaChangePassword API is used to change a user account's password.
|
||
The user must have appropriate access to the user account and must
|
||
know the current password value.
|
||
|
||
|
||
Arguments:
|
||
|
||
ServerName - The name of the Domain Controller at which the password
|
||
can be changed.
|
||
|
||
DomainName - The name of the domain in which the account exists.
|
||
|
||
AccountName - The name of the account whose password is to be changed.
|
||
|
||
NewPassword - The new password value.
|
||
|
||
OldPassword - The old (current) password value.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_ILL_FORMED_PASSWORD - The new password is poorly formed, e.g.
|
||
contains characters that can't be entered from the keyboard.
|
||
|
||
STATUS_PASSWORD_RESTRICTION - A restriction prevents the password
|
||
from being changed. This may be for an number of reasons,
|
||
including time restrictions on how often a password may be changed
|
||
or length restrictions on the provided (new) password.
|
||
|
||
This error might also be returned if the new password matched
|
||
a password in the recent history log for the account. Security
|
||
administrators indicate how many of the most recently used
|
||
passwords may not be re-used.
|
||
|
||
STATUS_WRONG_PASSWORD - OldPassword does not contain the user's
|
||
current password.
|
||
|
||
STATUS_NO_SUCH_USER - The SID provided does not lead to a user
|
||
account.
|
||
|
||
STATUS_CANT_UPDATE_MASTER - An attempt to update the master copy
|
||
of the password was unsuccessful. Please try again later.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
DBG_UNREFERENCED_PARAMETER( ServerName );
|
||
DBG_UNREFERENCED_PARAMETER( DomainName );
|
||
DBG_UNREFERENCED_PARAMETER( AccountName );
|
||
DBG_UNREFERENCED_PARAMETER( OldPassword );
|
||
DBG_UNREFERENCED_PARAMETER( NewPassword );
|
||
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaCreateAccount(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PSID AccountSid,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSA_HANDLE AccountHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaCreateAccount API adds a user or group account to the
|
||
list of accounts in the target system's LsaDatabase object. The
|
||
newly added account object is initially placed in the opened state and
|
||
a handle to it is returned. The caller must have LSA_CREATE_ACCOUNT
|
||
access to the LsaDatabase object.
|
||
|
||
Note that no check is made to determine whether there is an account
|
||
of the given Sid in the target system's Primary Domain (if any), nor
|
||
is any check made to verify that the Sid and name describe the same
|
||
account.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenLsa call.
|
||
|
||
AccountSid - Points to the SID of the Account object.
|
||
|
||
DesiredAccess - Specifies the accesses to be granted to the newly
|
||
created and opened account.
|
||
|
||
AccountHandle - Receives a handle to the newly created and opened
|
||
account. This handle is used on subsequent accesses to the account
|
||
until closed.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_ACCOUNT_ALREADY_EXISTS - A user or group account object having
|
||
the Sid given in AccountInformation already exists.
|
||
|
||
STATUS_INVALID_PARAMETER - An invalid parameter has been specified,
|
||
one or more of the following apply.
|
||
|
||
- CreateDisposition not valid
|
||
- A user or group account having the Sid given AccountInformation
|
||
already exists, but CreateDisposition = LSA_OBJECT_CREATE.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarCreateAccount(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
(PLSAPR_SID) AccountSid,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE) AccountHandle
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaEnumerateAccounts(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
|
||
OUT PVOID *Buffer,
|
||
IN ULONG PreferedMaximumLength,
|
||
OUT PULONG CountReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaEnumerateAccounts API returns information about
|
||
Account objects. 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.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenLsa call.
|
||
|
||
EnumerationContext - API-specific handle to allow multiple calls
|
||
(see Routine Description above).
|
||
|
||
EnumerationInformation - Receives a pointer to an array of structures
|
||
each describing an Account object. Currently, each structure contains
|
||
a pointer to the Account Sid.
|
||
|
||
PreferedMaximumLength - Prefered maximum 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 - Pointer to location which receives the number of entries
|
||
returned.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - The call completed successfully, there may be
|
||
more entries.
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
|
||
is returned if there are no more objects to enumerate. Note that
|
||
one or more objects may be enumerated on a call that returns this
|
||
reply.
|
||
|
||
STATUS_INVALID_PARAMETER - Invalid parameter.
|
||
|
||
- NULL return pointer for enumeration buffer.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
LSAPR_ACCOUNT_ENUM_BUFFER EnumerationBuffer;
|
||
|
||
EnumerationBuffer.EntriesRead = 0;
|
||
EnumerationBuffer.Information = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Enumerate the Accounts. On successful return,
|
||
// the Enumeration Buffer structure will receive a count
|
||
// of the number of Accounts enumerated this call
|
||
// and a pointer to an array of Account Information Entries.
|
||
//
|
||
// EnumerationBuffer -> EntriesRead
|
||
// Information -> Account Info for Domain 0
|
||
// Account Info for Domain 1
|
||
// ...
|
||
// Account Info for Domain
|
||
// (EntriesRead - 1)
|
||
//
|
||
|
||
Status = LsarEnumerateAccounts(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
EnumerationContext,
|
||
&EnumerationBuffer,
|
||
PreferedMaximumLength
|
||
);
|
||
|
||
//
|
||
// Return enumeration information or NULL to caller.
|
||
//
|
||
// NOTE: "Information" is allocated by the called client stub
|
||
// as a single block via MIDL_user_allocate, because Information is
|
||
// allocated all-nodes. We can therefore pass back the pointer
|
||
// directly to the client, who will be able to free the memory after
|
||
// use via LsaFreeMemory() [which makes a MIDL_user_free call].
|
||
//
|
||
|
||
*CountReturned = EnumerationBuffer.EntriesRead;
|
||
*Buffer = EnumerationBuffer.Information;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the Account Information array,
|
||
// free it.
|
||
//
|
||
|
||
if (EnumerationBuffer.Information != NULL) {
|
||
|
||
MIDL_user_free(EnumerationBuffer.Information);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaCreateTrustedDomain(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PLSA_TRUST_INFORMATION TrustedDomainInformation,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSA_HANDLE TrustedDomainHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaCreateTrustedDomain API creates a new TrustedDomain object. The
|
||
caller must have POLICY_TRUST_ADMIN access to the Policy Object.
|
||
|
||
Note that NO verification is done to check that the given domain name
|
||
matches the given SID or that the SID or name represent an actual domain.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
TrustedDomainInformation - Pointer to structure containing the name and
|
||
SID of the new Trusted Domain.
|
||
|
||
DesiredAccess - Specifies the accesses to be granted for the newly
|
||
created object.
|
||
|
||
TrustedDomainHandle - receives a handle referencing the newly created
|
||
object. This handle is used on subsequent accesses to the object.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
*TrustedDomainHandle = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarCreateTrustedDomain(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
(PLSAPR_TRUST_INFORMATION) TrustedDomainInformation,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE) TrustedDomainHandle
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaOpenTrustedDomain(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PSID TrustedDomainSid,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSA_HANDLE TrustedDomainHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaOpenTrustedDomain API opens an existing TrustedDomain object
|
||
using the SID as the primary key value.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - An open handle to a Policy object.
|
||
|
||
TrustedDomainSid - Pointer to the account's Sid.
|
||
|
||
DesiredAccess - This is an access mask indicating accesses being
|
||
requested to the target object.
|
||
|
||
TrustedDomainHandle - Receives a handle to be used in future requests.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_TRUSTED_DOMAIN_NOT_FOUND - There is no TrustedDomain object in the
|
||
target system's LSA Database having the specified AccountSid.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarOpenTrustedDomain(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
(PLSAPR_SID) TrustedDomainSid,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE) TrustedDomainHandle
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaQueryInfoTrustedDomain(
|
||
IN LSA_HANDLE TrustedDomainHandle,
|
||
IN TRUSTED_INFORMATION_CLASS InformationClass,
|
||
OUT PVOID *Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaQueryInfoTrustedDomain API obtains information from a
|
||
TrustedDomain object. The caller must have access appropriate to the
|
||
information being requested (see InformationClass parameter).
|
||
|
||
Arguments:
|
||
|
||
TrustedDomainHandle - Handle from an LsaOpenTrustedDomain or
|
||
LsaCreateTrustedDomain call.
|
||
|
||
InformationClass - Specifies the information to be returned. The
|
||
Information Classes and accesses required are as follows:
|
||
|
||
Information Class Required Access Type
|
||
|
||
TrustedAccountNameInformation TRUSTED_QUERY_ACCOUNT_NAME
|
||
TrustedControllersInformation TRUSTED_QUERY_CONTROLLERS
|
||
TrustedPosixInformation TRUSTED_QUERY_POSIX
|
||
|
||
Buffer - Receives a pointer to the buffer returned comtaining the
|
||
requested information. This buffer is allocated by this service
|
||
and must be freed when no longer needed by passing the returned
|
||
value to LsaFreeMemory().
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate
|
||
access to complete the operation.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
|
||
such as memory, to complete the call.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
PLSAPR_TRUSTED_DOMAIN_INFO TrustedDomainInformation = NULL;
|
||
|
||
//
|
||
// Avoid the internal info levels that represent the encrypted version on
|
||
// the wire.
|
||
//
|
||
switch ( InformationClass ) {
|
||
case TrustedDomainAuthInformationInternal:
|
||
case TrustedDomainFullInformationInternal:
|
||
case TrustedDomainInformationEx2Internal:
|
||
case TrustedDomainFullInformation2Internal:
|
||
return STATUS_INVALID_INFO_CLASS;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaQueryInformationTrustedDomain.
|
||
//
|
||
|
||
Status = LsarQueryInfoTrustedDomain(
|
||
(LSAPR_HANDLE) TrustedDomainHandle,
|
||
InformationClass,
|
||
&TrustedDomainInformation
|
||
);
|
||
|
||
//
|
||
// Return pointer to Policy Information for the given class, or NULL.
|
||
//
|
||
|
||
*Buffer = TrustedDomainInformation;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the returned Trusted Domain Information,
|
||
// free it.
|
||
//
|
||
|
||
if (TrustedDomainInformation != NULL) {
|
||
|
||
MIDL_user_free(TrustedDomainInformation);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaSetInformationTrustedDomain(
|
||
IN LSA_HANDLE TrustedDomainHandle,
|
||
IN TRUSTED_INFORMATION_CLASS InformationClass,
|
||
IN PVOID Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaSetInformationTrustedDomain API modifies information in the Trusted
|
||
Domain Object. The caller must have access appropriate to the
|
||
information to be changedin the Policy Object, see the InformationClass
|
||
parameter.
|
||
|
||
Arguments:
|
||
|
||
TrustedDomainHandle - Handle from an LsaOpenTrustedDomain or
|
||
LsaCreateTrustedDomain call.
|
||
|
||
InformationClass - Specifies the type of information being changed.
|
||
The information types and accesses required to change them are as
|
||
follows:
|
||
|
||
TrustedAccountInformation ( Cannot be set )
|
||
TrustedControllersInformation TRUSTED_SET_CONTROLLERS
|
||
TrustedPosixOffsetInformation TRUSTED_POSIX_INFORMATION
|
||
|
||
Buffer - Points to a structure containing the information appropriate
|
||
to the InformationClass parameter.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - Call completed successfully.
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources,
|
||
such as memory, to complete the call.
|
||
|
||
STATUS_INVALID_HANDLE - Handle is invalid or is of the wrong type.
|
||
|
||
STATUS_INVALID_PARAMETER - Invalid parameter:
|
||
Information class invalid
|
||
Information class cannot be set
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION_INTERNAL InternalAuthBuffer = NULL;
|
||
PVOID InternalBuffer;
|
||
TRUSTED_INFORMATION_CLASS InternalInformationClass;
|
||
|
||
LSAPR_TRUSTED_DOMAIN_FULL_INFORMATION_INTERNAL InternalFullBuffer;
|
||
|
||
//
|
||
// Initialization
|
||
//
|
||
|
||
InternalInformationClass = InformationClass;
|
||
InternalBuffer = Buffer;
|
||
|
||
//
|
||
// Avoid the internal info levels that represent the encrypted version on
|
||
// the wire.
|
||
//
|
||
switch ( InformationClass ) {
|
||
case TrustedPasswordInformation:
|
||
case TrustedDomainInformationBasic:
|
||
case TrustedDomainAuthInformationInternal:
|
||
case TrustedDomainFullInformationInternal:
|
||
case TrustedDomainInformationEx2Internal:
|
||
case TrustedDomainFullInformation2Internal:
|
||
Status = STATUS_INVALID_INFO_CLASS;
|
||
goto Cleanup;
|
||
|
||
//
|
||
// Handle the info classes that need to be encrypted on the wire
|
||
//
|
||
case TrustedDomainAuthInformation: {
|
||
|
||
//
|
||
// Encrypt the data into an internal buffer.
|
||
//
|
||
|
||
Status = LsapEncryptAuthInfo( TrustedDomainHandle,
|
||
(PLSAPR_TRUSTED_DOMAIN_AUTH_INFORMATION) Buffer,
|
||
&InternalAuthBuffer );
|
||
|
||
if ( !NT_SUCCESS(Status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Use an internal info level to tell the server that the data is
|
||
// encrypted.
|
||
//
|
||
|
||
InternalInformationClass = TrustedDomainAuthInformationInternal;
|
||
InternalBuffer = InternalAuthBuffer;
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Handle the info classes that need to be encrypted on the wire
|
||
//
|
||
case TrustedDomainFullInformation: {
|
||
PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION FullBuffer =
|
||
(PLSAPR_TRUSTED_DOMAIN_FULL_INFORMATION) Buffer;
|
||
|
||
//
|
||
// Encrypt the data into an internal buffer.
|
||
//
|
||
|
||
Status = LsapEncryptAuthInfo( TrustedDomainHandle,
|
||
&FullBuffer->AuthInformation,
|
||
&InternalAuthBuffer );
|
||
|
||
if ( !NT_SUCCESS(Status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Copy all of the information into a single new structure.
|
||
//
|
||
|
||
InternalFullBuffer.Information = FullBuffer->Information;
|
||
InternalFullBuffer.PosixOffset = FullBuffer->PosixOffset;
|
||
InternalFullBuffer.AuthInformation = *InternalAuthBuffer;
|
||
|
||
//
|
||
// Use an internal info level to tell the server that the data is
|
||
// encrypted.
|
||
//
|
||
|
||
InternalInformationClass = TrustedDomainFullInformationInternal;
|
||
InternalBuffer = &InternalFullBuffer;
|
||
break;
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the information class was morphed,
|
||
// try the morphed class.
|
||
//
|
||
|
||
if ( InternalInformationClass != InformationClass ) {
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub
|
||
//
|
||
|
||
Status = LsarSetInformationTrustedDomain(
|
||
(LSAPR_HANDLE) TrustedDomainHandle,
|
||
InternalInformationClass,
|
||
(PLSAPR_TRUSTED_DOMAIN_INFO) InternalBuffer
|
||
);
|
||
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
//
|
||
// If the morphed info class is valid,
|
||
// we're all done with this call.
|
||
// (Otherwise, drop through to try the non-morphed class.)
|
||
//
|
||
|
||
if ( Status != RPC_NT_INVALID_TAG ) {
|
||
goto Cleanup;
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// Handle non-morphed information classes.
|
||
//
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub
|
||
//
|
||
|
||
Status = LsarSetInformationTrustedDomain(
|
||
(LSAPR_HANDLE) TrustedDomainHandle,
|
||
InformationClass,
|
||
(PLSAPR_TRUSTED_DOMAIN_INFO) Buffer
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
Cleanup:
|
||
if ( InternalAuthBuffer != NULL ) {
|
||
LocalFree( InternalAuthBuffer );
|
||
}
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaEnumerateTrustedDomains(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
|
||
OUT PVOID *Buffer,
|
||
IN ULONG PreferedMaximumLength,
|
||
OUT PULONG CountReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaEnumerateTrustedDomains API returns information about the accounts
|
||
in the target system's Policy object. 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.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
EnumerationContext - API-specific handle to allow multiple calls
|
||
(see Routine Description above).
|
||
|
||
Buffer - Receives a pointer to a buffer containing enumeration
|
||
information. This buffer is an array of structures of type
|
||
LSA_TRUST_INFORMATION. If no trusted domains are found,
|
||
NULL is returned.
|
||
|
||
PreferedMaximumLength - Prefered maximum 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 - Pointer to variable which will receive a count of the
|
||
entries returned.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - The call completed successfully, there may be
|
||
more entries.
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_NO_MORE_ENTRIES - There are no more entries. This warning
|
||
is returned if there are no more objects to enumerate. Note that
|
||
one or more objects may be enumerated on a call that returns this
|
||
reply.
|
||
|
||
STATUS_INVALID_PARAMETER - Invalid parameter.
|
||
|
||
- NULL return pointer for enumeration buffer.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
LSAPR_TRUSTED_ENUM_BUFFER EnumerationBuffer;
|
||
EnumerationBuffer.EntriesRead = 0;
|
||
EnumerationBuffer.Information = NULL;
|
||
|
||
//
|
||
// Verify that caller has provided a return buffer pointer.
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(Buffer)) {
|
||
|
||
return(STATUS_INVALID_PARAMETER);
|
||
}
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Enumerate the Trusted Domains. On successful return,
|
||
// the Enumeration Buffer structure will receive a count
|
||
// of the number of Trusted Domains enumerated this call
|
||
// and a pointer to an array of Trust Information Entries.
|
||
//
|
||
// EnumerationBuffer -> EntriesRead
|
||
// Information -> Trust Info for Domain 0
|
||
// Trust Info for Domain 1
|
||
// ...
|
||
// Trust Info for Domain
|
||
// (EntriesRead - 1)
|
||
//
|
||
//
|
||
|
||
Status = LsarEnumerateTrustedDomains(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
EnumerationContext,
|
||
&EnumerationBuffer,
|
||
PreferedMaximumLength
|
||
);
|
||
|
||
//
|
||
// Return enumeration information or NULL to caller.
|
||
//
|
||
// NOTE: "Information" is allocated by the called client stub
|
||
// as a single block via MIDL_user_allocate, because Information is
|
||
// allocated all-nodes. We can therefore pass back the pointer
|
||
// directly to the client, who will be able to free the memory after
|
||
// use via LsaFreeMemory() [which makes a MIDL_user_free call].
|
||
//
|
||
|
||
*CountReturned = EnumerationBuffer.EntriesRead;
|
||
*Buffer = EnumerationBuffer.Information;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the Trust Information array,
|
||
// free it.
|
||
//
|
||
|
||
if (EnumerationBuffer.Information != NULL) {
|
||
|
||
MIDL_user_free(EnumerationBuffer.Information);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
LsaEnumeratePrivileges(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN OUT PLSA_ENUMERATION_HANDLE EnumerationContext,
|
||
OUT PVOID *Buffer,
|
||
IN ULONG PreferedMaximumLength,
|
||
OUT PULONG CountReturned
|
||
)
|
||
|
||
/*++
|
||
|
||
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 LsaOpenPolicy() call.
|
||
|
||
EnumerationContext - API specific handle to allow multiple calls
|
||
(see Routine Description).
|
||
|
||
Buffer - Receives a pointer to a buffer containing information for
|
||
one or more Privileges. This information is an array of structures
|
||
of type POLICY_PRIVILEGE_DEFINITION.
|
||
|
||
When this information is no longer needed, it must be released by
|
||
passing the returned pointer to LsaFreeMemory().
|
||
|
||
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.
|
||
|
||
Errors from RPC.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
LSAPR_PRIVILEGE_ENUM_BUFFER EnumerationBuffer;
|
||
|
||
EnumerationBuffer.Entries = 0;
|
||
EnumerationBuffer.Privileges = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Enumerate the Privileges. On successful return,
|
||
// the Enumeration Buffer structure will receive a count
|
||
// of the number of Privileges enumerated this call
|
||
// and a pointer to an array of Privilege Definition Entries.
|
||
//
|
||
// EnumerationBuffer -> Entries
|
||
// Privileges -> Privilege Definition 0
|
||
// Privilege Definition 1
|
||
// ...
|
||
// Privilege Definition
|
||
// (Entries - 1)
|
||
//
|
||
|
||
Status = LsarEnumeratePrivileges(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
EnumerationContext,
|
||
&EnumerationBuffer,
|
||
PreferedMaximumLength
|
||
);
|
||
|
||
//
|
||
// Return enumeration information or NULL to caller.
|
||
//
|
||
// NOTE: "Information" is allocated by the called client stub
|
||
// as a single block via MIDL_user_allocate, because Information is
|
||
// allocated all-nodes. We can therefore pass back the pointer
|
||
// directly to the client, who will be able to free the memory after
|
||
// use via LsaFreeMemory() [which makes a MIDL_user_free call].
|
||
//
|
||
|
||
*CountReturned = EnumerationBuffer.Entries;
|
||
*Buffer = EnumerationBuffer.Privileges;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the Account Information array,
|
||
// free it.
|
||
//
|
||
|
||
if (EnumerationBuffer.Privileges != NULL) {
|
||
|
||
MIDL_user_free(EnumerationBuffer.Privileges);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaCreateSecret(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PUNICODE_STRING SecretName,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSA_HANDLE SecretHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaCreateSecretInLsa API creates a named Secret object in the
|
||
Lsa Database. Each Secret Object can have two values assigned,
|
||
called the Current Value and the Old Value. The meaning of these
|
||
values is known to the Secret object creator. The caller must have
|
||
LSA_CREATE_SECRET access to the LsaDatabase object.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenLsa call.
|
||
|
||
SecretName - Pointer to Unicode String specifying the name of the
|
||
secret.
|
||
|
||
DesiredAccess - Specifies the accesses to be granted to the newly
|
||
created and opened secret.
|
||
|
||
SecretHandle - Receives a handle to the newly created and opened
|
||
Secret object. This handle is used on subsequent accesses to
|
||
the object until closed.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_OBJECT_NAME_COLLISION - A Secret object having the given name
|
||
already exists.
|
||
|
||
STATUS_TOO_MANY_SECRETS - The maximum number of Secret objects in the
|
||
system has been reached.
|
||
|
||
STATUS_PRIVILEGE_NOT_HELD - ACCESS_SYSTEM_SECURITY was specified as part
|
||
of DesiredAccess mask, but the caller does not hold SE_SECURITY_PRIVILEGE
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
*SecretHandle = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Verify that the given SecretName has non-null length. Currently
|
||
// midl cannot handle this.
|
||
//
|
||
|
||
if ((SecretName == NULL) ||
|
||
(SecretName->Buffer == NULL) ||
|
||
(SecretName->Length == 0) ||
|
||
(SecretName->Length > SecretName->MaximumLength)) {
|
||
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
} else {
|
||
|
||
Status = LsarCreateSecret(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
(PLSAPR_UNICODE_STRING) SecretName,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE) SecretHandle
|
||
);
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsaLookupNames2(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN ULONG Flags,
|
||
IN ULONG Count,
|
||
IN PUNICODE_STRING Names,
|
||
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
||
OUT PLSA_TRANSLATED_SID2 *Sids
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaLookupNames API attempts to translate names of domains, users,
|
||
groups or aliases to Sids. The caller must have POLICY_LOOKUP_NAMES
|
||
access to the Policy object.
|
||
|
||
Names may be either isolated (e.g. JohnH) or composite names containing
|
||
both the domain name and account name. Composite names must include a
|
||
backslash character separating the domain name from the account name
|
||
(e.g. Acctg\JohnH). An isolated name may be either an account name
|
||
(user, group, or alias) or a domain name.
|
||
|
||
Translation of isolated names introduces the possibility of name
|
||
collisions (since the same name may be used in multiple domains). An
|
||
isolated name will be translated using the following algorithm:
|
||
|
||
If the name is a well-known name (e.g. Local or Interactive), then the
|
||
corresponding well-known Sid is returned.
|
||
|
||
If the name is the Built-in Domain's name, then that domain's Sid
|
||
will be returned.
|
||
|
||
If the name is the Account Domain's name, then that domain's Sid
|
||
will be returned.
|
||
|
||
If the name is the Primary Domain's name, then that domain's Sid will
|
||
be returned.
|
||
|
||
If the name is a user, group, or alias in the Built-in Domain, then the
|
||
Sid of that account is returned.
|
||
|
||
If the name is a user, group, or alias in the Primary Domain, then the
|
||
Sid of that account is returned.
|
||
|
||
Otherwise, the name is not translated.
|
||
|
||
NOTE: Proxy, Machine, and Trust user accounts are not referenced
|
||
for name translation. Only normal user accounts are used for ID
|
||
translation. If translation of other account types is needed, then
|
||
SAM services should be used directly.
|
||
|
||
Arguments:
|
||
|
||
This function is the LSA server RPC worker routine for the
|
||
LsaLookupNamesInLsa API.
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
Flags - LSA_LOOKUP_ISOLATED_AS_LOCAL
|
||
|
||
Count - Specifies the number of names to be translated.
|
||
|
||
Names - Pointer to an array of Count Unicode String structures
|
||
specifying the names to be looked up and mapped to Sids.
|
||
The strings may be names of User, Group or Alias accounts or
|
||
domains.
|
||
|
||
ReferencedDomains - receives a pointer to a structure describing the
|
||
domains used for the translation. The entries in this structure
|
||
are referenced by the structure returned via the Sids parameter.
|
||
Unlike the Sids parameter, which contains an array entry for
|
||
each translated name, this structure will only contain one
|
||
component for each domain utilized in the translation.
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
Sids - Receives a pointer to an array of records describing each
|
||
translated Sid. The nth entry in this array provides a translation
|
||
for (the nth element in the Names parameter.
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_SOME_NOT_MAPPED - Some or all of the names provided could
|
||
not be mapped. This is an informational status only.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
|
||
to complete the call.
|
||
|
||
STATUS_TOO_MANY_NAMES - Too many Names have been specified.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG MappedCount = 0;
|
||
ULONG i;
|
||
|
||
if ( (NULL == Sids)
|
||
|| (NULL == ReferencedDomains ) ) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
//
|
||
// Init the out parameters since LsaICLookupNames expects this
|
||
//
|
||
*ReferencedDomains = NULL;
|
||
*Sids = NULL;
|
||
|
||
Status = LsaICLookupNames(
|
||
PolicyHandle,
|
||
Flags,
|
||
Count,
|
||
Names,
|
||
(PLSA_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
(PLSA_TRANSLATED_SID_EX2*)Sids,
|
||
LsapLookupWksta,
|
||
0,
|
||
&MappedCount,
|
||
NULL
|
||
);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaLookupNames(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN ULONG Count,
|
||
IN PUNICODE_STRING Names,
|
||
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
||
OUT PLSA_TRANSLATED_SID *Sids
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaLookupNames API attempts to translate names of domains, users,
|
||
groups or aliases to Sids. The caller must have POLICY_LOOKUP_NAMES
|
||
access to the Policy object.
|
||
|
||
Names may be either isolated (e.g. JohnH) or composite names containing
|
||
both the domain name and account name. Composite names must include a
|
||
backslash character separating the domain name from the account name
|
||
(e.g. Acctg\JohnH). An isolated name may be either an account name
|
||
(user, group, or alias) or a domain name.
|
||
|
||
Translation of isolated names introduces the possibility of name
|
||
collisions (since the same name may be used in multiple domains). An
|
||
isolated name will be translated using the following algorithm:
|
||
|
||
If the name is a well-known name (e.g. Local or Interactive), then the
|
||
corresponding well-known Sid is returned.
|
||
|
||
If the name is the Built-in Domain's name, then that domain's Sid
|
||
will be returned.
|
||
|
||
If the name is the Account Domain's name, then that domain's Sid
|
||
will be returned.
|
||
|
||
If the name is the Primary Domain's name, then that domain's Sid will
|
||
be returned.
|
||
|
||
If the name is a user, group, or alias in the Built-in Domain, then the
|
||
Sid of that account is returned.
|
||
|
||
If the name is a user, group, or alias in the Primary Domain, then the
|
||
Sid of that account is returned.
|
||
|
||
Otherwise, the name is not translated.
|
||
|
||
NOTE: Proxy, Machine, and Trust user accounts are not referenced
|
||
for name translation. Only normal user accounts are used for ID
|
||
translation. If translation of other account types is needed, then
|
||
SAM services should be used directly.
|
||
|
||
Arguments:
|
||
|
||
This function is the LSA server RPC worker routine for the
|
||
LsaLookupNamesInLsa API.
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
Count - Specifies the number of names to be translated.
|
||
|
||
Names - Pointer to an array of Count Unicode String structures
|
||
specifying the names to be looked up and mapped to Sids.
|
||
The strings may be names of User, Group or Alias accounts or
|
||
domains.
|
||
|
||
ReferencedDomains - receives a pointer to a structure describing the
|
||
domains used for the translation. The entries in this structure
|
||
are referenced by the structure returned via the Sids parameter.
|
||
Unlike the Sids parameter, which contains an array entry for
|
||
each translated name, this structure will only contain one
|
||
component for each domain utilized in the translation.
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
Sids - Receives a pointer to an array of records describing each
|
||
translated Sid. The nth entry in this array provides a translation
|
||
for (the nth element in the Names parameter.
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_SOME_NOT_MAPPED - Some or all of the names provided could
|
||
not be mapped. This is an informational status only.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
|
||
to complete the call.
|
||
|
||
STATUS_TOO_MANY_NAMES - Too many Names have been specified.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG MappedCount = 0;
|
||
PLSA_TRANSLATED_SID_EX2 SidsEx = NULL;
|
||
ULONG i;
|
||
|
||
if ( (NULL == Sids)
|
||
|| (NULL == ReferencedDomains ) ) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
*Sids = NULL;
|
||
*ReferencedDomains = NULL;
|
||
|
||
Status = LsaICLookupNames(
|
||
PolicyHandle,
|
||
0,
|
||
Count,
|
||
Names,
|
||
(PLSA_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
&SidsEx,
|
||
LsapLookupWksta,
|
||
LSAIC_NO_LARGE_SID,
|
||
&MappedCount,
|
||
NULL
|
||
);
|
||
|
||
if ( SidsEx ) {
|
||
|
||
//
|
||
// Some sids were returned -- map the new structure to the old one
|
||
//
|
||
ULONG SizeNeeded = 0;
|
||
PLSA_TRANSLATED_SID TempSids = NULL;
|
||
|
||
SizeNeeded = Count * sizeof( LSA_TRANSLATED_SID );
|
||
TempSids = midl_user_allocate( SizeNeeded );
|
||
if ( TempSids ) {
|
||
|
||
RtlZeroMemory( TempSids, SizeNeeded );
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
TempSids[i].Use = SidsEx[i].Use;
|
||
|
||
if (SidTypeDomain == SidsEx[i].Use) {
|
||
|
||
TempSids[i].RelativeId = LSA_UNKNOWN_ID;
|
||
|
||
} else if (SidsEx[i].Sid) {
|
||
|
||
ULONG SubAuthCount = (ULONG) *RtlSubAuthorityCountSid(SidsEx[i].Sid);
|
||
TempSids[i].RelativeId = *RtlSubAuthoritySid(SidsEx[i].Sid, (SubAuthCount - 1));
|
||
|
||
} else {
|
||
TempSids[i].RelativeId = 0;
|
||
}
|
||
TempSids[i].DomainIndex = SidsEx[i].DomainIndex;
|
||
}
|
||
|
||
*Sids = TempSids;
|
||
|
||
} else {
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
if ( *ReferencedDomains ) {
|
||
|
||
midl_user_free( *ReferencedDomains );
|
||
*ReferencedDomains = NULL;
|
||
}
|
||
}
|
||
|
||
midl_user_free( SidsEx );
|
||
|
||
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
NTSTATUS
|
||
LsaICLookupNames(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN ULONG LookupOptions,
|
||
IN ULONG Count,
|
||
IN PUNICODE_STRING Names,
|
||
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
||
OUT PLSA_TRANSLATED_SID_EX2 *Sids,
|
||
IN LSAP_LOOKUP_LEVEL LookupLevel,
|
||
IN ULONG Flags,
|
||
IN OUT PULONG MappedCount,
|
||
IN OUT PULONG ServerRevision
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the internal client side version of the LsaLookupNames
|
||
API. It is called both from the client side of the Lsa and also
|
||
the server side of the LSA (when calling out to another LSA). The
|
||
function is identical to the LsaLookupNames API except that there is an
|
||
additional parameter, the LookupLevel parameter.
|
||
|
||
The LsaLookupNames API attempts to translate names of domains, users,
|
||
groups or aliases to Sids. The caller must have POLICY_LOOKUP_NAMES
|
||
access to the Policy object.
|
||
|
||
Names may be either isolated (e.g. JohnH) or composite names containing
|
||
both the domain name and account name. Composite names must include a
|
||
backslash character separating the domain name from the account name
|
||
(e.g. Acctg\JohnH). An isolated name may be either an account name
|
||
(user, group, or alias) or a domain name.
|
||
|
||
Translation of isolated names introduces the possibility of name
|
||
collisions (since the same name may be used in multiple domains). An
|
||
isolated name will be translated using the following algorithm:
|
||
|
||
If the name is a well-known name (e.g. Local or Interactive), then the
|
||
corresponding well-known Sid is returned.
|
||
|
||
If the name is the Built-in Domain's name, then that domain's Sid
|
||
will be returned.
|
||
|
||
If the name is the Account Domain's name, then that domain's Sid
|
||
will be returned.
|
||
|
||
If the name is the Primary Domain's name, then that domain's Sid will
|
||
be returned.
|
||
|
||
If the name is a user, group, or alias in the Built-in Domain, then the
|
||
Sid of that account is returned.
|
||
|
||
If the name is a user, group, or alias in the Primary Domain, then the
|
||
Sid of that account is returned.
|
||
|
||
Otherwise, the name is not translated.
|
||
|
||
NOTE: Proxy, Machine, and Trust user accounts are not referenced
|
||
for name translation. Only normal user accounts are used for ID
|
||
translation. If translation of other account types is needed, then
|
||
SAM services should be used directly.
|
||
|
||
Arguments:
|
||
|
||
This function is the LSA server RPC worker routine for the
|
||
LsaLookupNamesInLsa API.
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
LookupOptions - Values to pass through to LsarLookupNames2 and above
|
||
|
||
Count - Specifies the number of names to be translated.
|
||
|
||
Names - Pointer to an array of Count Unicode String structures
|
||
specifying the names to be looked up and mapped to Sids.
|
||
The strings may be names of User, Group or Alias accounts or
|
||
domains.
|
||
|
||
ReferencedDomains - receives a pointer to a structure describing the
|
||
domains used for the translation. The entries in this structure
|
||
are referenced by the structure returned via the Sids parameter.
|
||
Unlike the Sids parameter, which contains an array entry for
|
||
each translated name, this structure will only contain one
|
||
component for each domain utilized in the translation.
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
Sids - Receives a pointer to an array of records describing each
|
||
translated Sid. The nth entry in this array provides a translation
|
||
for (the nth element in the Names parameter.
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
LookupLevel - Specifies the Level of Lookup to be performed on the
|
||
target machine. Values of this field are are follows:
|
||
|
||
LsapLookupWksta - First Level Lookup performed on a workstation
|
||
normally configured for Windows-Nt. The lookup searches the
|
||
Well-Known Sids/Names, and the Built-in Domain and Account Domain
|
||
in the local SAM Database. If not all Sids or Names are
|
||
identified, performs a "handoff" of a Second level Lookup to the
|
||
LSA running on a Controller for the workstation's Primary Domain
|
||
(if any).
|
||
|
||
LsapLookupPDC - Second Level Lookup performed on a Primary Domain
|
||
Controller. The lookup searches the Account Domain of the
|
||
SAM Database on the controller. If not all Sids or Names are
|
||
found, the Trusted Domain List (TDL) is obtained from the
|
||
LSA's Policy Database and Third Level lookups are performed
|
||
via "handoff" to each Trusted Domain in the List.
|
||
|
||
LsapLookupTDL - Third Level Lookup performed on a controller
|
||
for a Trusted Domain. The lookup searches the Account Domain of
|
||
the SAM Database on the controller only.
|
||
|
||
Flags - flags to control the operation of the function. Currently defined:
|
||
|
||
LSAIC_NO_LARGE_SID -- implies only call interfaces that will return
|
||
the old style format SID (no more than
|
||
28 bytes)
|
||
|
||
LSAIC_NT4_TARGET -- target server is known to be NT4
|
||
|
||
LSAIC_WIN2K_TARGET -- target server is known to be Win2k
|
||
|
||
MappedCount - Pointer to location that contains a count of the Names
|
||
mapped so far. On exit, this count will be updated.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_SOME_NOT_MAPPED - Some or all of the names provided could
|
||
not be mapped. This is an informational status only.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
|
||
to complete the call.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
ULONG LsaLookupNameRevision = 3;
|
||
|
||
LSAPR_TRANSLATED_SIDS_EX2 ReturnedSidsEx2 = { 0, NULL };
|
||
|
||
LSAPR_TRANSLATED_SIDS_EX ReturnedSidsEx = { 0, NULL };
|
||
|
||
LSAPR_TRANSLATED_SIDS ReturnedSids = { 0, NULL };
|
||
|
||
ULONG Size, SidCount = 0;
|
||
PBYTE NextSid;
|
||
ULONG i;
|
||
|
||
ULONG StartingRevision = 3;
|
||
|
||
//
|
||
// There are no known clients who pass in a value here
|
||
//
|
||
ASSERT( *ReferencedDomains == NULL );
|
||
ASSERT( *Sids == NULL );
|
||
|
||
//
|
||
// Init to NULL since these are considered to be a IN/OUT parameters
|
||
// for the Lsar Lookup API's
|
||
//
|
||
*ReferencedDomains = NULL;
|
||
*Sids = NULL;
|
||
|
||
//
|
||
// Check that we have not specfied more than the maximum number of names
|
||
// allowed.
|
||
//
|
||
|
||
if (Count > LSAP_DB_TRIAL_MAXIMUM_NAME_COUNT) {
|
||
|
||
return(STATUS_TOO_MANY_NAMES);
|
||
}
|
||
|
||
if ( ServerRevision ) {
|
||
// The latest client's will prefer the latest servers
|
||
*ServerRevision = LSA_LOOKUP_REVISION_LATEST;
|
||
}
|
||
|
||
//
|
||
// Adjust the starting version
|
||
//
|
||
StartingRevision = 3;
|
||
if ((Flags & LSAIC_NO_LARGE_SID)
|
||
|| (Flags & LSAIC_WIN2K_TARGET) ) {
|
||
StartingRevision = 2;
|
||
}
|
||
if (Flags & LSAIC_NT4_TARGET) {
|
||
StartingRevision = 1;
|
||
}
|
||
|
||
switch (StartingRevision) {
|
||
case 3:
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarLookupNames3(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
Count,
|
||
(PLSAPR_UNICODE_STRING) Names,
|
||
(PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
&ReturnedSidsEx2,
|
||
LookupLevel,
|
||
MappedCount,
|
||
LookupOptions,
|
||
LSA_LOOKUP_REVISION_LATEST
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if ( (Status == RPC_NT_UNKNOWN_IF) ||
|
||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE) ) {
|
||
//
|
||
// Continue on to next block;
|
||
//
|
||
NOTHING;
|
||
} else {
|
||
//
|
||
// The interface was supported; leave
|
||
//
|
||
break;
|
||
}
|
||
|
||
case 2:
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarLookupNames2(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
Count,
|
||
(PLSAPR_UNICODE_STRING) Names,
|
||
(PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
&ReturnedSidsEx,
|
||
LookupLevel,
|
||
MappedCount,
|
||
LookupOptions,
|
||
LSA_LOOKUP_REVISION_LATEST
|
||
);
|
||
|
||
LsaLookupNameRevision = 2;
|
||
if ( ReturnedSidsEx.Sids ) {
|
||
// Memory can be allocated on !NT_SUCCESS, namely
|
||
// STATUS_NONE_MAPPED
|
||
SidCount = ReturnedSidsEx.Entries;
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if ( (Status == RPC_NT_UNKNOWN_IF) ||
|
||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE) ) {
|
||
//
|
||
// Continue on to next block;
|
||
//
|
||
NOTHING;
|
||
} else {
|
||
//
|
||
// The interface was supported; leave
|
||
//
|
||
break;
|
||
}
|
||
|
||
case 1:
|
||
|
||
if ( ServerRevision ) {
|
||
*ServerRevision = LSA_LOOKUP_REVISION_1;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarLookupNames(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
Count,
|
||
(PLSAPR_UNICODE_STRING) Names,
|
||
(PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
&ReturnedSids,
|
||
LookupLevel,
|
||
MappedCount
|
||
);
|
||
|
||
LsaLookupNameRevision = 1;
|
||
if ( ReturnedSids.Sids ) {
|
||
// Memory can be allocated on !NT_SUCCESS, namely
|
||
// STATUS_NONE_MAPPED
|
||
SidCount = ReturnedSids.Entries;
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
ASSERT(FALSE && "Programming error -- invalid revision" );
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Prevent against network hacks
|
||
//
|
||
if ( NT_SUCCESS( Status )
|
||
&& (Count > 0)
|
||
&& ( (LsaLookupNameRevision == 1) && ((ReturnedSids.Entries == 0)
|
||
|| (ReturnedSids.Sids == NULL))
|
||
|| (LsaLookupNameRevision == 2) && ((ReturnedSidsEx.Entries == 0)
|
||
|| (ReturnedSidsEx.Sids == NULL))
|
||
|| (LsaLookupNameRevision == 3) && ((ReturnedSidsEx2.Entries == 0)
|
||
|| (ReturnedSidsEx2.Sids == NULL)))) {
|
||
//
|
||
// This is bogus -- an NT server would never return this
|
||
//
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Ok at this point, we have a success -- map the return values
|
||
// to the latest revision: LSA_TRANSLATES_SID_EX2
|
||
//
|
||
|
||
if ( ((LsaLookupNameRevision == 2) && ReturnedSidsEx.Sids != NULL)
|
||
|| ((LsaLookupNameRevision == 1) && ReturnedSids.Sids != NULL) ) {
|
||
|
||
//
|
||
// There should be a ReferencedDomains
|
||
//
|
||
ASSERT( NULL != *ReferencedDomains);
|
||
|
||
//
|
||
// Calculate the size necessary. All SID's from non Sid-Extended domains
|
||
// will be less than 28 bytes. However, we still sanity check the values
|
||
// returned from the untrusted net before copying in (see below).
|
||
//
|
||
|
||
#define MAX_DOWNLEVEL_SID_SIZE 28
|
||
|
||
//
|
||
// Since we are returning a buffer containing all allocations, make sure
|
||
// everything aligned properly
|
||
//
|
||
|
||
ASSERT(MAX_DOWNLEVEL_SID_SIZE ==
|
||
ROUND_UP_COUNT(MAX_DOWNLEVEL_SID_SIZE, ALIGN_DWORD));
|
||
ASSERT(sizeof(LSA_TRANSLATED_SID_EX2) ==
|
||
ROUND_UP_COUNT(sizeof(LSA_TRANSLATED_SID_EX2), ALIGN_DWORD));
|
||
|
||
Size = SidCount * sizeof(LSA_TRANSLATED_SID_EX2);
|
||
Size += SidCount * MAX_DOWNLEVEL_SID_SIZE;
|
||
ReturnedSidsEx2.Sids = MIDL_user_allocate(Size);
|
||
if (NULL == ReturnedSidsEx2.Sids) {
|
||
Status = STATUS_NO_MEMORY;
|
||
goto Cleanup;
|
||
}
|
||
RtlZeroMemory(ReturnedSidsEx2.Sids, Size);
|
||
NextSid = (PBYTE) ReturnedSidsEx2.Sids;
|
||
NextSid += (SidCount * sizeof(LSA_TRANSLATED_SID_EX2));
|
||
|
||
for ( i = 0; i < SidCount; i++ ) {
|
||
|
||
BYTE Buffer[MAX_DOWNLEVEL_SID_SIZE];
|
||
PSID Sid = (PSID)Buffer;
|
||
ULONG SidLength;
|
||
ULONG DomainIndex;
|
||
ULONG Rid;
|
||
SID_NAME_USE SidNameUse;
|
||
ULONG Flags;
|
||
PSID DomainSid;
|
||
|
||
if (1 == LsaLookupNameRevision) {
|
||
|
||
DomainIndex = ReturnedSids.Sids[i].DomainIndex;
|
||
Rid = ReturnedSids.Sids[i].RelativeId;
|
||
SidNameUse = ReturnedSids.Sids[i].Use;
|
||
Flags = 0;
|
||
|
||
} else {
|
||
|
||
ASSERT( 2 == LsaLookupNameRevision );
|
||
|
||
DomainIndex = ReturnedSidsEx.Sids[i].DomainIndex;
|
||
Rid = ReturnedSidsEx.Sids[i].RelativeId;
|
||
SidNameUse = ReturnedSidsEx.Sids[i].Use;
|
||
Flags = ReturnedSidsEx.Sids[i].Flags;
|
||
}
|
||
|
||
//
|
||
// Copy over the simple values
|
||
//
|
||
ReturnedSidsEx2.Sids[i].Use = SidNameUse;
|
||
ReturnedSidsEx2.Sids[i].DomainIndex = DomainIndex;
|
||
ReturnedSidsEx2.Sids[i].Flags = Flags;
|
||
|
||
//
|
||
// Copy over the sid if possible
|
||
//
|
||
// To support possible additions in the future, check for the negative cases.
|
||
// These types will never have any SIDs; all others must have a SID portion.
|
||
//
|
||
if ( (SidNameUse != SidTypeDeletedAccount)
|
||
&& (SidNameUse != SidTypeInvalid)
|
||
&& (SidNameUse != SidTypeUnknown) ) {
|
||
|
||
if (DomainIndex == LSA_UNKNOWN_INDEX) {
|
||
//
|
||
// This is a bogus return value
|
||
//
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// N.B. For domain names, the RID is set to LSA_UNKNOWN_ID and
|
||
// to be compatible with the LsarLookupName3 routine, return
|
||
// a SID in ReturedSidsEx2 structure.
|
||
//
|
||
DomainSid = (*ReferencedDomains)->Domains[DomainIndex].Sid;
|
||
if (RtlLengthSid(DomainSid) > (MAX_DOWNLEVEL_SID_SIZE - sizeof(DWORD))){
|
||
//
|
||
// This is a bogus return value
|
||
//
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
goto Cleanup;
|
||
}
|
||
|
||
RtlCopySid(sizeof(Buffer), Sid, DomainSid);
|
||
if ( Rid != LSA_UNKNOWN_ID ) {
|
||
ULONG RidAuthority;
|
||
RidAuthority= (*(RtlSubAuthorityCountSid(Sid)))++;
|
||
*RtlSubAuthoritySid(Sid,RidAuthority) = Rid;
|
||
}
|
||
|
||
SidLength = RtlLengthSid(Sid);
|
||
RtlCopySid(SidLength, (PSID)NextSid, Sid);
|
||
|
||
ReturnedSidsEx2.Sids[i].Sid = (PSID)NextSid;
|
||
NextSid += RtlLengthSid(Sid);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Either no domain SID, or account is unknown
|
||
//
|
||
ReturnedSidsEx2.Sids[i].Sid = NULL;
|
||
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
*Sids = (PLSA_TRANSLATED_SID_EX2) ReturnedSidsEx2.Sids;
|
||
ReturnedSidsEx2.Sids = NULL;
|
||
|
||
Cleanup:
|
||
|
||
if ( (STATUS_INVALID_NETWORK_RESPONSE == Status)
|
||
|| (STATUS_NO_MEMORY == Status) ) {
|
||
if ( *ReferencedDomains ) {
|
||
MIDL_user_free( *ReferencedDomains );
|
||
*ReferencedDomains = NULL;
|
||
}
|
||
*Sids = NULL;
|
||
}
|
||
|
||
if ( ReturnedSids.Sids ) {
|
||
MIDL_user_free( ReturnedSids.Sids );
|
||
}
|
||
if ( ReturnedSidsEx.Sids ) {
|
||
MIDL_user_free( ReturnedSidsEx.Sids );
|
||
}
|
||
if ( ReturnedSidsEx2.Sids ) {
|
||
MIDL_user_free( ReturnedSidsEx2.Sids );
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaLookupSids(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN ULONG Count,
|
||
IN PSID *Sids,
|
||
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
||
OUT PLSA_TRANSLATED_NAME *Names
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaLookupSids API attempts to find names corresponding to Sids.
|
||
If a name can not be mapped to a Sid, the Sid is converted to character
|
||
form. The caller must have POLICY_LOOKUP_NAMES access to the Policy
|
||
object.
|
||
|
||
WARNING: This routine allocates memory for its output. The caller is
|
||
responsible for freeing this memory after use. See description of the
|
||
Names parameter.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
Count - Specifies the number of Sids to be translated.
|
||
|
||
Sids - Pointer to an array of Count pointers to Sids to be mapped
|
||
to names. The Sids may be well_known SIDs, SIDs of User accounts
|
||
Group Accounts, Alias accounts, or Domains.
|
||
|
||
ReferencedDomains - Receives a pointer to a structure describing the
|
||
domains used for the translation. The entries in this structure
|
||
are referenced by the strutcure returned via the Names parameter.
|
||
Unlike the Names paraemeter, which contains an array entry
|
||
for (each translated name, this strutcure will only contain
|
||
component for each domain utilized in the translation.
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
Names - Receives a pointer to array records describing each translated
|
||
name. The nth entry in this array provides a translation for
|
||
the nth entry in the Sids parameter.
|
||
|
||
All of the returned names will be isolated names or NULL strings
|
||
(domain names are returned as NULL strings). If the caller needs
|
||
composite names, they can be generated by prepending the
|
||
isolated name with the domain name and a backslash. For example,
|
||
if (the name Sally is returned, and it is from the domain Manufact,
|
||
then the composite name would be "Manufact" + "\" + "Sally" or
|
||
"Manufact\Sally".
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
If a Sid is not translatable, then the following will occur:
|
||
|
||
1) If the SID's domain is known, then a reference domain record
|
||
will be generated with the domain's name. In this case, the
|
||
name returned via the Names parameter is a Unicode representation
|
||
of the relative ID of the account, such as "(314)" or the null
|
||
string, if the Sid is that of a domain. So, you might end up
|
||
with a resultant name of "Manufact\(314) for the example with
|
||
Sally above, if Sally's relative id is 314.
|
||
|
||
2) If not even the SID's domain could be located, then a full
|
||
Unicode representation of the SID is generated and no domain
|
||
record is referenced. In this case, the returned string might
|
||
be something like: "(S-1-672194-21-314)".
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_SOME_NOT_MAPPED - Some or all of the names provided could not be
|
||
mapped. This is a warning only.
|
||
|
||
Rest TBS
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG MappedCount = 0;
|
||
PLSA_TRANSLATED_NAME_EX NamesEx = NULL;
|
||
ULONG i;
|
||
|
||
if ( NULL == Names ) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
Status = LsaICLookupSids(
|
||
PolicyHandle,
|
||
Count,
|
||
Sids,
|
||
ReferencedDomains,
|
||
&NamesEx,
|
||
LsapLookupWksta,
|
||
0,
|
||
&MappedCount,
|
||
NULL
|
||
);
|
||
|
||
if ( NamesEx != NULL ) {
|
||
|
||
//
|
||
// Some names were returned -- map the new structure to the old one
|
||
// and keep allocations in the same block of memory so existing clients
|
||
// won't have memory leaks
|
||
//
|
||
ULONG SizeNeeded = 0;
|
||
PBYTE NextBuffer;
|
||
PLSA_TRANSLATED_NAME TempNames = NULL;
|
||
|
||
SizeNeeded = Count * sizeof( LSA_TRANSLATED_NAME );
|
||
for ( i = 0; i < Count; i++ ) {
|
||
SizeNeeded += NamesEx[i].Name.MaximumLength;
|
||
}
|
||
|
||
TempNames = MIDL_user_allocate( SizeNeeded );
|
||
if ( TempNames ) {
|
||
|
||
RtlZeroMemory( TempNames, SizeNeeded );
|
||
NextBuffer = ((PBYTE)TempNames) + (Count * sizeof( LSA_TRANSLATED_NAME ));
|
||
|
||
for ( i = 0; i < Count; i++ ) {
|
||
|
||
TempNames[i].Use = NamesEx[i].Use;
|
||
TempNames[i].DomainIndex = NamesEx[i].DomainIndex;
|
||
|
||
TempNames[i].Name = NamesEx[i].Name;
|
||
RtlCopyMemory( NextBuffer, NamesEx[i].Name.Buffer, NamesEx[i].Name.Length );
|
||
TempNames[i].Name.Buffer = (WCHAR*)NextBuffer;
|
||
|
||
NextBuffer += NamesEx[i].Name.MaximumLength;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// The call succeeded but the extra allocation didn't
|
||
//
|
||
if ( *ReferencedDomains ) {
|
||
MIDL_user_free( *ReferencedDomains );
|
||
*ReferencedDomains = NULL;
|
||
}
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Return the results (or NULL)
|
||
//
|
||
*Names = TempNames;
|
||
|
||
MIDL_user_free( NamesEx );
|
||
|
||
} else {
|
||
|
||
*Names = NULL;
|
||
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsapVerifyReturnedNames(
|
||
IN LSAPR_TRANSLATED_NAMES_EX *ReturnedNames,
|
||
IN ULONG Count,
|
||
IN PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine validates the returned names structure from the server.
|
||
There are some checks that RPC can't make that the client assumes are
|
||
true and will AV otherwise.
|
||
|
||
Arguments:
|
||
|
||
Count -- the number of elements the client asked the server to resolve
|
||
|
||
ReturnedNames -- the structure holding the data returned from the server
|
||
|
||
ReferencedDomains -- the array of domains that ReturnedNames points into
|
||
(also returned from the server)
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
STATUS_INVALID_NETWORK_RESPONSE
|
||
|
||
--*/
|
||
{
|
||
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
ULONG i;
|
||
|
||
if (ReturnedNames->Entries != Count) {
|
||
|
||
//
|
||
// Entries returned should always equal the number of items asked for
|
||
//
|
||
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
goto Finish;
|
||
}
|
||
|
||
if ( Count > 0
|
||
&& (ReturnedNames->Names == NULL)) {
|
||
|
||
//
|
||
// If there are entries, then there must be an array
|
||
//
|
||
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
goto Finish;
|
||
|
||
}
|
||
|
||
for (i = 0; i < Count; i++) {
|
||
|
||
//
|
||
// All resolved names must have a valid domain index
|
||
//
|
||
if ( (ReturnedNames->Names[i].Use != SidTypeInvalid) &&
|
||
(ReturnedNames->Names[i].Use != SidTypeDeletedAccount) &&
|
||
(ReturnedNames->Names[i].Use != SidTypeUnknown) ) {
|
||
|
||
if (NULL == ReferencedDomains) {
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
goto Finish;
|
||
} else if ( (ReturnedNames->Names[i].DomainIndex == LSA_UNKNOWN_INDEX)
|
||
|| (ReturnedNames->Names[i].DomainIndex < 0)
|
||
|| ((ULONG)ReturnedNames->Names[i].DomainIndex >= ReferencedDomains->Entries)) {
|
||
ASSERT(FALSE && "Invalid network response!");
|
||
Status = STATUS_INVALID_NETWORK_RESPONSE;
|
||
goto Finish;
|
||
}
|
||
}
|
||
}
|
||
|
||
Finish:
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsaICLookupSids(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN ULONG Count,
|
||
IN PSID *Sids,
|
||
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
||
IN OUT PLSA_TRANSLATED_NAME_EX *Names,
|
||
IN LSAP_LOOKUP_LEVEL LookupLevel,
|
||
IN ULONG Flags,
|
||
IN OUT PULONG MappedCount,
|
||
OUT ULONG *ServerRevision OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the internal client side version of the LsaLookupSids
|
||
API. It is called both from the client side of the Lsa and also
|
||
the server side of the LSA (when calling out to another LSA). The
|
||
function is identical to the LsaLookupSids API except that there is an
|
||
additional parameter, the LookupLevel parameter.
|
||
|
||
The LsaLookupSids API attempts to find names corresponding to Sids.
|
||
If a name can not be mapped to a Sid, the Sid is converted to character
|
||
form. The caller must have POLICY_LOOKUP_NAMES access to the Policy
|
||
object.
|
||
|
||
WARNING: This routine allocates memory for its output. The caller is
|
||
responsible for freeing this memory after use. See description of the
|
||
Names parameter.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenPolicy call.
|
||
|
||
Count - Specifies the number of Sids to be translated.
|
||
|
||
Sids - Pointer to an array of Count pointers to Sids to be mapped
|
||
to names. The Sids may be well_known SIDs, SIDs of User accounts
|
||
Group Accounts, Alias accounts, or Domains.
|
||
|
||
ReferencedDomains - Receives a pointer to a structure describing the
|
||
domains used for the translation. The entries in this structure
|
||
are referenced by the strutcure returned via the Names parameter.
|
||
Unlike the Names paraemeter, which contains an array entry
|
||
for (each translated name, this strutcure will only contain
|
||
component for each domain utilized in the translation.
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
Names - Receives a pointer to array records describing each translated
|
||
name. The nth entry in this array provides a translation for
|
||
the nth entry in the Sids parameter.
|
||
|
||
All of the retruned names will be isolated names or NULL strings
|
||
(domain names are returned as NULL strings). If the caller needs
|
||
composite names, they can be generated by prepending the
|
||
isolated name with the domain name and a backslash. For example,
|
||
if (the name Sally is returned, and it is from the domain Manufact,
|
||
then the composite name would be "Manufact" + "\" + "Sally" or
|
||
"Manufact\Sally".
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
If a Sid is not translatable, then the following will occur:
|
||
|
||
1) If the SID's domain is known, then a reference domain record
|
||
will be generated with the domain's name. In this case, the
|
||
name returned via the Names parameter is a Unicode representation
|
||
of the relative ID of the account, such as "(314)" or the null
|
||
string, if the Sid is that of a domain. So, you might end up
|
||
with a resultant name of "Manufact\(314) for the example with
|
||
Sally above, if Sally's relative id is 314.
|
||
|
||
2) If not even the SID's domain could be located, then a full
|
||
Unicode representation of the SID is generated and no domain
|
||
record is referenced. In this case, the returned string might
|
||
be something like: "(S-1-672194-21-314)".
|
||
|
||
When this information is no longer needed, it must be released
|
||
by passing the returned pointer to LsaFreeMemory().
|
||
|
||
LookupLevel - Specifies the Level of Lookup to be performed on the
|
||
target machine. Values of this field are are follows:
|
||
|
||
LsapLookupWksta - First Level Lookup performed on a workstation
|
||
normally configured for Windows-Nt. The lookup searches the
|
||
Well-Known Sids, and the Built-in Domain and Account Domain
|
||
in the local SAM Database. If not all Sids are
|
||
identified, performs a "handoff" of a Second level Lookup to the
|
||
LSA running on a Controller for the workstation's Primary Domain
|
||
(if any).
|
||
|
||
LsapLookupPDC - Second Level Lookup performed on a Primary Domain
|
||
Controller. The lookup searches the Account Domain of the
|
||
SAM Database on the controller. If not all Sids are
|
||
found, the Trusted Domain List (TDL) is obtained from the
|
||
LSA's Policy Database and Third Level lookups are performed
|
||
via "handoff" to each Trusted Domain in the List.
|
||
|
||
LsapLookupTDL - Third Level Lookup performed on a controller
|
||
for a Trusted Domain. The lookup searches the Account Domain of
|
||
the SAM Database on the controller only.
|
||
|
||
Flags:
|
||
LSAIC_NT4_TARGET -- target server is known to be NT4
|
||
|
||
LSAIC_WIN2K_TARGET -- target server is known to be Win2k
|
||
|
||
MappedCount - Pointer to location that contains a count of the Sids
|
||
mapped so far. On exit, this count will be updated.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_SOME_NOT_MAPPED - Some or all of the names provided could not be
|
||
mapped. This is a warning only.
|
||
|
||
STATUS_TOO_MANY_SIDS - Too many Sids have been specified.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
BOOLEAN NamesArraySpecified = FALSE;
|
||
|
||
LSAPR_SID_ENUM_BUFFER SidEnumBuffer;
|
||
|
||
LSAPR_TRANSLATED_NAMES_EX ReturnedNames = {0, NULL};
|
||
|
||
LSAPR_TRANSLATED_NAMES DownlevelNames = {0, NULL};
|
||
|
||
ULONG StartingRevision = 2;
|
||
|
||
if ( ServerRevision ) {
|
||
// The latest client's will prefer the latest servers
|
||
*ServerRevision = LSA_CLIENT_LATEST;
|
||
}
|
||
|
||
//
|
||
// Verify that the Count is positive and not too high
|
||
//
|
||
|
||
if (Count == 0) {
|
||
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
if (Count > LSAP_DB_TRIAL_MAXIMUM_SID_COUNT) {
|
||
|
||
return STATUS_TOO_MANY_SIDS;
|
||
}
|
||
|
||
SidEnumBuffer.Entries = Count;
|
||
SidEnumBuffer.SidInfo = (PLSAPR_SID_INFORMATION) Sids;
|
||
|
||
//
|
||
// If this is a Workstation-Level lookup, the Names and
|
||
// ReferencedDomain Lists have not been created. Since these
|
||
// are input parameters in the general case, we need to set them
|
||
// to NULL.
|
||
//
|
||
|
||
if (LookupLevel == LsapLookupWksta) {
|
||
|
||
*ReferencedDomains = NULL;
|
||
*Names = NULL;
|
||
}
|
||
|
||
//
|
||
// There may already be a name translation array in cases where
|
||
// we are called internally (i.e. with lookup level higher than
|
||
// LsapLookupWksta). Initialize the ReturnedNames structure
|
||
// accordingly.
|
||
//
|
||
|
||
ReturnedNames.Entries = 0;
|
||
ReturnedNames.Names = NULL;
|
||
|
||
if (*Names != NULL) {
|
||
|
||
ReturnedNames.Entries = Count;
|
||
ReturnedNames.Names = (PLSAPR_TRANSLATED_NAME_EX) *Names;
|
||
NamesArraySpecified = TRUE;
|
||
}
|
||
|
||
//
|
||
// Adjust the StartingRevision
|
||
//
|
||
StartingRevision = 2;
|
||
if (Flags & LSAIC_NT4_TARGET) {
|
||
StartingRevision = 1;
|
||
}
|
||
|
||
//
|
||
// Lookup Sids on the Server..
|
||
//
|
||
|
||
switch (StartingRevision) {
|
||
case 2:
|
||
|
||
RpcTryExcept {
|
||
Status = LsarLookupSids2(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
&SidEnumBuffer,
|
||
(PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
&ReturnedNames,
|
||
LookupLevel,
|
||
MappedCount,
|
||
0,
|
||
LSA_CLIENT_NT5
|
||
);
|
||
|
||
//
|
||
// Return the array of translation to name info or NULL.
|
||
//
|
||
// NOTE: The array of name translations is allocated by the called
|
||
// client stub as a single block via MIDL_user_allocate, because
|
||
// Information is allocated all-nodes. We can therefore pass back the pointer
|
||
// directly to the client, who will be able to free the memory after
|
||
// use via LsaFreeMemory() [which makes a MIDL_user_free call].
|
||
//
|
||
|
||
*Names = (PLSA_TRANSLATED_NAME_EX) ReturnedNames.Names;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the name translation array,
|
||
// free it.
|
||
//
|
||
|
||
if ((!NamesArraySpecified) && ReturnedNames.Names != NULL) {
|
||
|
||
MIDL_user_free( ReturnedNames.Names );
|
||
ReturnedNames.Names = NULL;
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if ( (Status == RPC_NT_UNKNOWN_IF) ||
|
||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE) ) {
|
||
//
|
||
// Continue on to next block;
|
||
//
|
||
NOTHING;
|
||
} else {
|
||
//
|
||
// The interface was supported; leave
|
||
//
|
||
break;
|
||
}
|
||
|
||
case 1:
|
||
|
||
if ( ServerRevision ) {
|
||
// This is pre nt5
|
||
*ServerRevision = LSA_CLIENT_PRE_NT5;
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Ok, lower down to the previous version
|
||
//
|
||
Status = LsarLookupSids(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
&SidEnumBuffer,
|
||
(PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
&DownlevelNames,
|
||
LookupLevel,
|
||
MappedCount
|
||
);
|
||
|
||
if ( DownlevelNames.Names != NULL ) {
|
||
|
||
ULONG i;
|
||
ULONG SizeNeeded = 0;
|
||
PBYTE NextBuffer;
|
||
|
||
//
|
||
// Package the results into a new structure. Note all memory
|
||
// must be in the same block as LSA_TRANSLATED_NAMES and
|
||
// LSA_TRANSLATED_NAMES_EX are NOT allocate all nodes
|
||
//
|
||
SizeNeeded = DownlevelNames.Entries * sizeof( LSA_TRANSLATED_NAME_EX );
|
||
for ( i = 0; i < DownlevelNames.Entries; i++ ) {
|
||
SizeNeeded += DownlevelNames.Names[i].Name.MaximumLength;
|
||
}
|
||
if ( !NamesArraySpecified ) {
|
||
ReturnedNames.Names = MIDL_user_allocate( SizeNeeded );
|
||
if ( !ReturnedNames.Names ) {
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
_leave;
|
||
}
|
||
RtlZeroMemory( ReturnedNames.Names, SizeNeeded );
|
||
ReturnedNames.Entries = Count;
|
||
}
|
||
NextBuffer = ((PBYTE)ReturnedNames.Names) + (Count * sizeof( LSA_TRANSLATED_NAME_EX ));
|
||
|
||
ReturnedNames.Entries = DownlevelNames.Entries;
|
||
for ( i = 0; i < DownlevelNames.Entries; i++ ) {
|
||
|
||
ReturnedNames.Names[i].Use = DownlevelNames.Names[i].Use;
|
||
ReturnedNames.Names[i].Name = DownlevelNames.Names[i].Name;
|
||
RtlCopyMemory( NextBuffer, DownlevelNames.Names[i].Name.Buffer, DownlevelNames.Names[i].Name.Length );
|
||
ReturnedNames.Names[i].Name.Buffer = (WCHAR*)NextBuffer;
|
||
ReturnedNames.Names[i].DomainIndex = DownlevelNames.Names[i].DomainIndex;
|
||
NextBuffer += DownlevelNames.Names[i].Name.MaximumLength;
|
||
}
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
if ( DownlevelNames.Names ) {
|
||
|
||
MIDL_user_free( DownlevelNames.Names );
|
||
DownlevelNames.Names = NULL;
|
||
}
|
||
|
||
if ((!NamesArraySpecified) && ReturnedNames.Names != NULL) {
|
||
|
||
MIDL_user_free( ReturnedNames.Names );
|
||
ReturnedNames.Names = NULL;
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
break;
|
||
|
||
default:
|
||
ASSERT(FALSE && "Programming error -- wrong revision");
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
|
||
}
|
||
|
||
//
|
||
// Return the array of translation to name info or NULL.
|
||
//
|
||
// NOTE: The array of name translations is allocated by the called
|
||
// client stub as a single block via MIDL_user_allocate, because
|
||
// Information is allocated all-nodes. We can therefore pass back the pointer
|
||
// directly to the client, who will be able to free the memory after
|
||
// use via LsaFreeMemory() [which makes a MIDL_user_free call].
|
||
//
|
||
|
||
*Names = (PLSA_TRANSLATED_NAME_EX) ReturnedNames.Names;
|
||
|
||
//
|
||
// This memory, if allocated is never returned to the caller, so free
|
||
//
|
||
if ( DownlevelNames.Names ) {
|
||
|
||
MIDL_user_free( DownlevelNames.Names );
|
||
|
||
}
|
||
|
||
//
|
||
// Prevent against network hacks
|
||
//
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
Status = LsapVerifyReturnedNames(&ReturnedNames,
|
||
Count,
|
||
*ReferencedDomains);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
if ( (!NamesArraySpecified) && ReturnedNames.Names ) {
|
||
MIDL_user_free( ReturnedNames.Names );
|
||
}
|
||
|
||
if ( *ReferencedDomains ) {
|
||
MIDL_user_free( *ReferencedDomains );
|
||
*ReferencedDomains = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaOpenAccount(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PSID AccountSid,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSA_HANDLE AccountHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaOpenAccount API opens an account object in the Lsa Database of the
|
||
target system. An account must be opened before any operation can be
|
||
performed, including deletion of the account. A handle to the account
|
||
object is returned for use on subsequent API calls that access the
|
||
account. Before calling this API, the caller must have connected to
|
||
the target system's LSA and opened the Policy object by means
|
||
of a preceding call to LsaOpenPolicy.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenLsa call.
|
||
|
||
AccountSid - Pointer to the account's Sid.
|
||
|
||
DesiredAccess - This is an access mask indicating accesses being
|
||
requested for the LSA Subsystem's LSA Database. These access types
|
||
are reconciled with the Discretionary Access Control List of the
|
||
target Account object to determine whether the accesses will be
|
||
granted or denied.
|
||
|
||
AccountHandle - Pointer to location in which a handle to the opened
|
||
account object will be returned if the call succeeds.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_ACCOUNT_DOES_NOT_EXIST - There is no account object in the
|
||
target system's LSA Database having the specified AccountSid.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarOpenAccount(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
(PLSAPR_SID) AccountSid,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE) AccountHandle
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaEnumeratePrivilegesOfAccount(
|
||
IN LSA_HANDLE AccountHandle,
|
||
OUT PPRIVILEGE_SET *Privileges
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaEnumeratePrivilegesOfAccount API obtains information which
|
||
describes the privileges assigned to an account. This call requires
|
||
LSA_ACCOUNT_VIEW access to the account object.
|
||
|
||
Arguments:
|
||
|
||
AccountHandle - The handle to the open account object whose privilege
|
||
information is to be obtained. This handle will have been returned
|
||
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
|
||
|
||
Privileges - Receives a pointer to a buffer containing the Privilege
|
||
Set. The Privilege Set is an array of structures, one for each
|
||
privilege. Each structure contains the LUID of the privilege and
|
||
a mask of the privilege's attributes.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
*Privileges = NULL;
|
||
|
||
Status = LsarEnumeratePrivilegesAccount(
|
||
(LSAPR_HANDLE) AccountHandle,
|
||
(PLSAPR_PRIVILEGE_SET *) Privileges
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaAddPrivilegesToAccount(
|
||
IN LSA_HANDLE AccountHandle,
|
||
IN PPRIVILEGE_SET Privileges
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaAddPrivilegesToAccount API adds privileges and their attributes
|
||
to an account object. If any provided privilege is already assigned
|
||
to the account object, the attributes of that privilege are replaced
|
||
by the newly rpovided values. This API call requires
|
||
LSA_ACCOUNT_ADJUST_PRIVILEGES access to the account object.
|
||
|
||
Arguments:
|
||
|
||
AccountHandle - The handle to the open account object to which
|
||
privileges are to be added. This handle will have been returned
|
||
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
|
||
|
||
Privileges - Points to a set of privileges (and their attributes) to
|
||
be assigned to the account.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarAddPrivilegesToAccount(
|
||
(LSAPR_HANDLE) AccountHandle,
|
||
(PLSAPR_PRIVILEGE_SET) Privileges
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaRemovePrivilegesFromAccount(
|
||
IN LSA_HANDLE AccountHandle,
|
||
IN BOOLEAN AllPrivileges,
|
||
IN OPTIONAL PPRIVILEGE_SET Privileges
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaRemovePrivilegesFromAccount API removes privileges from an
|
||
account object. This API call requires LSA_ACCOUNT_ADJUST_PRIVILEGES
|
||
access to the account object. Note that if all privileges are removed
|
||
from the account object, the account object remains in existence until
|
||
deleted explicitly via a call to the LsaDelete API.
|
||
|
||
Arguments:
|
||
|
||
AccountHandle - The handle to the open account object to which
|
||
privileges are to be removed. This handle will have been returned
|
||
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
|
||
|
||
AllPrivileges - If TRUE, then all privileges are to be removed from
|
||
the account. In this case, the Privileges parameter must be
|
||
specified as NULL. If FALSE, the Privileges parameter specifies
|
||
the privileges to be removed, and must be non NULL.
|
||
|
||
Privileges - Optionally points to a set of privileges (and their
|
||
attributes) to be removed from the account object. The attributes
|
||
fields of this structure are ignored. This parameter must
|
||
be specified as non-NULL if and only if AllPrivileges is set to
|
||
FALSE.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
|
||
|
||
STATUS_INVALID_PARAMETER - The optional Privileges paraemter was
|
||
specified as NULL and AllPrivileges was set to FALSE.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarRemovePrivilegesFromAccount(
|
||
(LSAPR_HANDLE) AccountHandle,
|
||
AllPrivileges,
|
||
(PLSAPR_PRIVILEGE_SET) Privileges
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaGetQuotasForAccount(
|
||
IN LSA_HANDLE AccountHandle,
|
||
OUT PQUOTA_LIMITS QuotaLimits
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaGetQuotasForAccount API obtains the quota limits for pageable and
|
||
non-pageable memory (in Kilobytes) and the maximum execution time (in
|
||
seconds) for any session logged on to the account specified by
|
||
AccountHandle. For each quota and explicit value is returned. This
|
||
call requires LSA_ACCOUNT_VIEW access to the account object.
|
||
|
||
Arguments:
|
||
|
||
AccountHandle - The handle to the open account object whose quotas
|
||
are to be obtained. This handle will have been returned
|
||
from a prior LsaOpenAccount or LsaCreateAccountInLsa API call.
|
||
|
||
QuotaLimits - Pointer to structure in which the system resource
|
||
quota limits applicable to each session logged on to this account
|
||
will be returned. Note that all quotas, including those specified
|
||
as being the system default values, are returned as actual values.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept{
|
||
|
||
Status = LsarGetQuotasForAccount(
|
||
(LSAPR_HANDLE) AccountHandle,
|
||
QuotaLimits
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaSetQuotasForAccount(
|
||
IN LSA_HANDLE AccountHandle,
|
||
IN PQUOTA_LIMITS QuotaLimits
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaSetQuotasForAccount API sets the quota limits for pageable and
|
||
non-pageable memory (in Kilobytes) and the maximum execution time (in
|
||
seconds) for any session logged on to the account specified by
|
||
AccountHandle. For each quota an explicit value or the system default
|
||
may be specified. This call requires LSA_ACCOUNT_ADJUST_QUOTAS
|
||
access to the account object.
|
||
|
||
Arguments:
|
||
|
||
AccountHandle - The handle to the open account object whose quotas
|
||
are to be set. This handle will have been returned from a prior
|
||
LsaOpenAccount or LsaCreateAccountInLsa API call.
|
||
|
||
QuotaLimits - Pointer to structure containing the system resource
|
||
quota limits applicable to each session logged on to this account.
|
||
A zero value specified in any field indicates that the current
|
||
System Default Quota Limit is to be applied.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_INVALID_HANDLE - The specified AccountHandle is not valid.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarSetQuotasForAccount(
|
||
(LSAPR_HANDLE) AccountHandle,
|
||
QuotaLimits
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaGetSystemAccessAccount(
|
||
IN LSA_HANDLE AccountHandle,
|
||
OUT PULONG SystemAccess
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaGetSystemAccessAccount() service returns the System Access
|
||
account flags for an Account object.
|
||
|
||
Arguments:
|
||
|
||
AccountHandle - The handle to the Account object whose system access
|
||
flags are to be read. This handle will have been returned
|
||
from a preceding LsaOpenAccount() or LsaCreateAccount() call
|
||
an must be open for ACCOUNT_VIEW access.
|
||
|
||
SystemAccess - Points to location that will receive the system access
|
||
flags for the account.
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - The call was successful.
|
||
|
||
STATUS_ACCESS_DENIED - The AccountHandle does not specify
|
||
ACCOUNT_VIEW access.
|
||
|
||
STATUS_INVALID_HANDLE - The specified AccountHandle is invalid.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// Avoid RPC stub code raising exception on NULL handle so that
|
||
// we can return the error code STATUS_INVALID_HANDLE in this case
|
||
// too.
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(AccountHandle)) {
|
||
|
||
return(STATUS_INVALID_HANDLE);
|
||
}
|
||
|
||
RpcTryExcept{
|
||
|
||
Status = LsarGetSystemAccessAccount(
|
||
(LSAPR_HANDLE) AccountHandle,
|
||
SystemAccess
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaSetSystemAccessAccount(
|
||
IN LSA_HANDLE AccountHandle,
|
||
IN ULONG SystemAccess
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaSetSystemAccessAccount() service sets the System Access
|
||
account flags for an Account object.
|
||
|
||
Arguments:
|
||
|
||
AccountHandle - The handle to the Account object whose system access
|
||
flags are to be read. This handle will have been returned
|
||
from a preceding LsaOpenAccount() or LsaCreateAccount() call
|
||
an must be open for ACCOUNT_ADJUST_SYSTEM_ACCESS access.
|
||
|
||
SystemAccess - A mask of the system access flags to assign to the
|
||
Account object. The valid access flags include:
|
||
|
||
POLICY_MODE_INTERACTIVE - Account can be accessed interactively
|
||
|
||
POLICY_MODE_NETWORK - Account can be accessed remotely
|
||
|
||
POLICY_MODE_SERVICE - TBS
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_SUCCESS - The call was successful.
|
||
|
||
STATUS_ACCESS_DENIED - The AccountHandle does not specify
|
||
ACCOUNT_VIEW access.
|
||
|
||
STATUS_INVALID_HANDLE - The specified AccountHandle is invalid.
|
||
|
||
STATUS_INVALID_PARAMETER - The specified Access Flags are invalid.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// Avoid RPC stub code raising exception on NULL handle so that
|
||
// we can return the error code STATUS_INVALID_HANDLE in this case
|
||
// too.
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(AccountHandle)) {
|
||
|
||
return(STATUS_INVALID_HANDLE);
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarSetSystemAccessAccount(
|
||
(LSAPR_HANDLE) AccountHandle,
|
||
SystemAccess
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaFreeMemory(
|
||
IN PVOID Buffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Some LSA services that return a potentially large amount of memory,
|
||
such as an enumeration might, allocate the buffer in which the data
|
||
is returned. This function is used to free those buffers when they
|
||
are no longer needed.
|
||
|
||
Parameters:
|
||
|
||
Buffer - Pointer to the buffer to be freed. This buffer must
|
||
have been allocated by a previous LSA service call.
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - normal, successful completion.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
MIDL_user_free( Buffer );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
LsaOpenSecret(
|
||
IN LSA_HANDLE PolicyHandle,
|
||
IN PUNICODE_STRING SecretName,
|
||
IN ACCESS_MASK DesiredAccess,
|
||
OUT PLSA_HANDLE SecretHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaOpenSecret API opens a Secret Object within the LSA Database.
|
||
A handle is returned which must be used to perform operations on the
|
||
secret object.
|
||
|
||
Arguments:
|
||
|
||
PolicyHandle - Handle from an LsaOpenLsa call.
|
||
|
||
SecretName - Pointer to a Unicode String structure that references the
|
||
name of the Secret object to be opened.
|
||
|
||
DesiredAccess - This is an access mask indicating accesses being
|
||
requested for the secret object being opened. These access types
|
||
are reconciled with the Discretionary Access Control List of the
|
||
target secret object to determine whether the accesses will be
|
||
granted or denied.
|
||
|
||
|
||
SecretHandle - Pointer to location that will receive a handle to the
|
||
newly opened Secret object.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_OBJECT_NAME_NOT_FOUND - There is no Secret object in the
|
||
target system's LSA Database having the specified SecretName.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarOpenSecret(
|
||
(LSAPR_HANDLE) PolicyHandle,
|
||
(PLSAPR_UNICODE_STRING) SecretName,
|
||
DesiredAccess,
|
||
(PLSAPR_HANDLE) SecretHandle
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaSetSecret(
|
||
IN LSA_HANDLE SecretHandle,
|
||
IN OPTIONAL PUNICODE_STRING CurrentValue,
|
||
IN OPTIONAL PUNICODE_STRING OldValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaSetSecret API optionally sets one or both values associated with
|
||
a secret. These values are known as the "current value" and "old value"
|
||
of the secret and have a meaning known to the creator of the Secret
|
||
object. The values given are stored in encrypted form.
|
||
|
||
Arguments:
|
||
|
||
SecretHandle - Handle from an LsaOpenSecret or LsaCreateSecret call.
|
||
|
||
CurrentValue - Optional pointer to Unicode String containing the
|
||
value to be assigned as the "current value" of the Secret
|
||
object. The meaning of "current value" is dependent on the
|
||
purpose for which the Secret object is being used.
|
||
|
||
OldValue - Optional pointer to Unicode String containing the
|
||
value to be assigned as the "old value" of the Secret object.
|
||
The meaning of "old value" is dependent on the purpose for
|
||
which the Secret object is being used.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_OBJECT_NAME_NOT_FOUND - There is no Secret object in the
|
||
target system's LSA Database having the specified SecretName.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
PLSAP_CR_CIPHER_VALUE CipherCurrentValue = NULL;
|
||
PLSAP_CR_CIPHER_VALUE CipherOldValue = NULL;
|
||
LSAP_CR_CLEAR_VALUE ClearCurrentValue;
|
||
LSAP_CR_CLEAR_VALUE ClearOldValue;
|
||
PLSAP_CR_CIPHER_KEY SessionKey = NULL;
|
||
|
||
//
|
||
// Convert input from Unicode Structures to Clear Value Structures.
|
||
//
|
||
|
||
LsapCrUnicodeToClearValue( CurrentValue, &ClearCurrentValue );
|
||
LsapCrUnicodeToClearValue( OldValue, &ClearOldValue );
|
||
|
||
//
|
||
// Obtain the Session Key to be used to two-way encrypt the
|
||
// Current Value and/or Old Values.
|
||
//
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsapCrClientGetSessionKey( SecretHandle, &SessionKey );
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetSecretError;
|
||
}
|
||
|
||
//
|
||
// Encrypt the Current Value if specified and not too long.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(CurrentValue)) {
|
||
|
||
Status = LsapCrEncryptValue(
|
||
&ClearCurrentValue,
|
||
SessionKey,
|
||
&CipherCurrentValue
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetSecretError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Encrypt the Old Value if specified and not too long.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(OldValue)) {
|
||
|
||
Status = LsapCrEncryptValue(
|
||
(PLSAP_CR_CLEAR_VALUE) &ClearOldValue,
|
||
SessionKey,
|
||
&CipherOldValue
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetSecretError;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set the Secret Values.
|
||
//
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarSetSecret(
|
||
(LSAPR_HANDLE) SecretHandle,
|
||
(PLSAPR_CR_CIPHER_VALUE) CipherCurrentValue,
|
||
(PLSAPR_CR_CIPHER_VALUE) CipherOldValue
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto SetSecretError;
|
||
}
|
||
|
||
SetSecretFinish:
|
||
|
||
//
|
||
// If necessary, free memory allocated for the Encrypted Current Value.
|
||
//
|
||
|
||
if (CipherCurrentValue != NULL) {
|
||
|
||
LsaFreeMemory(CipherCurrentValue);
|
||
}
|
||
|
||
//
|
||
// If necessary, free memory allocated for the Encrypted Old Value.
|
||
//
|
||
|
||
if (CipherOldValue != NULL) {
|
||
|
||
LsaFreeMemory(CipherOldValue);
|
||
}
|
||
|
||
//
|
||
// If necessary, free memory allocated for the Session Key.
|
||
//
|
||
|
||
if (SessionKey != NULL) {
|
||
|
||
MIDL_user_free(SessionKey);
|
||
}
|
||
|
||
return(Status);
|
||
|
||
SetSecretError:
|
||
|
||
goto SetSecretFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaQuerySecret(
|
||
IN LSA_HANDLE SecretHandle,
|
||
IN OUT OPTIONAL PUNICODE_STRING *CurrentValue,
|
||
OUT PLARGE_INTEGER CurrentValueSetTime,
|
||
IN OUT OPTIONAL PUNICODE_STRING *OldValue,
|
||
OUT PLARGE_INTEGER OldValueSetTime
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The LsaQuerySecret API optionally returns one or both of the values
|
||
assigned to a Secret object. These values are known as the "current value"
|
||
and the "old value", and they have a meaning known to the creator of the
|
||
Secret object. The values are returned in their original unencrypted form.
|
||
The caller must have LSA_QUERY_SECRET access to the Secret object.
|
||
|
||
Arguments:
|
||
|
||
SecretHandle - Handle from an LsaOpenSecret or LsaCreateSecret call.
|
||
|
||
CurrentValue - Optional pointer to location which will receive a pointer
|
||
to a Unicode String containing the value assigned as the "current
|
||
value" of the secret object. If no "current value" is assigned to
|
||
the Secret object, a NULL pointer is returned.
|
||
|
||
CurrentValueSetTime - The date/time at which the current secret value
|
||
was established.
|
||
|
||
OldValue - Optional pointer to location which will receive a pointer
|
||
to a Unicode String containing the value assigned as the "old
|
||
value" of the secret object. If no "current value" is assigned to
|
||
the Secret object, a NULL pointer is returned.
|
||
|
||
OldValueSetTime - The date/time at which the old secret value
|
||
was established.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_OBJECT_NAME_NOT_FOUND - There is no Secret object in the
|
||
target system's LSA Database having the specified SecretName.
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
PLSAP_CR_CIPHER_VALUE CipherCurrentValue = NULL;
|
||
PLSAP_CR_CIPHER_VALUE CipherOldValue = NULL;
|
||
PLSAP_CR_CLEAR_VALUE ClearCurrentValue = NULL;
|
||
PLSAP_CR_CLEAR_VALUE ClearOldValue = NULL;
|
||
PLSAP_CR_CIPHER_KEY SessionKey = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsarQuerySecret(
|
||
(PLSAPR_HANDLE) SecretHandle,
|
||
(PLSAPR_CR_CIPHER_VALUE *) &CipherCurrentValue,
|
||
CurrentValueSetTime,
|
||
(PLSAPR_CR_CIPHER_VALUE *) &CipherOldValue,
|
||
OldValueSetTime
|
||
);
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QuerySecretError;
|
||
}
|
||
|
||
//
|
||
// Obtain the Session Key to be used to two-way encrypt the
|
||
// Current Value and/or Old Values.
|
||
//
|
||
|
||
RpcTryExcept {
|
||
|
||
Status = LsapCrClientGetSessionKey( SecretHandle, &SessionKey );
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QuerySecretError;
|
||
}
|
||
|
||
//
|
||
// If the Current Value is requested and a Current Value exists,
|
||
// decrypt it using the Session key. Otherwise store NULL for return.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(CurrentValue)) {
|
||
|
||
if (CipherCurrentValue != NULL) {
|
||
|
||
Status = LsapCrDecryptValue(
|
||
CipherCurrentValue,
|
||
SessionKey,
|
||
&ClearCurrentValue
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QuerySecretError;
|
||
}
|
||
|
||
//
|
||
// Convert Clear Current Value to Unicode
|
||
//
|
||
|
||
LsapCrClearValueToUnicode(
|
||
ClearCurrentValue,
|
||
(PUNICODE_STRING) ClearCurrentValue
|
||
);
|
||
*CurrentValue = (PUNICODE_STRING) ClearCurrentValue;
|
||
|
||
} else {
|
||
|
||
*CurrentValue = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the Old Value is requested and an Old Value exists,
|
||
// decrypt it using the Session key. Otherwise store NULL for return.
|
||
//
|
||
|
||
if (ARGUMENT_PRESENT(OldValue)) {
|
||
|
||
if (CipherOldValue != NULL) {
|
||
|
||
Status = LsapCrDecryptValue(
|
||
CipherOldValue,
|
||
SessionKey,
|
||
&ClearOldValue
|
||
);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
goto QuerySecretError;
|
||
}
|
||
|
||
//
|
||
// Convert Clear Old Value to Unicode
|
||
//
|
||
|
||
LsapCrClearValueToUnicode(
|
||
ClearOldValue,
|
||
(PUNICODE_STRING) ClearOldValue
|
||
);
|
||
|
||
*OldValue = (PUNICODE_STRING) ClearOldValue;
|
||
|
||
} else {
|
||
|
||
*OldValue = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Getting here means that the operation completed successfully,
|
||
// but Status can be something other than STATUS_SUCCESS.
|
||
// For instance, if both output buffers are NULL, the value of Status
|
||
// at this point will be STATUS_LOCAL_USER_SESSION_KEY.
|
||
// Explicitly clear Status here and avoid confusion for the client.
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
|
||
QuerySecretFinish:
|
||
|
||
//
|
||
// If necessary, free memory allocated for the Session Key.
|
||
//
|
||
|
||
if (SessionKey != NULL) {
|
||
|
||
MIDL_user_free(SessionKey);
|
||
}
|
||
|
||
//
|
||
// If necessary, free memory allocated for the returned Encrypted
|
||
// Current Value.
|
||
//
|
||
|
||
if (CipherCurrentValue != NULL) {
|
||
|
||
LsapCrFreeMemoryValue(CipherCurrentValue);
|
||
}
|
||
|
||
//
|
||
// If necessary, free memory allocated for the returned Encrypted
|
||
// Old Value.
|
||
//
|
||
|
||
if (CipherOldValue != NULL) {
|
||
|
||
LsapCrFreeMemoryValue(CipherOldValue);
|
||
}
|
||
|
||
return(Status);
|
||
|
||
QuerySecretError:
|
||
|
||
//
|
||
// If necessary, free memory allocated for the Clear Current Value
|
||
//
|
||
|
||
if (ClearCurrentValue != NULL) {
|
||
|
||
LsapCrFreeMemoryValue(ClearCurrentValue);
|
||
}
|
||
|
||
//
|
||
// If necessary, free memory allocated for the Clear Old Value
|
||
// Unicode string (buffer and structure).
|
||
//
|
||
|
||
if (ClearOldValue != NULL) {
|
||
|
||
LsapCrFreeMemoryValue(ClearOldValue);
|
||
}
|
||
|
||
|
||
if (ARGUMENT_PRESENT(CurrentValue)) {
|
||
|
||
*CurrentValue = NULL;
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(OldValue)) {
|
||
|
||
*OldValue = NULL;
|
||
}
|
||
|
||
goto QuerySecretFinish;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaGetUserName(
|
||
OUT PUNICODE_STRING * UserName,
|
||
OUT OPTIONAL PUNICODE_STRING * DomainName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the callers user name and domain name
|
||
|
||
|
||
Arguments:
|
||
|
||
UserName - Receives a pointer to the user's name.
|
||
|
||
DomainName - Optionally receives a pointer to the user's domain name.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The privilege was found and returned.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
PLSAPR_UNICODE_STRING UserNameBuffer = NULL;
|
||
PLSAPR_UNICODE_STRING DomainNameBuffer = NULL;
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaGetUserName
|
||
//
|
||
|
||
Status = LsarGetUserName(
|
||
NULL,
|
||
&UserNameBuffer,
|
||
ARGUMENT_PRESENT(DomainName) ? &DomainNameBuffer : NULL
|
||
);
|
||
|
||
(*UserName) = (PUNICODE_STRING)UserNameBuffer;
|
||
|
||
if (ARGUMENT_PRESENT(DomainName)) {
|
||
(*DomainName) = (PUNICODE_STRING)DomainNameBuffer;
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the return buffer, free it.
|
||
//
|
||
|
||
if (UserNameBuffer != NULL) {
|
||
|
||
MIDL_user_free(UserNameBuffer);
|
||
}
|
||
|
||
if (DomainNameBuffer != NULL) {
|
||
|
||
MIDL_user_free(DomainNameBuffer);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
return(Status);
|
||
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
LsaGetRemoteUserName(
|
||
IN PUNICODE_STRING SystemName,
|
||
OUT PUNICODE_STRING * UserName,
|
||
OUT OPTIONAL PUNICODE_STRING * DomainName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns the callers user name and domain name
|
||
|
||
|
||
Arguments:
|
||
|
||
SystemName - Name of system on which to obtain the user name.
|
||
|
||
UserName - Receives a pointer to the user's name.
|
||
|
||
DomainName - Optionally receives a pointer to the user's domain name.
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The privilege was found and returned.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status;
|
||
PLSAPR_UNICODE_STRING UserNameBuffer = NULL;
|
||
PLSAPR_UNICODE_STRING DomainNameBuffer = NULL;
|
||
PLSAPR_SERVER_NAME ServerName = NULL;
|
||
USHORT NullTerminatedServerNameLength;
|
||
|
||
if (ARGUMENT_PRESENT(SystemName) &&
|
||
(SystemName->Buffer != NULL) &&
|
||
(SystemName->Length > 0)) {
|
||
|
||
NullTerminatedServerNameLength = SystemName->Length + (USHORT) sizeof (WCHAR);
|
||
|
||
ServerName = MIDL_user_allocate( NullTerminatedServerNameLength );
|
||
|
||
if (ServerName != NULL) {
|
||
|
||
RtlZeroMemory( ServerName, NullTerminatedServerNameLength );
|
||
|
||
RtlMoveMemory(
|
||
ServerName,
|
||
SystemName->Buffer,
|
||
SystemName->Length
|
||
);
|
||
|
||
} else {
|
||
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
}
|
||
|
||
RpcTryExcept {
|
||
|
||
//
|
||
// Call the Client Stub for LsaGetUserName
|
||
//
|
||
|
||
Status = LsarGetUserName(
|
||
ServerName,
|
||
&UserNameBuffer,
|
||
ARGUMENT_PRESENT(DomainName) ? &DomainNameBuffer : NULL
|
||
);
|
||
|
||
(*UserName) = (PUNICODE_STRING)UserNameBuffer;
|
||
|
||
if (ARGUMENT_PRESENT(DomainName)) {
|
||
(*DomainName) = (PUNICODE_STRING)DomainNameBuffer;
|
||
}
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
//
|
||
// If memory was allocated for the return buffer, free it.
|
||
//
|
||
|
||
if (UserNameBuffer != NULL) {
|
||
|
||
MIDL_user_free(UserNameBuffer);
|
||
}
|
||
|
||
if (DomainNameBuffer != NULL) {
|
||
|
||
MIDL_user_free(DomainNameBuffer);
|
||
}
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
if (ServerName != NULL) {
|
||
MIDL_user_free(ServerName);
|
||
}
|
||
|
||
return(Status);
|
||
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
LsaICLookupNamesWithCreds(
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ServerPrincipalName,
|
||
IN ULONG AuthnLevel,
|
||
IN ULONG AuthnSvc,
|
||
IN RPC_AUTH_IDENTITY_HANDLE AuthIdentity,
|
||
IN ULONG AuthzSvc,
|
||
IN ULONG Count,
|
||
IN PUNICODE_STRING Names,
|
||
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
||
OUT PLSA_TRANSLATED_SID_EX2 *Sids,
|
||
IN LSAP_LOOKUP_LEVEL LookupLevel,
|
||
IN OUT PULONG MappedCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs a lookup with the using an LSA context handle.
|
||
Its purpose is to facilitate lookups over NETLOGON's secure channel.
|
||
|
||
N.B. The routine uses only TCP/IP as the transport.
|
||
|
||
Arguments:
|
||
|
||
ServerName -- the destination server, NULL terminated
|
||
|
||
ServerPrincipalName,
|
||
AuthnLevel,
|
||
AuthSvc,
|
||
AuthIdentity,
|
||
AuthzSvc -- see RpcSetAuthInfo
|
||
|
||
Rset of the parameters -- see LsaLookupNames2
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_SOME_NOT_MAPPED - Some or all of the names provided could
|
||
not be mapped. This is an informational status only.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
|
||
to complete the call.
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
DWORD RpcError = 0;
|
||
RPC_BINDING_HANDLE BindingHandle = NULL;
|
||
WCHAR *StringBinding = NULL;
|
||
LSAPR_TRANSLATED_SIDS_EX2 ReturnedSidsEx2 = { 0, NULL };
|
||
|
||
//
|
||
// Init to NULL since these are considered to be a IN/OUT parameters
|
||
// for the Lsar Lookup API's
|
||
//
|
||
if ((ServerName == NULL)
|
||
|| (ReferencedDomains == NULL)
|
||
|| (Sids == NULL)
|
||
|| (MappedCount == NULL)) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
*ReferencedDomains = NULL;
|
||
*Sids = NULL;
|
||
*MappedCount = 0;
|
||
|
||
if ( 0 == wcsncmp(ServerName, L"\\\\", 2) ) {
|
||
ServerName += 2;
|
||
}
|
||
|
||
RpcError = RpcStringBindingComposeW(
|
||
NULL,
|
||
L"ncacn_ip_tcp",
|
||
ServerName,
|
||
NULL,
|
||
NULL,
|
||
&StringBinding);
|
||
|
||
if (RPC_S_OK == RpcError) {
|
||
|
||
RpcError = RpcBindingFromStringBindingW(
|
||
StringBinding,
|
||
&BindingHandle);
|
||
|
||
if ( RPC_S_OK == RpcError ) {
|
||
|
||
RpcError = RpcEpResolveBinding(BindingHandle,
|
||
lsarpc_ClientIfHandle);
|
||
|
||
if ( RPC_S_OK == RpcError ) {
|
||
|
||
RpcError = RpcBindingSetAuthInfoW(
|
||
BindingHandle,
|
||
ServerPrincipalName,
|
||
AuthnLevel,
|
||
AuthnSvc,
|
||
AuthIdentity,
|
||
AuthzSvc
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (RPC_S_OK != RpcError) {
|
||
//
|
||
// This is fatal
|
||
//
|
||
Status = I_RpcMapWin32Status(RpcError);
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
ReturnedSidsEx2.Entries = 0;
|
||
ReturnedSidsEx2.Sids = NULL;
|
||
|
||
Status = LsarLookupNames4(
|
||
BindingHandle,
|
||
Count,
|
||
(PLSAPR_UNICODE_STRING) Names,
|
||
(PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
&ReturnedSidsEx2,
|
||
LookupLevel,
|
||
MappedCount,
|
||
0, // no flags currently defined
|
||
LSA_LOOKUP_REVISION_LATEST
|
||
);
|
||
|
||
*Sids = (PLSA_TRANSLATED_SID_EX2)ReturnedSidsEx2.Sids;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// Make the handling of this unsupported condition simpler by returning
|
||
// one error code
|
||
//
|
||
if ( (Status == RPC_NT_UNKNOWN_IF) ||
|
||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE) ||
|
||
(Status == EPT_NT_NOT_REGISTERED) ) {
|
||
|
||
Status = STATUS_NOT_SUPPORTED;
|
||
|
||
}
|
||
|
||
if (BindingHandle) {
|
||
RpcBindingFree(&BindingHandle);
|
||
}
|
||
|
||
if (StringBinding){
|
||
RpcStringFreeW(&StringBinding);
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
NTSTATUS
|
||
LsaICLookupSidsWithCreds(
|
||
IN LPWSTR ServerName,
|
||
IN LPWSTR ServerPrincipalName,
|
||
IN ULONG AuthnLevel,
|
||
IN ULONG AuthnSvc,
|
||
IN RPC_AUTH_IDENTITY_HANDLE AuthIdentity,
|
||
IN ULONG AuthzSvc,
|
||
IN ULONG Count,
|
||
IN PSID *Sids,
|
||
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
||
OUT PLSA_TRANSLATED_NAME_EX *Names,
|
||
IN LSAP_LOOKUP_LEVEL LookupLevel,
|
||
IN OUT PULONG MappedCount
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs a lookup with the using an LSA context handle.
|
||
Its purpose is to facilitate lookups over NETLOGON's secure channel.
|
||
|
||
N.B. The routine uses only TCP/IP as the transport.
|
||
|
||
Arguments:
|
||
|
||
ServerName -- the destination server, NULL terminated
|
||
|
||
ServerPrincipalName,
|
||
AuthnLevel,
|
||
AuthSvc,
|
||
AuthIdentity,
|
||
AuthzSvc -- see RpcSetAuthInfo
|
||
|
||
Rset of the parameters -- see LsaLookupSids
|
||
|
||
Return Values:
|
||
|
||
NTSTATUS - Standard Nt Result Code
|
||
|
||
STATUS_ACCESS_DENIED - Caller does not have the appropriate access
|
||
to complete the operation.
|
||
|
||
STATUS_SOME_NOT_MAPPED - Some or all of the names provided could
|
||
not be mapped. This is an informational status only.
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources
|
||
to complete the call.
|
||
--*/
|
||
{
|
||
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
DWORD RpcError = 0;
|
||
RPC_BINDING_HANDLE BindingHandle = NULL;
|
||
WCHAR *StringBinding = NULL;
|
||
LSAPR_TRANSLATED_NAMES_EX ReturnedNames = { 0, NULL };
|
||
LSAPR_SID_ENUM_BUFFER SidEnumBuffer;
|
||
|
||
//
|
||
// Init to NULL since these are considered to be a IN/OUT parameters
|
||
// for the Lsar Lookup API's
|
||
//
|
||
if ((ServerName == NULL)
|
||
|| (ReferencedDomains == NULL)
|
||
|| (Names == NULL)
|
||
|| (MappedCount == NULL)
|
||
|| (Count == 0) ) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
*ReferencedDomains = NULL;
|
||
*Names = NULL;
|
||
*MappedCount = 0;
|
||
|
||
SidEnumBuffer.Entries = Count;
|
||
SidEnumBuffer.SidInfo = (PLSAPR_SID_INFORMATION) Sids;
|
||
|
||
if ( 0 == wcsncmp(ServerName, L"\\\\", 2) ) {
|
||
ServerName += 2;
|
||
}
|
||
|
||
RpcError = RpcStringBindingComposeW(
|
||
NULL,
|
||
L"ncacn_ip_tcp",
|
||
ServerName,
|
||
NULL,
|
||
NULL,
|
||
&StringBinding);
|
||
|
||
if (RPC_S_OK == RpcError) {
|
||
|
||
RpcError = RpcBindingFromStringBindingW(
|
||
StringBinding,
|
||
&BindingHandle);
|
||
|
||
if ( RPC_S_OK == RpcError ) {
|
||
|
||
RpcError = RpcEpResolveBinding(BindingHandle,
|
||
lsarpc_ClientIfHandle);
|
||
|
||
if ( RPC_S_OK == RpcError ) {
|
||
|
||
RpcError = RpcBindingSetAuthInfoW(
|
||
BindingHandle,
|
||
ServerPrincipalName,
|
||
AuthnLevel,
|
||
AuthnSvc,
|
||
AuthIdentity,
|
||
AuthzSvc
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (RPC_S_OK != RpcError) {
|
||
Status = I_RpcMapWin32Status(RpcError);
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
ReturnedNames.Entries = 0;
|
||
ReturnedNames.Names = NULL;
|
||
|
||
//
|
||
// Lookup Sids on the Server..
|
||
//
|
||
|
||
Status = LsarLookupSids3(
|
||
BindingHandle,
|
||
&SidEnumBuffer,
|
||
(PLSAPR_REFERENCED_DOMAIN_LIST *) ReferencedDomains,
|
||
&ReturnedNames,
|
||
LookupLevel,
|
||
MappedCount,
|
||
0,
|
||
LSA_CLIENT_NT5
|
||
);
|
||
|
||
*Names = (PLSA_TRANSLATED_NAME_EX) ReturnedNames.Names;
|
||
|
||
} RpcExcept( I_RpcExceptionFilter( RpcExceptionCode()) ) {
|
||
|
||
Status = LsapApiReturnResult(I_RpcMapWin32Status(RpcExceptionCode()));
|
||
|
||
} RpcEndExcept;
|
||
|
||
|
||
//
|
||
// Prevent against network hacks
|
||
//
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
Status = LsapVerifyReturnedNames(&ReturnedNames,
|
||
Count,
|
||
*ReferencedDomains);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
if (*Names) {
|
||
MIDL_user_free(*Names);
|
||
*Names = NULL;
|
||
}
|
||
|
||
if ( *ReferencedDomains ) {
|
||
MIDL_user_free( *ReferencedDomains );
|
||
*ReferencedDomains = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// Make the handling of this unsupported condition simpler by returning
|
||
// one error code
|
||
//
|
||
if ( (Status == RPC_NT_UNKNOWN_IF) ||
|
||
(Status == RPC_NT_PROCNUM_OUT_OF_RANGE) ||
|
||
(Status == EPT_NT_NOT_REGISTERED) ) {
|
||
|
||
Status = STATUS_NOT_SUPPORTED;
|
||
|
||
}
|
||
|
||
if (BindingHandle) {
|
||
RpcBindingFree(&BindingHandle);
|
||
}
|
||
|
||
if (StringBinding){
|
||
RpcStringFreeW(&StringBinding);
|
||
}
|
||
|
||
return(Status);
|
||
}
|