|
|
/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
Security.c
Abstract:
This module implements security related tasks in the NetWare redirector.
Author:
Colin Watson [ColinW] 05-Nov-1993
Revision History:
--*/
#include "Procs.h"
#include <stdio.h>
PLOGON FindUserByName( IN PUNICODE_STRING UserName );
//
// The local debug trace level
//
#define Dbg (DEBUG_TRACE_SECURITY)
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, CreateAnsiUid )
#pragma alloc_text( PAGE, MakeUidServer )
#pragma alloc_text( PAGE, FindUser )
#pragma alloc_text( PAGE, FindUserByName )
#pragma alloc_text( PAGE, GetUid )
#pragma alloc_text( PAGE, FreeLogon )
#pragma alloc_text( PAGE, Logon )
#pragma alloc_text( PAGE, Logoff )
#pragma alloc_text( PAGE, GetDriveMapTable )
#endif
VOID CreateAnsiUid( OUT PCHAR aUid, IN PLARGE_INTEGER Uid ) /*++
Routine Description:
This routine converts the Uid into an array of ansi characters, preserving the uniqueness and allocating the buffer in the process.
Note: aUid needs to be 17 bytes long.
Arguments:
OUT PCHAR aUid, IN PLARGE_INTEGER Uid
Return Value:
Status
--*/ { PAGED_CODE();
if (Uid->HighPart != 0) { sprintf( aUid, "%lx%08lx\\", Uid->HighPart, Uid->LowPart ); } else { sprintf( aUid, "%lx\\", Uid->LowPart ); } return; }
NTSTATUS MakeUidServer( PUNICODE_STRING UidServer, PLARGE_INTEGER Uid, PUNICODE_STRING Server )
/*++
Routine Description:
This routine makes a Unicode string of the form 3e7\servername
Arguments:
OUT PUNICODE_STRING UidServer, IN PLARGE_INTEGER Uid, IN PUNICODE_STRING Server
Return Value:
Status
--*/ { //
// Translate the servername into the form 3e7\Server where 3e7
// is the value of the Uid.
//
UCHAR aUid[17]; ANSI_STRING AnsiString; ULONG UnicodeLength; NTSTATUS Status;
PAGED_CODE();
CreateAnsiUid( aUid, Uid);
RtlInitAnsiString( &AnsiString, aUid );
UnicodeLength = RtlAnsiStringToUnicodeSize(&AnsiString);
//
// Ensuring we don't cause overflow, corrupting memory
//
if ( (UnicodeLength + (ULONG)Server->Length) > 0xFFFF ) { return STATUS_INSUFFICIENT_RESOURCES; }
UidServer->MaximumLength = (USHORT)UnicodeLength + Server->Length; UidServer->Buffer = ALLOCATE_POOL(PagedPool,UidServer->MaximumLength);
if (UidServer->Buffer == NULL) { DebugTrace(-1, Dbg, "MakeUidServer -> %08lx\n", STATUS_INSUFFICIENT_RESOURCES); return STATUS_INSUFFICIENT_RESOURCES; }
Status = RtlAnsiStringToUnicodeString( UidServer, &AnsiString, FALSE); ASSERT(NT_SUCCESS(Status) && "MakeUidServer failed!");
Status = RtlAppendStringToString( (PSTRING)UidServer, (PSTRING)Server); ASSERT(NT_SUCCESS(Status) && "MakeUidServer part 2 failed!"); return STATUS_SUCCESS; }
PLOGON FindUser( IN PLARGE_INTEGER Uid, IN BOOLEAN ExactMatch )
/*++
Routine Description:
This routine searches the LogonList for the user entry corresponding to Uid.
Note: Rcb must be held to prevent LogonList being changed.
Arguments:
IN PLARGE_INTEGER Uid
IN BOOLEAN ExactMatch - if TRUE, don't return a default
Return Value:
None
--*/ { PLIST_ENTRY LogonQueueEntry = LogonList.Flink; PLOGON DefaultLogon = NULL;
PAGED_CODE();
DebugTrace(+1, Dbg, "FindUser...\n", 0); DebugTrace( 0, Dbg, " ->UserUidHigh = %08lx\n", Uid->HighPart); DebugTrace( 0, Dbg, " ->UserUidLow = %08lx\n", Uid->LowPart); while ( LogonQueueEntry != &LogonList ) {
PLOGON Logon = CONTAINING_RECORD( LogonQueueEntry, LOGON, Next );
if ( (*Uid).QuadPart == Logon->UserUid.QuadPart ) { DebugTrace(-1, Dbg, " ... %x\n", Logon ); return Logon; }
LogonQueueEntry = Logon->Next.Flink; }
if (ExactMatch) { DebugTrace(-1, Dbg, " ... DefaultLogon NULL\n", 0 ); return NULL; }
LogonQueueEntry = LogonList.Flink; while ( LogonQueueEntry != &LogonList ) {
PLOGON Logon = CONTAINING_RECORD( LogonQueueEntry, LOGON, Next );
if (Logon->UserUid.QuadPart == DefaultLuid.QuadPart) {
//
// This is the first Default Logon entry. If this UID is not
// in the table then this is the one to use.
//
DebugTrace(-1, Dbg, " ... DefaultLogon %lx\n", Logon ); return Logon; }
LogonQueueEntry = Logon->Next.Flink; }
ASSERT( FALSE && "Couldn't find the Id" );
DebugTrace(-1, Dbg, " ... DefaultLogon NULL\n", 0 ); return NULL; }
PLOGON FindUserByName( IN PUNICODE_STRING UserName ) /*++
Routine Description:
This routine searches the LogonList for the user entry corresponding to Username.
Note: Rcb must be held to prevent LogonList being changed.
Arguments:
UserName - The user name to find.
Return Value:
If found, a pointer to the logon structure NULL, if no match
--*/ { PLIST_ENTRY LogonQueueEntry = LogonList.Flink; PLOGON Logon;
PAGED_CODE();
DebugTrace(+1, Dbg, "FindUserByName...\n", 0); DebugTrace( 0, Dbg, " ->UserName = %wZ\n", UserName);
while ( LogonQueueEntry != &LogonList ) {
Logon = CONTAINING_RECORD( LogonQueueEntry, LOGON, Next );
if ( RtlEqualUnicodeString( UserName, &Logon->UserName, TRUE ) ) { DebugTrace(-1, Dbg, " ... %x\n", Logon ); return Logon; }
LogonQueueEntry = Logon->Next.Flink; }
DebugTrace(-1, Dbg, " ... NULL\n", 0 ); return NULL; }
PVCB * GetDriveMapTable ( IN LARGE_INTEGER Uid ) /*++
Routine Description:
This routine searches the LogonList for the user entry corresponding to Uid and returns the drive map table.
Note: Rcb must be held to prevent LogonList being changed.
Arguments:
Uid - The user ID to find.
Return Value:
Always returns a value, even if the default
--*/ { PLOGON Logon;
PAGED_CODE(); Logon = FindUser(&Uid, TRUE);
if ( Logon != NULL ) return Logon->DriveMapTable; else { DebugTrace(+1, Dbg, "Using Global Drive Map Table.\n", 0); return GlobalDriveMapTable; }
}
LARGE_INTEGER GetUid( IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext )
/*++
Routine Description:
This routine gets the effective UID to be used for this create.
Arguments:
SubjectSecurityContext - Supplies the information from IrpSp.
Return Value:
None
--*/ { LARGE_INTEGER LogonId;
PAGED_CODE();
DebugTrace(+1, Dbg, "GetUid ... \n", 0);
// Is the thread currently impersonating someone else?
if (SubjectSecurityContext->ClientToken != NULL) {
//
// If its impersonating someone that is logged in locally then use
// the local id.
//
SeQueryAuthenticationIdToken(SubjectSecurityContext->ClientToken, (PLUID)&LogonId);
if (FindUser(&LogonId, TRUE) == NULL) {
//
// Not logged on locally, use the processes LogonId so that the
// gateway will work.
//
SeQueryAuthenticationIdToken(SubjectSecurityContext->PrimaryToken, (PLUID)&LogonId); }
} else {
//
// Use the processes LogonId
//
SeQueryAuthenticationIdToken(SubjectSecurityContext->PrimaryToken, (PLUID)&LogonId); }
DebugTrace( 0, Dbg, " ->UserUidHigh = %08lx\n", LogonId.HighPart); DebugTrace(-1, Dbg, " ->UserUidLow = %08lx\n", LogonId.LowPart);
return LogonId; }
VOID FreeLogon( IN PLOGON Logon )
/*++
Routine Description:
This routine free's all the strings inside Logon and the structure itself.
Arguments:
IN PLOGON Logon
Return Value:
None
--*/ { PLIST_ENTRY pListEntry; PNDS_SECURITY_CONTEXT pContext;
PAGED_CODE();
if ((Logon == NULL) || (Logon == &Guest)) { return; }
if ( Logon->UserName.Buffer != NULL ) { FREE_POOL( Logon->UserName.Buffer ); }
if ( Logon->PassWord.Buffer != NULL ) { FREE_POOL( Logon->PassWord.Buffer ); }
if ( Logon->ServerName.Buffer != NULL ) { FREE_POOL( Logon->ServerName.Buffer ); }
while ( !IsListEmpty(&Logon->NdsCredentialList) ) {
pListEntry = RemoveHeadList( &Logon->NdsCredentialList ); pContext = CONTAINING_RECORD(pListEntry, NDS_SECURITY_CONTEXT, Next ); FreeNdsContext( pContext );
}
ExDeleteResourceLite( &Logon->CredentialListResource ); FREE_POOL( Logon ); }
NTSTATUS Logon( IN PIRP_CONTEXT IrpContext )
/*++
Routine Description:
This routine takes the username and password supplied and makes them the default to be used for all connections.
Arguments:
IN PIRP_CONTEXT IrpContext - Io Request Packet for request
Return Value:
NTSTATUS
--*/
{ NTSTATUS Status = STATUS_SUCCESS; PLOGON Logon = NULL;
PIRP Irp = IrpContext->pOriginalIrp; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PNWR_REQUEST_PACKET InputBuffer = Irp->AssociatedIrp.SystemBuffer; ULONGLONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
UNICODE_STRING ServerName; PNDS_SECURITY_CONTEXT pNdsContext;
PAGED_CODE();
DebugTrace(+1, Dbg, "Logon\n", 0);
try {
//
// Check some fields in the input buffer.
//
if (InputBufferLength < sizeof(NWR_REQUEST_PACKET)) { try_return(Status = STATUS_BUFFER_TOO_SMALL); }
if (InputBuffer->Version != REQUEST_PACKET_VERSION) { try_return(Status = STATUS_INVALID_PARAMETER); }
if (InputBufferLength < (ULONGLONG)(FIELD_OFFSET(NWR_REQUEST_PACKET,Parameters.Logon.UserName)) + (ULONGLONG)InputBuffer->Parameters.Logon.UserNameLength + (ULONGLONG)InputBuffer->Parameters.Logon.PasswordLength + (ULONGLONG)InputBuffer->Parameters.Logon.ServerNameLength + (ULONGLONG)InputBuffer->Parameters.Logon.ReplicaAddrLength) { try_return(Status = STATUS_INVALID_PARAMETER); }
if ((InputBuffer->Parameters.Logon.UserNameLength % 2) || (InputBuffer->Parameters.Logon.PasswordLength % 2) || (InputBuffer->Parameters.Logon.ServerNameLength % 2) || (InputBuffer->Parameters.Logon.ReplicaAddrLength % 2)) { try_return(Status = STATUS_INVALID_PARAMETER); }
Logon = ALLOCATE_POOL(NonPagedPool,sizeof(LOGON)); if (Logon == NULL) { try_return( Status = STATUS_INSUFFICIENT_RESOURCES ); }
RtlZeroMemory(Logon, sizeof(LOGON)); Logon->NodeTypeCode = NW_NTC_LOGON; Logon->NodeByteSize = sizeof(LOGON); InitializeListHead( &Logon->NdsCredentialList ); ExInitializeResourceLite( &Logon->CredentialListResource );
Status = SetUnicodeString(&Logon->UserName, InputBuffer->Parameters.Logon.UserNameLength, InputBuffer->Parameters.Logon.UserName);
if (!NT_SUCCESS(Status)) { try_return( Status ); }
Status = SetUnicodeString(&Logon->PassWord, InputBuffer->Parameters.Logon.PasswordLength, (PWCHAR) ((PUCHAR)InputBuffer->Parameters.Logon.UserName + InputBuffer->Parameters.Logon.UserNameLength));
if (!NT_SUCCESS(Status)) { try_return( Status ); }
ServerName.Buffer = (PWCHAR) ((PUCHAR)InputBuffer->Parameters.Logon.UserName + InputBuffer->Parameters.Logon.UserNameLength + InputBuffer->Parameters.Logon.PasswordLength);
ServerName.Length = (USHORT)InputBuffer->Parameters.Logon.ServerNameLength;
ServerName.MaximumLength = (USHORT)InputBuffer->Parameters.Logon.ServerNameLength;
if ( ServerName.Length && ServerName.Buffer[0] != L'*' ) {
//
// Only set this as the preferred server if it's not
// a default tree. Default tree requests start with a '*'.
//
Status = SetUnicodeString(&Logon->ServerName, ServerName.Length, ServerName.Buffer );
if (!NT_SUCCESS(Status)) { try_return( Status ); } }
//
// Store the unique userid in both unicode and large integer form
// the unicode form is used as a prefix to the servername in all
// paths so that each userid gets their own connection to the server.
//
*((PLUID)(&Logon->UserUid)) = InputBuffer->Parameters.Logon.LogonId;
Logon->NwPrintOptions = InputBuffer->Parameters.Logon.PrintOption;
// Save Uid for CreateScb
*((PLUID)(&IrpContext->Specific.Create.UserUid)) = InputBuffer->Parameters.Logon.LogonId;
try_exit:NOTHING; } except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode();
}
NwAcquireExclusiveRcb( &NwRcb, TRUE );
if (NT_SUCCESS(Status)) {
DebugTrace( 0, Dbg, " ->UserName = %wZ\n", &Logon->UserName ); DebugTrace( 0, Dbg, " ->PassWord = %wZ\n", &Logon->PassWord );
if ( ServerName.Length && ServerName.Buffer[0] == L'*' ) { DebugTrace( 0, Dbg, " ->DefaultTree = %wZ\n", &ServerName ); } else { DebugTrace( 0, Dbg, " ->ServerName = %wZ\n", &Logon->ServerName ); }
DebugTrace( 0, Dbg, " ->UserUidHigh = %08lx\n", Logon->UserUid.HighPart); DebugTrace( 0, Dbg, " ->UserUidLow = %08lx\n", Logon->UserUid.LowPart);
InsertHeadList( &LogonList, &Logon->Next ); NwReleaseRcb( &NwRcb );
if ( ServerName.Length && ServerName.Buffer[0] != L'*' ) {
PSCB Scb;
// See if we can login as this user.
Status = CreateScb( &Scb, IrpContext, &ServerName, NULL, NULL, NULL, FALSE, FALSE ); if (NT_SUCCESS(Status)) {
//
// CreateScb has already boosted the reference count
// because this is a preferred server so it will not go
// away. We need to dereference it here because there is
// no handle associated with the CreateScb
//
NwDereferenceScb(Scb->pNpScb); }
}
if ( ServerName.Length && ServerName.Buffer[0] == L'*' ) {
PSCB Scb; BOOL SetContext; UINT ContextLength; UNICODE_STRING DefaultContext; IPXaddress *ReplicaAddr;
//
// Ok, this is a little confusing. On Login, the provider can
// specify the address of the replica that we should use to log
// in. If this is the case, then we do pre-connect that replica.
// Otherwise, we do the standard login to any replica. The
// reason for this is that standard replica location uses the
// bindery and doesn't always get us the nearest dir server.
//
if ( InputBuffer->Parameters.Logon.ReplicaAddrLength == sizeof( TDI_ADDRESS_IPX ) ) {
ReplicaAddr = (IPXaddress*) ((PUCHAR) InputBuffer->Parameters.Logon.UserName + InputBuffer->Parameters.Logon.UserNameLength + InputBuffer->Parameters.Logon.PasswordLength + InputBuffer->Parameters.Logon.ServerNameLength);
ReplicaAddr->Socket = NCP_SOCKET;
Status = CreateScb( &Scb, IrpContext, NULL, // anonymous create
ReplicaAddr, // nearest replica add
NULL, // no user name
NULL, // no password
TRUE, // defer the login
FALSE ); // we are not deleting the connection
if (NT_SUCCESS(Status)) { //
// CreateScb has already boosted the reference count
// because this is a preferred server so it will not go
// away. We need to dereference it here because there is
// no handle associated with the CreateScb
//
NwDereferenceScb(Scb->pNpScb); }
}
//
// Set if this includes a default context.
//
ServerName.Buffer += 1; ServerName.Length -= sizeof( WCHAR ); ServerName.MaximumLength -= sizeof( WCHAR );
SetContext = FALSE; ContextLength = 0;
while ( ContextLength < ServerName.Length / sizeof( WCHAR ) ) {
if ( ServerName.Buffer[ContextLength] == L'\\' ) {
SetContext = TRUE;
ContextLength++;
//
// Skip any leading periods.
//
if ( ServerName.Buffer[ContextLength] == L'.' ) {
DefaultContext.Buffer = &ServerName.Buffer[ContextLength + 1]; ServerName.Length -= sizeof ( WCHAR ) ; ServerName.MaximumLength -= sizeof ( WCHAR );
} else {
DefaultContext.Buffer = &ServerName.Buffer[ContextLength];
}
ContextLength *= sizeof( WCHAR ); DefaultContext.Length = ServerName.Length - ContextLength; DefaultContext.MaximumLength = ServerName.MaximumLength - ContextLength;
ServerName.Length -= ( DefaultContext.Length + sizeof( WCHAR ) ); ServerName.MaximumLength -= ( DefaultContext.Length + sizeof( WCHAR ) );
}
ContextLength++; }
//
// Verify that this context is valid before we acquire
// the credentials and really set the context.
//
if ( SetContext ) {
Status = NdsVerifyContext( IrpContext, &ServerName, &DefaultContext );
if ( !NT_SUCCESS( Status )) { SetContext = FALSE; }
}
//
// Generate the credential shell for the default tree and
// set the context if appropriate.
//
Status = NdsLookupCredentials( IrpContext, &ServerName, Logon, &pNdsContext, CREDENTIAL_WRITE, TRUE );
if ( NT_SUCCESS( Status ) ) {
//
// Set the context. It doesn't matter if the
// credential is locked or not.
//
if ( SetContext ) {
RtlCopyUnicodeString( &pNdsContext->CurrentContext, &DefaultContext ); DebugTrace( 0, Dbg, "Default Context: %wZ\n", &DefaultContext ); }
NwReleaseCredList( Logon, IrpContext );
//
// RELAX! The credential list is free.
//
DebugTrace( 0, Dbg, "Default Tree: %wZ\n", &ServerName );
Status = NdsCreateTreeScb( IrpContext, &Scb, &ServerName, NULL, NULL, FALSE, FALSE );
if (NT_SUCCESS(Status)) { NwDereferenceScb(Scb->pNpScb); } } }
//
// No login requested.
//
} else {
FreeLogon( Logon ); NwReleaseRcb( &NwRcb );
}
DebugTrace(-1, Dbg, "Logon %lx\n", Status); return Status; }
NTSTATUS Logoff( IN PIRP_CONTEXT IrpContext ) /*++
Routine Description:
This routine sets the username back to guest and removes the password.
Arguments:
IN PIRP_CONTEXT IrpContext - Io Request Packet for request
Return Value:
NTSTATUS
--*/
{ BOOLEAN Locked = FALSE; NTSTATUS Status = STATUS_SUCCESS; PIRP Irp = IrpContext->pOriginalIrp; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); PNWR_REQUEST_PACKET InputBuffer = Irp->AssociatedIrp.SystemBuffer; ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; LARGE_INTEGER User; PLOGON Logon;
PAGED_CODE();
DebugTrace(+1, Dbg, "Logoff...\n", 0);
try {
//
// Check some fields in the input buffer.
//
if (InputBufferLength < sizeof(NWR_REQUEST_PACKET)) { try_return(Status = STATUS_BUFFER_TOO_SMALL); }
if (InputBuffer->Version != REQUEST_PACKET_VERSION) { try_return(Status = STATUS_INVALID_PARAMETER); }
*((PLUID)(&User)) = InputBuffer->Parameters.Logoff.LogonId;
NwAcquireExclusiveRcb( &NwRcb, TRUE ); Locked = TRUE;
Logon = FindUser(&User, TRUE);
if ( Logon != NULL ) {
LARGE_INTEGER Uid = Logon->UserUid;
//
// We have found the right user.
//
ASSERT( Logon != &Guest);
NwReleaseRcb( &NwRcb ); Locked = FALSE;
DebugTrace( 0, Dbg, " ->UserName = %wZ\n", &Logon->UserName ); DebugTrace( 0, Dbg, " ->ServerName = %wZ\n", &Logon->ServerName ); DebugTrace( 0, Dbg, " ->UserUidHigh = %08lx\n", Logon->UserUid.HighPart); DebugTrace( 0, Dbg, " ->UserUidLow = %08lx\n", Logon->UserUid.LowPart);
//
// Invalidating all the handles for this user will also cause logoffs
// to all the servers in question.
//
NwInvalidateAllHandles(&Uid, IrpContext);
NwAcquireExclusiveRcb( &NwRcb, TRUE ); Locked = TRUE;
Logon = FindUser(&User, TRUE);
if (Logon != NULL) { RemoveEntryList( &Logon->Next ); FreeLogon( Logon ); } else { ASSERT( FALSE && "Double logoff!"); }
Status = STATUS_SUCCESS;
} else {
Status = STATUS_UNSUCCESSFUL; }
try_exit:NOTHING; } finally { if (Locked == TRUE ) { NwReleaseRcb( &NwRcb ); } }
DebugTrace(-1, Dbg, "Logoff %lx\n", Status);
return Status; }
NTSTATUS UpdateUsersPassword( IN PUNICODE_STRING UserName, IN PUNICODE_STRING Password, OUT PLARGE_INTEGER Uid ) /*++
Routine Description:
This routine updates the cached password for a given user. If the named user is not logged in, an error is returned.
Arguments:
UserName - Supplies the name of the user
Password - Supplies the new password
Uid - Returns the LUID of the updated user.
Return Value:
NTSTATUS
--*/ { PLOGON Logon; NTSTATUS Status;
NwAcquireExclusiveRcb( &NwRcb, TRUE );
Logon = FindUserByName( UserName );
if ( Logon != NULL ) {
if ( Logon->PassWord.Buffer != NULL ) { FREE_POOL( Logon->PassWord.Buffer ); }
Status = SetUnicodeString( &Logon->PassWord, Password->Length, Password->Buffer );
*Uid = Logon->UserUid;
} else {
Status = STATUS_UNSUCCESSFUL; }
NwReleaseRcb( &NwRcb ); return( Status );
}
NTSTATUS UpdateServerPassword( PIRP_CONTEXT IrpContext, IN PUNICODE_STRING ServerName, IN PUNICODE_STRING UserName, IN PUNICODE_STRING Password, IN PLARGE_INTEGER Uid ) /*++
Routine Description:
This routine updates the cached password for a named server connection. If the server does not exist in the server table, an error is returned.
Arguments:
ServerName - Supplies the name of the server
UserName - Supplies the name of the user
Password - Supplies the new password
Uid - The LUID of the user.
Return Value:
NTSTATUS
--*/ { UNICODE_STRING UidServer; NTSTATUS Status; PUNICODE_PREFIX_TABLE_ENTRY PrefixEntry; PSCB pScb; PNONPAGED_SCB pNpScb; PVOID Buffer;
Status = MakeUidServer( &UidServer, Uid, ServerName );
if ( !NT_SUCCESS( Status )) { return( Status ); }
DebugTrace( 0, Dbg, " ->UidServer = %wZ\n", &UidServer );
NwAcquireExclusiveRcb( &NwRcb, TRUE );
PrefixEntry = RtlFindUnicodePrefix( &NwRcb.ServerNameTable, &UidServer, 0 );
if ( PrefixEntry != NULL ) {
pScb = CONTAINING_RECORD( PrefixEntry, SCB, PrefixEntry ); pNpScb = pScb->pNpScb;
NwReferenceScb( pNpScb );
//
// Release the RCB.
//
NwReleaseRcb( &NwRcb );
} else {
NwReleaseRcb( &NwRcb ); FREE_POOL(UidServer.Buffer); return( STATUS_BAD_NETWORK_PATH ); }
IrpContext->pNpScb = pNpScb; NwAppendToQueueAndWait( IrpContext );
//
// Free the old username password, allocate a new one.
//
if ( pScb->UserName.Buffer != NULL ) { FREE_POOL( pScb->UserName.Buffer ); }
Buffer = ALLOCATE_POOL_EX( NonPagedPool, UserName->Length + Password->Length );
pScb->UserName.Buffer = Buffer; pScb->UserName.Length = pScb->UserName.MaximumLength = UserName->Length; RtlMoveMemory( pScb->UserName.Buffer, UserName->Buffer, UserName->Length );
pScb->Password.Buffer = (PWCHAR)((PCHAR)Buffer + UserName->Length); pScb->Password.Length = pScb->Password.MaximumLength = Password->Length; RtlMoveMemory( pScb->Password.Buffer, Password->Buffer, Password->Length );
FREE_POOL(UidServer.Buffer);
return( STATUS_SUCCESS ); }
|