summaryrefslogtreecommitdiffstats
path: root/private/nw/rdr/security.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/rdr/security.c')
-rw-r--r--private/nw/rdr/security.c1009
1 files changed, 1009 insertions, 0 deletions
diff --git a/private/nw/rdr/security.c b/private/nw/rdr/security.c
new file mode 100644
index 000000000..e1b2fbfba
--- /dev/null
+++ b/private/nw/rdr/security.c
@@ -0,0 +1,1009 @@
+/*++
+
+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 )
+#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);
+
+ 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;
+}
+
+
+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 );
+
+ }
+
+ ExDeleteResource( &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;
+ ULONG 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 <
+ (FIELD_OFFSET(NWR_REQUEST_PACKET,Parameters.Logon.UserName)) +
+ InputBuffer->Parameters.Logon.UserNameLength +
+ InputBuffer->Parameters.Logon.PasswordLength +
+ InputBuffer->Parameters.Logon.ServerNameLength +
+ InputBuffer->Parameters.Logon.ReplicaAddrLength) {
+ 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 );
+ ExInitializeResource( &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;
+
+ // 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);
+
+ 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
+
+ }
+
+ //
+ // 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( &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 );
+
+ //
+ // 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 );
+}
+