windows-nt/Source/XPSP1/NT/ds/nw/rdr/security.c
2020-09-26 16:20:57 +08:00

1081 lines
26 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 );
}