mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1080 lines
26 KiB
1080 lines
26 KiB
/*++
|
|
|
|
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 );
|
|
}
|
|
|