814 lines
22 KiB
C
814 lines
22 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
display.c
|
||
|
||
Abstract:
|
||
|
||
NetQueryDisplay Information and NetGetDisplayInformationIndex API functions
|
||
|
||
Author:
|
||
|
||
Cliff Van Dyke (cliffv) 14-Dec-1994
|
||
|
||
Environment:
|
||
|
||
User mode only.
|
||
Contains NT-specific code.
|
||
Requires ANSI C extensions: slash-slash comments, long external names.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#undef DOMAIN_ALL_ACCESS // defined in both ntsam.h and ntwinapi.h
|
||
#include <ntsam.h>
|
||
#include <ntlsa.h>
|
||
|
||
#include <windef.h>
|
||
#include <winbase.h>
|
||
#include <lmcons.h>
|
||
|
||
#include <accessp.h>
|
||
#include <align.h>
|
||
// #include <lmapibuf.h>
|
||
#include <lmaccess.h>
|
||
#include <lmerr.h>
|
||
// #include <limits.h>
|
||
#include <netdebug.h>
|
||
#include <netlib.h>
|
||
#include <netlibnt.h>
|
||
#include <rpcutil.h>
|
||
// #include <rxuser.h>
|
||
// #include <secobj.h>
|
||
// #include <stddef.h>
|
||
#include <uasp.h>
|
||
|
||
|
||
VOID
|
||
DisplayRelocationRoutine(
|
||
IN DWORD Level,
|
||
IN OUT PBUFFER_DESCRIPTOR BufferDescriptor,
|
||
IN PTRDIFF_T Offset
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Routine to relocate the pointers from the fixed portion of a NetGroupEnum
|
||
enumeration
|
||
buffer to the string portion of an enumeration buffer. It is called
|
||
as a callback routine from NetpAllocateEnumBuffer when it re-allocates
|
||
such a buffer. NetpAllocateEnumBuffer copied the fixed portion and
|
||
string portion into the new buffer before calling this routine.
|
||
|
||
Arguments:
|
||
|
||
Level - Level of information in the buffer.
|
||
|
||
BufferDescriptor - Description of the new buffer.
|
||
|
||
Offset - Offset to add to each pointer in the fixed portion.
|
||
|
||
Return Value:
|
||
|
||
Returns the error code for the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD EntryCount;
|
||
DWORD EntryNumber;
|
||
DWORD FixedSize;
|
||
IF_DEBUG( UAS_DEBUG_USER ) {
|
||
NetpKdPrint(( "DisplayRelocationRoutine: entering\n" ));
|
||
}
|
||
|
||
//
|
||
// Compute the number of fixed size entries
|
||
//
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
FixedSize = sizeof(NET_DISPLAY_USER);
|
||
break;
|
||
case 2:
|
||
FixedSize = sizeof(NET_DISPLAY_MACHINE);
|
||
break;
|
||
case 3:
|
||
FixedSize = sizeof(NET_DISPLAY_GROUP);
|
||
break;
|
||
|
||
default:
|
||
NetpAssert( FALSE );
|
||
return;
|
||
|
||
}
|
||
|
||
EntryCount =
|
||
((DWORD)(BufferDescriptor->FixedDataEnd - BufferDescriptor->Buffer)) /
|
||
FixedSize;
|
||
|
||
//
|
||
// Loop relocating each field in each fixed size structure
|
||
//
|
||
|
||
for ( EntryNumber=0; EntryNumber<EntryCount; EntryNumber++ ) {
|
||
|
||
LPBYTE TheStruct = BufferDescriptor->Buffer + FixedSize * EntryNumber;
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
RELOCATE_ONE( ((PNET_DISPLAY_USER)TheStruct)->usri1_name, Offset );
|
||
RELOCATE_ONE( ((PNET_DISPLAY_USER)TheStruct)->usri1_comment, Offset );
|
||
RELOCATE_ONE( ((PNET_DISPLAY_USER)TheStruct)->usri1_full_name, Offset );
|
||
break;
|
||
|
||
case 2:
|
||
RELOCATE_ONE( ((PNET_DISPLAY_MACHINE)TheStruct)->usri2_name, Offset );
|
||
RELOCATE_ONE( ((PNET_DISPLAY_MACHINE)TheStruct)->usri2_comment, Offset );
|
||
break;
|
||
|
||
case 3:
|
||
RELOCATE_ONE( ((PNET_DISPLAY_GROUP)TheStruct)->grpi3_name, Offset );
|
||
RELOCATE_ONE( ((PNET_DISPLAY_GROUP)TheStruct)->grpi3_comment, Offset );
|
||
break;
|
||
|
||
default:
|
||
return;
|
||
|
||
}
|
||
}
|
||
|
||
return;
|
||
|
||
} // DisplayRelocationRoutine
|
||
|
||
|
||
|
||
NET_API_STATUS NET_API_FUNCTION
|
||
NetQueryDisplayInformation(
|
||
IN LPCWSTR ServerName OPTIONAL,
|
||
IN DWORD Level,
|
||
IN DWORD Index,
|
||
IN DWORD EntriesRequested,
|
||
IN DWORD PreferredMaximumLength,
|
||
OUT LPDWORD ReturnedEntryCount,
|
||
OUT PVOID *SortedBuffer )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine provides fast return of information commonly
|
||
needed to be displayed in user interfaces.
|
||
|
||
NT User Interface has a requirement for quick enumeration of
|
||
accounts for display in list boxes.
|
||
|
||
This API is remotable. The Server can be any NT workstation or server.
|
||
The server cannot be a Lanman or WFW machine.
|
||
|
||
NT 3.1 workstations and servers do not support Level 3.
|
||
NT 3.1 workstations and servers do not support an infinitely large
|
||
EntriesRequested.
|
||
|
||
|
||
Parameters:
|
||
|
||
|
||
ServerName - A pointer to a string containing the name of the remote
|
||
server on which the function is to execute. A NULL pointer
|
||
or string specifies the local machine.
|
||
|
||
Level - Level of information provided. Must be
|
||
|
||
1 --> Return all Local and Global (normal) user accounts
|
||
2 --> Return all Workstation and Server (BDC) user accounts
|
||
3 --> Return all Global Groups.
|
||
|
||
Index - The index of the first entry to be retrieved. Pass zero on
|
||
the first call. Pass the 'next_index' field of the last entry
|
||
returned on the previous call.
|
||
|
||
EntriesRequested - Specifies an upper limit on the number of entries
|
||
to be returned .
|
||
|
||
PreferedMaximumLength - A recommended upper limit to the number of
|
||
bytes to be returned. The returned information is allocated by
|
||
this routine.
|
||
|
||
ReturnedEntryCount - Number of entries returned by this call. Zero
|
||
indicates there are no entries with an index as large as that
|
||
specified.
|
||
|
||
Entries may be returned for a return status of either NERR_Success
|
||
or ERROR_MORE_DATA.
|
||
|
||
SortedBuffer - Receives a pointer to a buffer containing a sorted
|
||
list of the requested information. This buffer is allocated
|
||
by this routine and contains the following structure:
|
||
|
||
1 --> An array of ReturnedEntryCount elements of type
|
||
NET_DISPLAY_USER. This is followed by the bodies of the
|
||
various strings pointed to from within the
|
||
NET_DISPLAY_USER structures.
|
||
|
||
2 --> An array of ReturnedEntryCount elements of type
|
||
NET_DISPLAY_MACHINE. This is followed by the bodies of the
|
||
various strings pointed to from within the
|
||
NET_DISPLAY_MACHINE structures.
|
||
|
||
3 --> An array of ReturnedEntryCount elements of type
|
||
NET_DISPLAY_GROUP. This is followed by the bodies of the
|
||
various strings pointed to from within the
|
||
NET_DISPLAY_GROUP structures.
|
||
|
||
|
||
Return Values:
|
||
|
||
NERR_Success - normal, successful completion. There are no more entries
|
||
to be returned.
|
||
|
||
ERROR_ACCESS_DENIED - The caller doesn't have access to the requested
|
||
information.
|
||
|
||
ERROR_INVALID_LEVEL - The requested level of information
|
||
is not legitimate for this service.
|
||
|
||
ERROR_MORE_DATA - More entries are available. That is, the last entry
|
||
returned in SortedBuffer is not the last entry available. More
|
||
entries will be returned by calling again with the Index parameter
|
||
set to the 'next_index' field of the last entry in SortedBuffer.
|
||
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
NTSTATUS Status;
|
||
NET_API_STATUS SavedStatus;
|
||
|
||
BUFFER_DESCRIPTOR BufferDescriptor;
|
||
DWORD i;
|
||
|
||
SAM_HANDLE SamServerHandle = NULL;
|
||
SAM_HANDLE DomainHandle = NULL;
|
||
|
||
DOMAIN_DISPLAY_INFORMATION DisplayInformation;
|
||
DWORD FixedSize;
|
||
LPBYTE FixedData;
|
||
|
||
|
||
DWORD SamTotalBytesAvailable;
|
||
DWORD SamTotalBytesReturned;
|
||
DWORD SamReturnedEntryCount;
|
||
PVOID SamSortedBuffer = NULL;
|
||
|
||
DWORD Mode = SAM_SID_COMPATIBILITY_ALL;
|
||
|
||
//
|
||
// Validate Level parameter
|
||
//
|
||
|
||
*ReturnedEntryCount = 0;
|
||
*SortedBuffer = NULL;
|
||
BufferDescriptor.Buffer = NULL;
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
DisplayInformation = DomainDisplayUser;
|
||
FixedSize = sizeof(NET_DISPLAY_USER);
|
||
break;
|
||
case 2:
|
||
DisplayInformation = DomainDisplayMachine;
|
||
FixedSize = sizeof(NET_DISPLAY_MACHINE);
|
||
break;
|
||
case 3:
|
||
DisplayInformation = DomainDisplayGroup;
|
||
FixedSize = sizeof(NET_DISPLAY_GROUP);
|
||
break;
|
||
|
||
default:
|
||
return ERROR_INVALID_LEVEL;
|
||
|
||
}
|
||
|
||
//
|
||
// Connect to the SAM server
|
||
//
|
||
|
||
NetStatus = UaspOpenSam( ServerName,
|
||
FALSE, // Don't try null session
|
||
&SamServerHandle );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
IF_DEBUG( UAS_DEBUG_USER ) {
|
||
NetpKdPrint(( "NetQueryDisplayInformation: Cannot UaspOpenSam %ld\n", NetStatus ));
|
||
}
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Open the Account Domain.
|
||
//
|
||
|
||
NetStatus = UaspOpenDomain( SamServerHandle,
|
||
DOMAIN_LIST_ACCOUNTS,
|
||
TRUE, // Account Domain
|
||
&DomainHandle,
|
||
NULL );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = SamGetCompatibilityMode(DomainHandle,
|
||
&Mode);
|
||
if (NT_SUCCESS(Status)) {
|
||
if ( (Mode == SAM_SID_COMPATIBILITY_STRICT)) {
|
||
//
|
||
// All these info levels return RID's
|
||
//
|
||
Status = STATUS_NOT_SUPPORTED;
|
||
}
|
||
}
|
||
if (!NT_SUCCESS(Status)) {
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Pass the call to SAM
|
||
//
|
||
|
||
Status = SamQueryDisplayInformation (
|
||
DomainHandle,
|
||
DisplayInformation,
|
||
Index,
|
||
EntriesRequested,
|
||
PreferredMaximumLength,
|
||
&SamTotalBytesAvailable,
|
||
&SamTotalBytesReturned,
|
||
&SamReturnedEntryCount,
|
||
&SamSortedBuffer );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
SamSortedBuffer = NULL;
|
||
IF_DEBUG( UAS_DEBUG_USER ) {
|
||
NetpKdPrint((
|
||
"NetQueryDisplayInformation: SamQueryDisplayInformation returned %lX\n",
|
||
Status ));
|
||
}
|
||
|
||
//
|
||
// NT 3.1 systems returned STATUS_NO_MORE_ENTRIES if Index is too large.
|
||
//
|
||
|
||
if ( Status == STATUS_NO_MORE_ENTRIES ) {
|
||
NetStatus = NERR_Success;
|
||
goto Cleanup;
|
||
}
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Remember what status to return on success.
|
||
//
|
||
|
||
if ( Status == STATUS_MORE_ENTRIES ) {
|
||
SavedStatus = ERROR_MORE_DATA;
|
||
} else {
|
||
SavedStatus = NERR_Success;
|
||
}
|
||
|
||
//
|
||
// Loop for each entry
|
||
//
|
||
|
||
for ( i = 0; i < SamReturnedEntryCount; i++ ) {
|
||
|
||
PDOMAIN_DISPLAY_USER DomainDisplayUser;
|
||
PDOMAIN_DISPLAY_MACHINE DomainDisplayMachine;
|
||
PDOMAIN_DISPLAY_GROUP DomainDisplayGroup;
|
||
|
||
DWORD Size;
|
||
|
||
|
||
//
|
||
// Determine the total size of the return information.
|
||
//
|
||
|
||
Size = FixedSize;
|
||
switch (Level) {
|
||
case 1:
|
||
DomainDisplayUser = &((PDOMAIN_DISPLAY_USER)(SamSortedBuffer))[i];
|
||
Size += DomainDisplayUser->LogonName.Length + sizeof(WCHAR) +
|
||
DomainDisplayUser->AdminComment.Length + sizeof(WCHAR) +
|
||
DomainDisplayUser->FullName.Length + sizeof(WCHAR);
|
||
break;
|
||
|
||
case 2:
|
||
DomainDisplayMachine = &((PDOMAIN_DISPLAY_MACHINE)(SamSortedBuffer))[i];
|
||
Size += DomainDisplayMachine->Machine.Length + sizeof(WCHAR) +
|
||
DomainDisplayMachine->Comment.Length + sizeof(WCHAR);
|
||
break;
|
||
case 3:
|
||
DomainDisplayGroup = &((PDOMAIN_DISPLAY_GROUP)(SamSortedBuffer))[i];
|
||
|
||
Size += DomainDisplayGroup->Group.Length + sizeof(WCHAR) +
|
||
DomainDisplayGroup->Comment.Length + sizeof(WCHAR);
|
||
break;
|
||
|
||
default:
|
||
NetStatus = ERROR_INVALID_LEVEL;
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// Ensure there is buffer space for this information.
|
||
//
|
||
|
||
Size = ROUND_UP_COUNT( Size, ALIGN_WCHAR );
|
||
|
||
NetStatus = NetpAllocateEnumBuffer(
|
||
&BufferDescriptor,
|
||
FALSE, // Enumeration
|
||
0xFFFFFFFF, // PrefMaxLen (already limited by SAM)
|
||
Size,
|
||
DisplayRelocationRoutine,
|
||
Level );
|
||
|
||
if (NetStatus != NERR_Success) {
|
||
|
||
//
|
||
// NetpAllocateEnumBuffer returns ERROR_MORE_DATA if this
|
||
// entry doesn't fit into the buffer.
|
||
//
|
||
if ( NetStatus == ERROR_MORE_DATA ) {
|
||
NetStatus = NERR_InternalError;
|
||
}
|
||
|
||
IF_DEBUG( UAS_DEBUG_USER ) {
|
||
NetpKdPrint(( "NetQueryDisplayInformation: NetpAllocateEnumBuffer returns %ld\n",
|
||
NetStatus ));
|
||
}
|
||
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Define macros to make copying zero terminated strings less repetitive.
|
||
//
|
||
|
||
#define COPY_STRING( _dest, _string ) \
|
||
if ( !NetpCopyStringToBuffer( \
|
||
(_string).Buffer, \
|
||
(_string).Length/sizeof(WCHAR), \
|
||
BufferDescriptor.FixedDataEnd, \
|
||
(LPWSTR *)&BufferDescriptor.EndOfVariableData, \
|
||
(_dest) )) { \
|
||
\
|
||
NetStatus = NERR_InternalError; \
|
||
IF_DEBUG( UAS_DEBUG_USER ) { \
|
||
NetpKdPrint(( "NetQueryDisplayInformation: NetpCopyString returns %ld\n", \
|
||
NetStatus )); \
|
||
} \
|
||
goto Cleanup; \
|
||
}
|
||
|
||
|
||
//
|
||
// Place this entry into the return buffer.
|
||
//
|
||
// Fill in the information. The array of fixed entries are
|
||
// placed at the beginning of the allocated buffer. The strings
|
||
// pointed to by these fixed entries are allocated starting at
|
||
// the end of the allocated buffer.
|
||
//
|
||
|
||
FixedData = BufferDescriptor.FixedDataEnd;
|
||
BufferDescriptor.FixedDataEnd += FixedSize;
|
||
|
||
switch (Level) {
|
||
case 1: {
|
||
PNET_DISPLAY_USER NetDisplayUser = (PNET_DISPLAY_USER)FixedData;
|
||
|
||
COPY_STRING( &NetDisplayUser->usri1_name,
|
||
DomainDisplayUser->LogonName );
|
||
|
||
COPY_STRING( &NetDisplayUser->usri1_comment,
|
||
DomainDisplayUser->AdminComment );
|
||
|
||
NetDisplayUser->usri1_flags = NetpAccountControlToFlags(
|
||
DomainDisplayUser->AccountControl,
|
||
NULL );
|
||
|
||
COPY_STRING( &NetDisplayUser->usri1_full_name,
|
||
DomainDisplayUser->FullName );
|
||
|
||
if (Mode == SAM_SID_COMPATIBILITY_ALL) {
|
||
NetDisplayUser->usri1_user_id = DomainDisplayUser->Rid;
|
||
} else {
|
||
NetDisplayUser->usri1_user_id = 0;
|
||
}
|
||
NetDisplayUser->usri1_next_index = DomainDisplayUser->Index;
|
||
|
||
break;
|
||
}
|
||
|
||
case 2: {
|
||
PNET_DISPLAY_MACHINE NetDisplayMachine = (PNET_DISPLAY_MACHINE)FixedData;
|
||
|
||
COPY_STRING( &NetDisplayMachine->usri2_name,
|
||
DomainDisplayMachine->Machine );
|
||
|
||
COPY_STRING( &NetDisplayMachine->usri2_comment,
|
||
DomainDisplayMachine->Comment );
|
||
|
||
NetDisplayMachine->usri2_flags = NetpAccountControlToFlags(
|
||
DomainDisplayMachine->AccountControl,
|
||
NULL );
|
||
|
||
if (Mode == SAM_SID_COMPATIBILITY_ALL) {
|
||
NetDisplayMachine->usri2_user_id = DomainDisplayMachine->Rid;
|
||
} else {
|
||
NetDisplayMachine->usri2_user_id = 0;
|
||
}
|
||
NetDisplayMachine->usri2_next_index = DomainDisplayMachine->Index;
|
||
|
||
break;
|
||
}
|
||
|
||
case 3: {
|
||
PNET_DISPLAY_GROUP NetDisplayGroup = (PNET_DISPLAY_GROUP)FixedData;
|
||
|
||
COPY_STRING( &NetDisplayGroup->grpi3_name,
|
||
DomainDisplayGroup->Group );
|
||
|
||
COPY_STRING( &NetDisplayGroup->grpi3_comment,
|
||
DomainDisplayGroup->Comment );
|
||
|
||
if (Mode == SAM_SID_COMPATIBILITY_ALL) {
|
||
NetDisplayGroup->grpi3_group_id = DomainDisplayGroup->Rid;
|
||
} else {
|
||
NetDisplayGroup->grpi3_group_id = 0;
|
||
}
|
||
NetDisplayGroup->grpi3_attributes = DomainDisplayGroup->Attributes;
|
||
NetDisplayGroup->grpi3_next_index = DomainDisplayGroup->Index;
|
||
|
||
break;
|
||
}
|
||
|
||
default:
|
||
NetStatus = ERROR_INVALID_LEVEL;
|
||
goto Cleanup;
|
||
|
||
}
|
||
|
||
//
|
||
// Indicate that more information was returned.
|
||
//
|
||
|
||
(*ReturnedEntryCount) ++;
|
||
|
||
}
|
||
|
||
NetStatus = SavedStatus;
|
||
|
||
//
|
||
// Clean up.
|
||
//
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// Free up all resources, we reopen them if the caller calls again.
|
||
//
|
||
|
||
if ( DomainHandle != NULL ) {
|
||
UaspCloseDomain( DomainHandle );
|
||
}
|
||
|
||
if ( SamServerHandle != NULL ) {
|
||
(VOID) SamCloseHandle( SamServerHandle );
|
||
}
|
||
|
||
//
|
||
// If we're not returning data to the caller,
|
||
// free the return buffer.
|
||
//
|
||
|
||
if ( NetStatus != NERR_Success && NetStatus != ERROR_MORE_DATA ) {
|
||
if ( BufferDescriptor.Buffer != NULL ) {
|
||
MIDL_user_free( BufferDescriptor.Buffer );
|
||
BufferDescriptor.Buffer = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Free buffer returned from SAM.
|
||
//
|
||
|
||
if ( SamSortedBuffer != NULL ) {
|
||
(VOID) SamFreeMemory( SamSortedBuffer );
|
||
}
|
||
|
||
//
|
||
// Set the output parameters
|
||
//
|
||
|
||
*SortedBuffer = BufferDescriptor.Buffer;
|
||
|
||
IF_DEBUG( UAS_DEBUG_USER ) {
|
||
NetpKdPrint(( "NetQueryDisplayInformation: returning %ld\n", NetStatus ));
|
||
}
|
||
|
||
return NetStatus;
|
||
|
||
}
|
||
|
||
|
||
NET_API_STATUS NET_API_FUNCTION
|
||
NetGetDisplayInformationIndex(
|
||
IN LPCWSTR ServerName OPTIONAL,
|
||
IN DWORD Level,
|
||
IN LPCWSTR Prefix,
|
||
OUT LPDWORD Index )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns the index of the first display information entry
|
||
alphabetically equal to or following Prefix.
|
||
|
||
Parameters:
|
||
|
||
|
||
ServerName - A pointer to a string containing the name of the remote
|
||
server on which the function is to execute. A NULL pointer
|
||
or string specifies the local machine.
|
||
|
||
Level - Level of information queried. Must be
|
||
|
||
1 --> all Local and Global (normal) user accounts
|
||
2 --> all Workstation and Server (BDC) user accounts
|
||
3 --> all Global Groups.
|
||
|
||
|
||
Prefix - Prefix to be searched for
|
||
|
||
Index - The index of the entry found.
|
||
|
||
Return Values:
|
||
|
||
NERR_Success - normal, successful completion. The specified index
|
||
was returned.
|
||
|
||
ERROR_ACCESS_DENIED - The caller doesn't have access to the requested
|
||
information.
|
||
|
||
ERROR_INVALID_LEVEL - The requested level of information
|
||
is not legitimate for this service.
|
||
|
||
--*/
|
||
{
|
||
NET_API_STATUS NetStatus;
|
||
NTSTATUS Status;
|
||
|
||
SAM_HANDLE SamServerHandle = NULL;
|
||
SAM_HANDLE DomainHandle = NULL;
|
||
|
||
DOMAIN_DISPLAY_INFORMATION DisplayInformation;
|
||
UNICODE_STRING PrefixString;
|
||
|
||
DWORD Mode = SAM_SID_COMPATIBILITY_ALL;
|
||
|
||
//
|
||
// Validate Level parameter
|
||
//
|
||
|
||
switch (Level) {
|
||
case 1:
|
||
DisplayInformation = DomainDisplayUser;
|
||
break;
|
||
case 2:
|
||
DisplayInformation = DomainDisplayMachine;
|
||
break;
|
||
case 3:
|
||
DisplayInformation = DomainDisplayGroup;
|
||
break;
|
||
|
||
default:
|
||
return ERROR_INVALID_LEVEL;
|
||
|
||
}
|
||
|
||
//
|
||
// Connect to the SAM server
|
||
//
|
||
|
||
NetStatus = UaspOpenSam( ServerName,
|
||
FALSE, // Don't try null session
|
||
&SamServerHandle );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
IF_DEBUG( UAS_DEBUG_USER ) {
|
||
NetpKdPrint(( "NetGetDisplayInformationIndex: Cannot UaspOpenSam %ld\n", NetStatus ));
|
||
}
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Open the Account Domain.
|
||
//
|
||
|
||
NetStatus = UaspOpenDomain( SamServerHandle,
|
||
DOMAIN_LIST_ACCOUNTS,
|
||
TRUE, // Account Domain
|
||
&DomainHandle,
|
||
NULL );
|
||
|
||
if ( NetStatus != NERR_Success ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = SamGetCompatibilityMode(DomainHandle,
|
||
&Mode);
|
||
if (NT_SUCCESS(Status)) {
|
||
if ( (Mode == SAM_SID_COMPATIBILITY_STRICT)) {
|
||
//
|
||
// All these info levels return RID's
|
||
//
|
||
Status = STATUS_NOT_SUPPORTED;
|
||
}
|
||
}
|
||
if (!NT_SUCCESS(Status)) {
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// Pass the call to SAM
|
||
//
|
||
|
||
RtlInitUnicodeString( &PrefixString, Prefix );
|
||
|
||
Status = SamGetDisplayEnumerationIndex (
|
||
DomainHandle,
|
||
DisplayInformation,
|
||
&PrefixString,
|
||
Index );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
IF_DEBUG( UAS_DEBUG_USER ) {
|
||
NetpKdPrint((
|
||
"NetGetDisplayInformationIndex: SamGetDisplayEnumerationIndex returned %lX\n",
|
||
Status ));
|
||
}
|
||
|
||
NetStatus = NetpNtStatusToApiStatus( Status );
|
||
goto Cleanup;
|
||
}
|
||
|
||
Status = NERR_Success;
|
||
|
||
//
|
||
// Clean up.
|
||
//
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// Free up all resources, we reopen them if the caller calls again.
|
||
//
|
||
|
||
if ( DomainHandle != NULL ) {
|
||
UaspCloseDomain( DomainHandle );
|
||
}
|
||
if ( SamServerHandle != NULL ) {
|
||
(VOID) SamCloseHandle( SamServerHandle );
|
||
}
|
||
|
||
//
|
||
// Set the output parameters
|
||
//
|
||
|
||
IF_DEBUG( UAS_DEBUG_USER ) {
|
||
NetpKdPrint(( "NetGetDisplayInformationIndex: returning %ld\n", NetStatus ));
|
||
}
|
||
|
||
return NetStatus;
|
||
|
||
}
|