summaryrefslogtreecommitdiffstats
path: root/private/nw/rdr/ndsread.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/rdr/ndsread.c')
-rw-r--r--private/nw/rdr/ndsread.c1190
1 files changed, 1190 insertions, 0 deletions
diff --git a/private/nw/rdr/ndsread.c b/private/nw/rdr/ndsread.c
new file mode 100644
index 000000000..189fc9f1c
--- /dev/null
+++ b/private/nw/rdr/ndsread.c
@@ -0,0 +1,1190 @@
+/*++
+
+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;
+
+ PAGED_CODE();
+
+ //
+ // 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, &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 );
+
+ NwDequeueIrpContext( pIrpContext, FALSE );
+
+ Status = CreateScb( &Scb,
+ pIrpContext,
+ &ReferredServer,
+ NULL,
+ NULL,
+ NULL,
+ TRUE,
+ FALSE );
+
+ 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, &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, 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;
+
+ 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,
+ &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;
+
+}