322 lines
8.1 KiB
C
322 lines
8.1 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
lpcpriv.c
|
||
|
||
Abstract:
|
||
|
||
Local Inter-Process Communication priviledged procedures that implement
|
||
client impersonation.
|
||
|
||
Author:
|
||
|
||
Steve Wood (stevewo) 15-Nov-1989
|
||
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "lpcp.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,LpcpFreePortClientSecurity)
|
||
#pragma alloc_text(PAGE,NtImpersonateClientOfPort)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
NtImpersonateClientOfPort (
|
||
IN HANDLE PortHandle,
|
||
IN PPORT_MESSAGE Message
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure is used by the server thread to temporarily acquire the
|
||
identifier set of a client thread.
|
||
|
||
This service establishes an impersonation token for the calling thread.
|
||
The impersonation token corresponds to the context provided by the port
|
||
client. The client must currently be waiting for a reply to the
|
||
specified message.
|
||
|
||
This service returns an error status code if the client thread is not
|
||
waiting for a reply to the message. The security quality of service
|
||
parameters specified by the client upon connection dictate what use the
|
||
server will have of the client's security context.
|
||
|
||
For complicated or extended impersonation needs, the server may open a
|
||
copy of the client's token (using NtOpenThreadToken()). This must be
|
||
done while impersonating the client.
|
||
|
||
Arguments:
|
||
|
||
PortHandle - Specifies the handle of the communication port that the
|
||
message was received from.
|
||
|
||
Message - Specifies an address of a message that was received from the
|
||
client that is to be impersonated. The ClientId field of the message
|
||
identifies the client thread that is to be impersonated. The client
|
||
thread must be waiting for a reply to the message in order to
|
||
impersonate the client.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status code that indicates whether or not the operation was
|
||
successful.
|
||
|
||
--*/
|
||
|
||
{
|
||
PLPCP_PORT_OBJECT PortObject;
|
||
PLPCP_PORT_OBJECT ConnectedPort;
|
||
KPROCESSOR_MODE PreviousMode;
|
||
NTSTATUS Status;
|
||
PETHREAD ClientThread;
|
||
CLIENT_ID CapturedClientId;
|
||
ULONG CapturedMessageId;
|
||
SECURITY_CLIENT_CONTEXT DynamicSecurity;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get previous processor mode and probe output arguments if necessary.
|
||
//
|
||
|
||
PreviousMode = KeGetPreviousMode();
|
||
|
||
if (PreviousMode != KernelMode) {
|
||
|
||
try {
|
||
|
||
ProbeForReadSmallStructure( Message, sizeof( PORT_MESSAGE ), sizeof( ULONG ));
|
||
|
||
CapturedClientId = Message->ClientId;
|
||
CapturedMessageId = Message->MessageId;
|
||
|
||
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
return( GetExceptionCode() );
|
||
}
|
||
|
||
} else {
|
||
|
||
CapturedClientId = Message->ClientId;
|
||
CapturedMessageId = Message->MessageId;
|
||
}
|
||
|
||
//
|
||
// Reference the communication port object by handle. Return status if
|
||
// unsuccessful.
|
||
//
|
||
|
||
Status = LpcpReferencePortObject( PortHandle, 0,
|
||
PreviousMode, &PortObject );
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
return( Status );
|
||
}
|
||
|
||
//
|
||
// It is an error to try this on any port other than a server
|
||
// communication port
|
||
//
|
||
|
||
if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) {
|
||
|
||
ObDereferenceObject( PortObject );
|
||
|
||
return( STATUS_INVALID_PORT_HANDLE );
|
||
}
|
||
|
||
//
|
||
// Translate the ClientId from the connection request into a
|
||
// thread pointer. This is a referenced pointer to keep the thread
|
||
// from evaporating out from under us.
|
||
//
|
||
|
||
Status = PsLookupProcessThreadByCid( &CapturedClientId,
|
||
NULL,
|
||
&ClientThread );
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
ObDereferenceObject( PortObject );
|
||
|
||
return( Status );
|
||
}
|
||
|
||
//
|
||
// Acquire the mutex that guards the LpcReplyMessage field of
|
||
// the thread and get the pointer to the message that the thread
|
||
// is waiting for a reply to.
|
||
//
|
||
|
||
LpcpAcquireLpcpLock();
|
||
|
||
//
|
||
// The connected port can be in a state with 0 references in a deletion process.
|
||
// We need to test this case while referencing it.
|
||
//
|
||
|
||
ConnectedPort = PortObject->ConnectedPort;
|
||
|
||
if ( ( ConnectedPort == NULL ) ||
|
||
( !ObReferenceObjectSafe( ConnectedPort ) ) ) {
|
||
|
||
//
|
||
// The port is being deleted. Quit this function with
|
||
// appropriate return status.
|
||
// We don't need to dereference the connected port because
|
||
// it is anyway about to be deleted
|
||
//
|
||
|
||
LpcpReleaseLpcpLock();
|
||
|
||
ObDereferenceObject( PortObject );
|
||
ObDereferenceObject( ClientThread );
|
||
|
||
return( STATUS_PORT_DISCONNECTED );
|
||
}
|
||
|
||
//
|
||
// See if the thread is waiting for a reply to the message
|
||
// specified on this call, if the user gave us a bad
|
||
// message id. If not then a bogus message
|
||
// has been specified, so return failure.
|
||
//
|
||
|
||
//
|
||
// The W2k fix searched the client thread in the rundown queue, to make sure
|
||
// we are not impersonating a port from a different connection. Ones we added the port
|
||
// to the thread structure to fix other security issues for reply os accessing data
|
||
// we can use that easy test for the impersonation too, w/o searching the rundown queue
|
||
//
|
||
|
||
if ((ClientThread->LpcReplyMessageId != CapturedMessageId)
|
||
||
|
||
(CapturedMessageId == 0)
|
||
||
|
||
(!LpcpValidateClientPort( ClientThread,
|
||
PortObject,
|
||
LPCP_VALIDATE_REASON_IMPERSONATION)) ) {
|
||
|
||
LpcpReleaseLpcpLock();
|
||
|
||
ObDereferenceObject( PortObject );
|
||
ObDereferenceObject( ClientThread );
|
||
ObDereferenceObject( ConnectedPort );
|
||
|
||
return (STATUS_REPLY_MESSAGE_MISMATCH);
|
||
}
|
||
|
||
LpcpReleaseLpcpLock();
|
||
|
||
//
|
||
// If the client requested dynamic security tracking, then the client
|
||
// security needs to be referenced. Otherwise, (static case)
|
||
// it is already in the client's port.
|
||
//
|
||
|
||
if (ConnectedPort->Flags & PORT_DYNAMIC_SECURITY) {
|
||
|
||
//
|
||
// Impersonate the client with information from the queued message
|
||
//
|
||
|
||
Status = LpcpGetDynamicClientSecurity( ClientThread,
|
||
PortObject->ConnectedPort,
|
||
&DynamicSecurity );
|
||
|
||
if (!NT_SUCCESS( Status )) {
|
||
|
||
ObDereferenceObject( PortObject );
|
||
ObDereferenceObject( ClientThread );
|
||
ObDereferenceObject( ConnectedPort );
|
||
|
||
return( Status );
|
||
}
|
||
|
||
Status = SeImpersonateClientEx( &DynamicSecurity, NULL );
|
||
|
||
LpcpFreeDynamicClientSecurity( &DynamicSecurity );
|
||
|
||
} else {
|
||
|
||
//
|
||
// Impersonate the client with information from the client's port
|
||
//
|
||
|
||
Status = SeImpersonateClientEx( &ConnectedPort->StaticSecurity, NULL );
|
||
|
||
}
|
||
|
||
ObDereferenceObject( PortObject );
|
||
ObDereferenceObject( ClientThread );
|
||
ObDereferenceObject( ConnectedPort );
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
VOID
|
||
LpcpFreePortClientSecurity (
|
||
IN PLPCP_PORT_OBJECT Port
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine cleans up the captured security context for a client port.
|
||
The cleanup is typically done when we are deleting a port
|
||
|
||
Arguments:
|
||
|
||
Port - Supplies the client port being deleted
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// We only do this action if supplied with a client communication port
|
||
//
|
||
|
||
if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) {
|
||
|
||
//
|
||
// We only do this action if the port has static security tracking,
|
||
// and we have a captured client token. The action is to simply
|
||
// delete the client token.
|
||
//
|
||
|
||
if (!(Port->Flags & PORT_DYNAMIC_SECURITY)) {
|
||
|
||
if ( Port->StaticSecurity.ClientToken ) {
|
||
|
||
SeDeleteClientSecurity( &(Port)->StaticSecurity );
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return;
|
||
}
|