WindowsXP-SP1/ds/nw/rdr/ndsread.c
2020-09-30 16:53:49 +02:00

1239 lines
31 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
NdsRead.c
Abstract:
This module implements the NDS read and request routines called
by the redirector natively and the support routines that go with
them.
Author:
Cory West [CoryWest] 23-Feb-1995
--*/
#include "Procs.h"
#define Dbg (DEBUG_TRACE_NDS)
#pragma alloc_text( PAGE, NdsResolveNameKm )
#pragma alloc_text( PAGE, NdsReadStringAttribute )
#pragma alloc_text( PAGE, NdsReadAttributesKm )
#pragma alloc_text( PAGE, NdsCompletionCodetoNtStatus )
#pragma alloc_text( PAGE, FreeNdsContext )
#pragma alloc_text( PAGE, NdsPing )
#pragma alloc_text( PAGE, NdsGetUserName )
#pragma alloc_text( PAGE, NdsGetServerBasicName )
#pragma alloc_text( PAGE, NdsGetServerName )
#pragma alloc_text( PAGE, NdsReadPublicKey )
#pragma alloc_text( PAGE, NdsCheckGroupMembership )
#pragma alloc_text( PAGE, NdsAllocateLockedBuffer )
#pragma alloc_text( PAGE, NdsFreeLockedBuffer )
NTSTATUS
NdsResolveNameKm (
PIRP_CONTEXT pIrpContext,
IN PUNICODE_STRING puObjectName,
OUT DWORD *dwObjectId,
BOOLEAN AllowDsJump,
DWORD dwFlags
)
/*++
Description:
This is a wrapper routine to the browser routine NdsResolveName
for kernel components that need to resolve NDS names.
Arguments:
pIrpContext - must point to the dir server that we should query
puObjectName - what we want to resolve
*dwObjectId - where to report the result
AllowDsJump - if we are referred to another dir server, can we jump?
--*/
{
NTSTATUS Status;
PNWR_NDS_REQUEST_PACKET Rrp;
PNDS_RESPONSE_RESOLVE_NAME Rsp;
LOCKED_BUFFER NdsRequestBuffer;
PSCB Scb, OldScb;
UNICODE_STRING ReferredServer;
BOOL fReleasedCredentials = FALSE;
PLOGON pLogon;
PAGED_CODE();
//
// Note: If you are holding the credential resource coming in, then you
// need to be at the head of the queue.
//
//
// Prepare the request and response buffers.
//
Rrp = ALLOCATE_POOL( PagedPool, NDS_BUFFER_SIZE );
if ( !Rrp ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = NdsAllocateLockedBuffer( &NdsRequestBuffer, NDS_BUFFER_SIZE );
if ( !NT_SUCCESS( Status ) ) {
FREE_POOL( Rrp );
return Status;
}
//
// Set up the request packet.
//
RtlZeroMemory( Rrp, NDS_BUFFER_SIZE );
Rrp->Version = 0;
Rrp->Parameters.ResolveName.ObjectNameLength = puObjectName->Length;
Rrp->Parameters.ResolveName.ResolverFlags = dwFlags;
RtlCopyMemory( Rrp->Parameters.ResolveName.ObjectName,
puObjectName->Buffer,
puObjectName->Length );
//
// Do the resolve.
//
Status = NdsResolveName( pIrpContext, Rrp, NDS_BUFFER_SIZE, &NdsRequestBuffer );
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
Status = NdsCompletionCodetoNtStatus( &NdsRequestBuffer );
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
Rsp = ( PNDS_RESPONSE_RESOLVE_NAME ) NdsRequestBuffer.pRecvBufferVa;
if ( ( Rsp->RemoteEntry == RESOLVE_NAME_REFER_REMOTE ) &&
( AllowDsJump ) ) {
//
// We need to queue this request to another server
// since this server doesn't have any details about
// the object.
//
ReferredServer.Length = (USHORT) Rsp->ServerNameLength;
ReferredServer.MaximumLength = ReferredServer.Length;
ReferredServer.Buffer = Rsp->ReferredServer;
OldScb = pIrpContext->pScb;
ASSERT( OldScb != NULL );
//
// If you hold the credential lock, this is the time to let go of it or
// we might deadlock. We can reclaim it after we are at the head of the
// new SCB queue
//
if (BooleanFlagOn (pIrpContext->Flags, IRP_FLAG_HAS_CREDENTIAL_LOCK)) {
PSCB pScb;
pScb = pIrpContext->pNpScb->pScb;
NwAcquireExclusiveRcb( &NwRcb, TRUE );
pLogon = FindUser( &pScb->UserUid, FALSE );
NwReleaseRcb( &NwRcb );
NwReleaseCredList( pLogon, pIrpContext );
fReleasedCredentials = TRUE;
}
NwDequeueIrpContext( pIrpContext, FALSE );
Status = CreateScb( &Scb,
pIrpContext,
&ReferredServer,
NULL,
NULL,
NULL,
TRUE,
FALSE );
if (fReleasedCredentials == TRUE) {
//
// You have to be at the head of the queue before you
// grab the resource
//
if ( pIrpContext->pNpScb->Requests.Flink != &pIrpContext->NextRequest )
{
NwAppendToQueueAndWait( pIrpContext );
}
NwAcquireExclusiveCredList( pLogon, pIrpContext );
}
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
//
// Since we've jumped servers, dereference the old host
// server. The new one was referenced in CreateScb().
//
NwDereferenceScb( OldScb->pNpScb );
}
*dwObjectId = Rsp->EntryId;
ExitWithCleanup:
NdsFreeLockedBuffer( &NdsRequestBuffer );
FREE_POOL( Rrp );
return Status;
}
NTSTATUS
NdsReadStringAttribute(
PIRP_CONTEXT pIrpContext,
IN DWORD dwObjectId,
IN PUNICODE_STRING puAttributeName,
OUT PUNICODE_STRING puAttributeVal
)
/*++
Description:
This is a wrapper routine to the browser routine NdsReadAttributes
for kernel components that need to read NDS string attributes.
Arguments:
pIrpContext - must point to the dir server that we should query
dwObjectId - oid of the object to query
puAttributeName - attribute that we want
puAttributeVal - value of the attribute
--*/
{
NTSTATUS Status;
PNWR_NDS_REQUEST_PACKET Rrp;
DWORD dwRequestSize, dwAttributeCount;
LOCKED_BUFFER NdsRequest;
PAGED_CODE();
//
// Set up the request and response buffers.
//
dwRequestSize = sizeof( NWR_NDS_REQUEST_PACKET ) + puAttributeName->Length;
Rrp = ( PNWR_NDS_REQUEST_PACKET ) ALLOCATE_POOL( PagedPool, dwRequestSize );
if ( !Rrp ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
if ( !NT_SUCCESS( Status ) ) {
FREE_POOL( Rrp );
return Status;
}
//
// Prepare the request packet.
//
RtlZeroMemory( (BYTE *)Rrp, dwRequestSize );
Rrp->Version = 0;
Rrp->Parameters.ReadAttribute.ObjectId = dwObjectId;
Rrp->Parameters.ReadAttribute.IterHandle = DUMMY_ITER_HANDLE;
Rrp->Parameters.ReadAttribute.AttributeNameLength = puAttributeName->Length;
RtlCopyMemory( Rrp->Parameters.ReadAttribute.AttributeName,
puAttributeName->Buffer,
puAttributeName->Length );
//
// Make the request.
//
Status = NdsReadAttributes( pIrpContext, Rrp, NDS_BUFFER_SIZE, &NdsRequest );
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
//
// Dig out the string attribute and return it.
//
Status = ParseResponse( NULL,
NdsRequest.pRecvBufferVa,
NdsRequest.dwBytesWritten,
"G___D_S_T",
sizeof( DWORD ), // completion code
sizeof( DWORD ), // iter handle
sizeof( DWORD ), // info type
&dwAttributeCount, // attribute count
sizeof( DWORD ), // syntax id
NULL, // attribute name
sizeof( DWORD ), // number of values
puAttributeVal ); // attribute string
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
ExitWithCleanup:
FREE_POOL( Rrp );
NdsFreeLockedBuffer( &NdsRequest );
return Status;
}
NTSTATUS
NdsReadAttributesKm(
PIRP_CONTEXT pIrpContext,
IN DWORD dwObjectId,
IN PUNICODE_STRING puAttributeName,
IN OUT PLOCKED_BUFFER pNdsRequest
)
/*++
Description:
This is a wrapper routine to the browser routine NdsReadAttributes
for kernel components that need to read NDS string attributes and
get back the raw response.
Arguments:
pIrpContext - must point to the dir server that we should query
dwObjectId - oid of the object to query
puAttributeName - attribute that we want
puAttributeVal - value of the attribute
--*/
{
NTSTATUS Status;
PNWR_NDS_REQUEST_PACKET Rrp;
DWORD dwRequestSize;
PAGED_CODE();
//
// Set up the request.
//
dwRequestSize = sizeof( NWR_NDS_REQUEST_PACKET ) + puAttributeName->Length;
Rrp = ( PNWR_NDS_REQUEST_PACKET ) ALLOCATE_POOL( PagedPool, dwRequestSize );
if ( !Rrp ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory( (BYTE *)Rrp, dwRequestSize );
Rrp->Version = 0;
Rrp->Parameters.ReadAttribute.ObjectId = dwObjectId;
Rrp->Parameters.ReadAttribute.IterHandle = DUMMY_ITER_HANDLE;
Rrp->Parameters.ReadAttribute.AttributeNameLength = puAttributeName->Length;
RtlCopyMemory( Rrp->Parameters.ReadAttribute.AttributeName,
puAttributeName->Buffer,
puAttributeName->Length );
Status = NdsReadAttributes( pIrpContext, Rrp, NDS_BUFFER_SIZE, pNdsRequest );
FREE_POOL( Rrp );
return Status;
}
//
// Frosting and other helper wrapper functions.
//
NTSTATUS
NdsCompletionCodetoNtStatus(
IN PLOCKED_BUFFER pLockedBuffer
)
/*+++
Description:
Translates the completion code of an NDS transaction into
an NTSTATUS error code.
Arguments:
pLockedBuffer - describes the locked reply buffer that contains
the response.
---*/
{
NTSTATUS Status;
PAGED_CODE();
//
// Try to get the completion code from the user's buffer.
//
try {
Status = *((DWORD *)pLockedBuffer->pRecvBufferVa);
} except ( EXCEPTION_EXECUTE_HANDLER ) {
return STATUS_UNSUCCESSFUL;
}
//
// Decode it.
//
if ( Status != STATUS_SUCCESS ) {
DebugTrace( 0, Dbg, "NDS Error Code: %08lx\n", Status );
switch ( Status ) {
case -601: // No such entry.
case -602: // No such value.
case -603: // No such attribute.
case -607: // Illegal attribute.
case -610: // Illegal ds name.
Status = STATUS_BAD_NETWORK_PATH;
break;
//
// These may only come on a VERIFY_PASSWORD verb, which
// we do not support. I'm not sure, though.
//
case -216: // Password too short.
case -215: // Duplicate password.
Status = STATUS_PASSWORD_RESTRICTION;
break;
case -222: // Expired password (and no grace logins left).
Status = STATUS_PASSWORD_EXPIRED;
break;
case -223: // Expired password; this is a successful grace login.
Status = NWRDR_PASSWORD_HAS_EXPIRED;
break;
case -639: // Incomplete authentication.
case -672: // No access.
case -677: // Invalid identity.
case -669: // Wrong password.
Status = STATUS_WRONG_PASSWORD;
break;
case -197: // Intruder lockout active.
case -220: // Account expired or disabled.
Status = STATUS_ACCOUNT_DISABLED;
break;
case -218: // Login time restrictions.
Status = STATUS_LOGIN_TIME_RESTRICTION;
break;
case -217: // Maximum logins exceeded.
Status = STATUS_CONNECTION_COUNT_LIMIT;
break;
case -630: // We get this back for bogus resolve
// name calls. Glenn prefers this error.
Status = STATUS_OBJECT_NAME_NOT_FOUND;
break;
default:
Status = STATUS_UNSUCCESSFUL;
}
}
return Status;
}
VOID
FreeNdsContext(
IN PNDS_SECURITY_CONTEXT pNdsSecContext
)
/*++
Routine Description:
Free the referenced NDS context.
--*/
{
PAGED_CODE();
//
// Make sure this is a valid thing to be mucking with.
//
if ( !pNdsSecContext ||
pNdsSecContext->ntc != NW_NTC_NDS_CREDENTIAL ) {
DebugTrace( 0, Dbg, "FreeNdsContext didn't get an NDS context.\n", 0 );
return;
}
if ( pNdsSecContext->Credential ) {
FREE_POOL( pNdsSecContext->Credential );
}
if ( pNdsSecContext->Signature ) {
FREE_POOL( pNdsSecContext->Signature );
}
if ( pNdsSecContext->PublicNdsKey ) {
FREE_POOL( pNdsSecContext->PublicNdsKey );
}
if ( pNdsSecContext->Password.Buffer ) {
FREE_POOL( pNdsSecContext->Password.Buffer );
}
DebugTrace( 0, Dbg, "Freeing NDS security context at 0x%08lx\n", pNdsSecContext );
FREE_POOL( pNdsSecContext );
return;
}
VOID
NdsPing(
IN PIRP_CONTEXT pIrpContext,
IN PSCB pScb
)
/*++
Routine Description:
Examine the server for NDS support and record the NDS tree
name in the SCB for later reference.
Routine Arguments:
pIrpContext - A pointer to the IRP context for this transaction.
pScb - The SCB for the server.
Return Value:
NTSTATUS - Status of the operation.
--*/
{
NTSTATUS Status;
OEM_STRING OemTreeName;
BYTE OemBuffer[NDS_TREE_NAME_LEN];
UNICODE_STRING TreeName;
WCHAR WBuffer[NDS_TREE_NAME_LEN];
UNICODE_STRING CredentialName;
PAGED_CODE();
pScb->NdsTreeName.Length = 0;
OemTreeName.Length = NDS_TREE_NAME_LEN;
OemTreeName.MaximumLength = NDS_TREE_NAME_LEN;
OemTreeName.Buffer = OemBuffer;
Status = ExchangeWithWait( pIrpContext,
SynchronousResponseCallback,
"N",
NDS_REQUEST, // NDS Function 104
NDS_PING ); // NDS Subfunction 1
if ( !NT_SUCCESS( Status ) ) {
return;
}
//
// Pull out the padded NDS name
//
Status = ParseResponse( pIrpContext,
pIrpContext->rsp,
pIrpContext->ResponseLength,
"N_r",
2 * sizeof( DWORD ),
OemBuffer,
NDS_TREE_NAME_LEN );
if ( !NT_SUCCESS( Status ) ) {
return;
}
//
// Strip off the padding and convert to unicode.
//
while ( OemTreeName.Length > 0 &&
OemBuffer[OemTreeName.Length - 1] == '_' ) {
OemTreeName.Length--;
}
//
// Copy or munge the tree name, depending on the create type.
//
if ( pIrpContext->Specific.Create.fExCredentialCreate ) {
TreeName.Length = 0;
TreeName.MaximumLength = sizeof( WBuffer );
TreeName.Buffer = WBuffer;
Status = RtlOemStringToUnicodeString( &TreeName,
&OemTreeName,
FALSE );
if ( !NT_SUCCESS( Status ) ) {
pScb->NdsTreeName.Length = 0;
return;
}
Status = BuildExCredentialServerName( &TreeName,
pIrpContext->Specific.Create.puCredentialName,
&CredentialName );
if ( !NT_SUCCESS( Status ) ) {
return;
}
RtlCopyUnicodeString( &pScb->NdsTreeName, &CredentialName );
FREE_POOL( CredentialName.Buffer );
} else {
Status = RtlOemStringToUnicodeString( &pScb->NdsTreeName,
&OemTreeName,
FALSE );
if ( !NT_SUCCESS( Status ) ) {
pScb->NdsTreeName.Length = 0;
return;
}
}
DebugTrace( 0, Dbg, "Nds Ping: Tree is ""%wZ""\n", &pScb->NdsTreeName);
return;
}
NTSTATUS
NdsGetUserName(
IN PIRP_CONTEXT pIrpContext,
IN DWORD dwUserOid,
OUT PUNICODE_STRING puUserName
)
/*++
Description:
Get the fully distinguished name of the user referred to
by the provided oid.
--*/
{
NTSTATUS Status;
LOCKED_BUFFER NdsRequest;
PAGED_CODE();
//
// Allocate buffer space.
//
Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
if ( !NT_SUCCESS( Status ) ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Make the request.
//
Status = FragExWithWait( pIrpContext,
NDSV_READ_ENTRY_INFO,
&NdsRequest,
"DD",
0,
dwUserOid );
if ( !NT_SUCCESS(Status) ) {
goto ExitWithCleanup;
}
Status = NdsCompletionCodetoNtStatus( &NdsRequest );
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
Status = ParseResponse( NULL,
NdsRequest.pRecvBufferVa,
NdsRequest.dwBytesWritten,
"G_St",
sizeof( NDS_RESPONSE_GET_OBJECT_INFO ),
NULL,
puUserName );
//
// We either got it or we didn't.
//
ExitWithCleanup:
NdsFreeLockedBuffer( &NdsRequest );
return Status;
}
NTSTATUS
NdsGetServerBasicName(
IN PUNICODE_STRING pServerX500Name,
IN OUT PUNICODE_STRING pServerName
) {
//
// Dig out the first component of the server's X.500 name.
// We count on the X500 prefix for the server object being "CN=",
// which might be unwise.
//
USHORT usPrefixSize, usSrv;
PAGED_CODE();
usPrefixSize = sizeof( "CN=" ) - sizeof( "" );
usSrv = 0;
if ( ( pServerX500Name->Buffer[0] != L'C' ) ||
( pServerX500Name->Buffer[1] != L'N' ) ||
( pServerX500Name->Buffer[2] != L'=' ) ) {
DebugTrace( 0, Dbg, "NdsGetServerBasicName: Bad prefix.\n", 0 );
return STATUS_INVALID_PARAMETER;
}
if ( pServerX500Name->Length <= usPrefixSize ) {
DebugTrace( 0, Dbg, "NdsGetServerBasicName: Bad string length.\n", 0 );
return STATUS_INVALID_PARAMETER;
}
pServerName->Buffer = pServerX500Name->Buffer + usPrefixSize;
pServerName->Length = 0;
while ( ( usSrv < MAX_SERVER_NAME_LENGTH ) &&
( pServerName->Buffer[usSrv++] != L'.' ) ) {
pServerName->Length += sizeof( WCHAR );
}
if ( usSrv == MAX_SERVER_NAME_LENGTH ) {
DebugTrace( 0, Dbg, "NdsGetServerBasicName: Bad server name response.\n", 0 );
return STATUS_BAD_NETWORK_PATH;
}
pServerName->MaximumLength = pServerName->Length;
return STATUS_SUCCESS;
}
NTSTATUS
NdsGetServerName(
IN PIRP_CONTEXT pIrpContext,
OUT PUNICODE_STRING puServerName
)
/*++
Description:
Get the fully distinguished name of the server that we
are connected to.
--*/
{
NTSTATUS Status;
LOCKED_BUFFER NdsRequest;
PAGED_CODE();
//
// Make the request.
//
Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
if ( !NT_SUCCESS( Status ) ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = FragExWithWait( pIrpContext,
NDSV_GET_SERVER_ADDRESS,
&NdsRequest,
NULL );
if ( !NT_SUCCESS(Status) ) {
goto ExitWithCleanup;
}
Status = NdsCompletionCodetoNtStatus( &NdsRequest );
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
//
// Get the server name from the response.
//
Status = ParseResponse( NULL,
NdsRequest.pRecvBufferVa,
NdsRequest.dwBytesWritten,
"G_T",
sizeof( DWORD ),
puServerName );
if ( !NT_SUCCESS(Status) ) {
goto ExitWithCleanup;
}
ExitWithCleanup:
NdsFreeLockedBuffer( &NdsRequest );
return Status;
}
NTSTATUS
NdsReadPublicKey(
IN PIRP_CONTEXT pIrpContext,
IN DWORD dwEntryId,
OUT BYTE *pPubKeyVal,
IN OUT DWORD *pPubKeyLen
)
/*++
Routine Description:
Read the public key referenced by the given entry id.
Routine Arguments:
pIrpContext - The IRP context for this connection.
dwEntryId - The entry id of the key.
pPubKeyVal - The destination buffer for the public key.
pPubKeyLen - The length of the public key destination buffer.
Return Value:
The length of the key.
--*/
{
NTSTATUS Status;
LOCKED_BUFFER NdsRequest;
PNWR_NDS_REQUEST_PACKET Rrp;
DWORD dwAttrNameLen, dwAttrLen, dwRcvLen, dwNumEntries;
BYTE *pRcv;
PAGED_CODE();
//
// Allocate and zero send and receive space.
//
Rrp = ALLOCATE_POOL( PagedPool, NDS_BUFFER_SIZE );
if ( !Rrp ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
if ( !NT_SUCCESS( Status ) ) {
FREE_POOL( Rrp );
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Fill in and prepare the request buffer.
//
RtlZeroMemory( Rrp, NDS_BUFFER_SIZE );
Rrp->Version = 0;
Rrp->Parameters.ReadAttribute.ObjectId = dwEntryId;
Rrp->Parameters.ReadAttribute.IterHandle = DUMMY_ITER_HANDLE;
Rrp->Parameters.ReadAttribute.AttributeNameLength =
sizeof( PUBLIC_KEY_ATTRIBUTE ) - sizeof( WCHAR );
RtlCopyMemory( Rrp->Parameters.ReadAttribute.AttributeName,
PUBLIC_KEY_ATTRIBUTE,
sizeof( PUBLIC_KEY_ATTRIBUTE ) - sizeof( WCHAR ) );
//
// Do the exchange.
//
Status = NdsReadAttributes( pIrpContext,
Rrp,
NDS_BUFFER_SIZE,
&NdsRequest );
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
//
// Skip over the attribute header and name.
//
Status = ParseResponse( NULL,
NdsRequest.pRecvBufferVa,
NdsRequest.dwBytesWritten,
"G_D",
5 * sizeof( DWORD ),
&dwAttrNameLen );
if ( !NT_SUCCESS( Status ) ) {
Status = STATUS_UNSUCCESSFUL;
goto ExitWithCleanup;
}
//
// Skip over the part we've parsed and pull out the attribute.
//
pRcv = (PBYTE)NdsRequest.pRecvBufferVa +
( 6 * sizeof( DWORD ) ) +
ROUNDUP4(dwAttrNameLen);
dwRcvLen = NdsRequest.dwBytesWritten -
( 6 * sizeof( DWORD ) ) +
ROUNDUP4(dwAttrNameLen);
Status = ParseResponse( NULL,
pRcv,
dwRcvLen,
"GDD",
&dwNumEntries,
&dwAttrLen );
if ( !NT_SUCCESS( Status ) ||
dwNumEntries != 1 ) {
Status = STATUS_UNSUCCESSFUL;
goto ExitWithCleanup;
}
DebugTrace( 0, Dbg, "Public Key Length: %d\n", dwAttrLen );
pRcv += ( 2 * sizeof( DWORD ) );
if ( dwAttrLen <= *pPubKeyLen ) {
RtlCopyMemory( pPubKeyVal, pRcv, dwAttrLen );
*pPubKeyLen = dwAttrLen;
Status = STATUS_SUCCESS;
} else {
DebugTrace( 0, Dbg, "Public key buffer is too small.\n", 0 );
Status = STATUS_BUFFER_TOO_SMALL;
}
ExitWithCleanup:
NdsFreeLockedBuffer( &NdsRequest );
FREE_POOL( Rrp );
return Status;
}
NTSTATUS
NdsCheckGroupMembership(
PIRP_CONTEXT pIrpContext,
DWORD dwUserOid,
PUNICODE_STRING puGroupName
) {
NTSTATUS Status;
UNICODE_STRING GroupListAttribute;
LOCKED_BUFFER NdsRequest;
PNDS_RESPONSE_READ_ATTRIBUTE pAttributeResponse;
PNDS_ATTRIBUTE pAttribute;
PBYTE pAttribData;
DWORD dwAttribLength, dwCurrentLength;
DWORD dwNumAttributes, dwCurrentAttribute;
UNICODE_STRING Group;
USHORT GroupLength;
PAGED_CODE();
RtlInitUnicodeString( &GroupListAttribute, GROUPS_ATTRIBUTE );
Status = NdsAllocateLockedBuffer( &NdsRequest, NDS_BUFFER_SIZE );
if ( !NT_SUCCESS( Status ) ) {
return STATUS_INSUFFICIENT_RESOURCES;
}
Status = NdsReadAttributesKm( pIrpContext,
dwUserOid,
&GroupListAttribute,
&NdsRequest );
if ( !NT_SUCCESS( Status ) ) {
goto ExitWithCleanup;
}
pAttributeResponse = ( PNDS_RESPONSE_READ_ATTRIBUTE ) NdsRequest.pRecvBufferVa;
ASSERT( pAttributeResponse->NumAttributes > 0 );
//
// Skip over the response header and walk down the attribute
// until we get to the data. This is a little clunky.
//
pAttribute = ( PNDS_ATTRIBUTE ) ( pAttributeResponse + 1 );
dwCurrentLength = sizeof( NDS_RESPONSE_READ_ATTRIBUTE );
dwAttribLength = ROUNDUP4( pAttribute->AttribNameLength );
dwAttribLength += ( 2 * sizeof( DWORD ) );
//
// Make sure we don't walk past the end of the buffer because
// of a bad packet from the server.
//
if ( ( dwCurrentLength + dwAttribLength ) > NDS_BUFFER_SIZE ) {
return STATUS_UNSUCCESSFUL;
}
pAttribData = ( ( BYTE * )pAttribute ) + dwAttribLength;
dwCurrentLength += dwAttribLength;
//
// This is DWORD aligned for four byte DWORDs.
//
if ( ( NDS_BUFFER_SIZE - dwCurrentLength ) < sizeof( DWORD ) ) {
return STATUS_UNSUCCESSFUL;
}
dwNumAttributes = * ( ( DWORD * ) pAttribData );
if ( dwNumAttributes == 0 ) {
Status = STATUS_UNSUCCESSFUL;
goto ExitWithCleanup;
}
//
// Each attribute is an NDS string DWORD aligned.
//
Status = STATUS_UNSUCCESSFUL;
pAttribData += sizeof( DWORD );
dwCurrentLength += sizeof( DWORD );
for ( dwCurrentAttribute = 0;
dwCurrentAttribute < dwNumAttributes ;
dwCurrentAttribute++ ) {
Group.Length = Group.MaximumLength =
( USHORT )( * ( ( DWORD * ) pAttribData ) ) - sizeof( WCHAR );
Group.Buffer = ( PWCHAR ) ( pAttribData + sizeof( DWORD ) );
if ( ( Group.Length + dwCurrentLength ) > NDS_BUFFER_SIZE ) {
return STATUS_UNSUCCESSFUL;
}
//
// Strip off the X500 prefix and the context.
//
GroupLength = 0;
while ( GroupLength < ( Group.Length / sizeof( WCHAR ) ) ) {
if ( Group.Buffer[GroupLength++] == L'=' ) {
Group.Buffer += 1;
Group.Length -= sizeof( WCHAR );
Group.MaximumLength -= sizeof( WCHAR );
GroupLength = ( Group.Length / sizeof( WCHAR ) );
}
Group.Buffer += 1;
Group.Length -= sizeof( WCHAR );
Group.MaximumLength -= sizeof( WCHAR );
}
GroupLength = 0;
while ( GroupLength < ( Group.Length / sizeof( WCHAR ) ) ) {
if ( Group.Buffer[GroupLength++] == L'.' ) {
Group.Length = ( GroupLength - 1 ) * sizeof( WCHAR );
Group.MaximumLength = Group.Length;
break;
}
}
if ( RtlEqualUnicodeString( puGroupName, &Group, TRUE ) ) {
DebugTrace( 0, Dbg, "Group check for %wZ succeeded.\n", &Group );
Status = STATUS_SUCCESS;
goto ExitWithCleanup;
}
//
// Dig out the attribute size and process the next entry.
//
dwAttribLength = ROUNDUP4( * ( ( DWORD * ) pAttribData ) );
dwAttribLength += sizeof( DWORD );
pAttribData += dwAttribLength;
dwCurrentLength += dwAttribLength;
}
ExitWithCleanup:
NdsFreeLockedBuffer( &NdsRequest );
return Status;
}
NTSTATUS
NdsAllocateLockedBuffer(
PLOCKED_BUFFER NdsRequest,
DWORD BufferSize
)
/*++
Description:
Allocate a buffer for io. Lock it down and fill in the
buffer data structure that we pass around.
--*/
{
PAGED_CODE();
NdsRequest->pRecvBufferVa = ALLOCATE_POOL( PagedPool, BufferSize );
if ( !NdsRequest->pRecvBufferVa ) {
DebugTrace( 0, Dbg, "Couldn't allocate locked io buffer.\n", 0 );
return STATUS_INSUFFICIENT_RESOURCES;
}
NdsRequest->dwRecvLen = BufferSize;
NdsRequest->pRecvMdl = ALLOCATE_MDL( NdsRequest->pRecvBufferVa,
BufferSize,
FALSE,
FALSE,
NULL );
if ( !NdsRequest->pRecvMdl ) {
DebugTrace( 0, Dbg, "Couldn't allocate mdl for locked io buffer.\n", 0 );
FREE_POOL( NdsRequest->pRecvBufferVa );
return STATUS_INSUFFICIENT_RESOURCES;
}
MmProbeAndLockPages( NdsRequest->pRecvMdl,
KernelMode,
IoWriteAccess );
return STATUS_SUCCESS;
}
NTSTATUS
NdsFreeLockedBuffer(
PLOCKED_BUFFER NdsRequest
)
/*++
Description:
Free a buffer allocated for io.
--*/
{
PAGED_CODE();
MmUnlockPages( NdsRequest->pRecvMdl );
FREE_MDL( NdsRequest->pRecvMdl );
FREE_POOL( NdsRequest->pRecvBufferVa );
return STATUS_SUCCESS;
}