/*++ Copyright (c) 1989 Microsoft Corporation Module Name: SecurSup.c Abstract: This module implements the Named Pipe Security support routines Author: Gary Kimura [GaryKi] 06-May-1991 Revision History: --*/ #include "NpProcs.h" // // The debug trace level // #define Dbg (DEBUG_TRACE_SECURSUP) #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, NpCopyClientContext) #pragma alloc_text(PAGE, NpImpersonateClientContext) #pragma alloc_text(PAGE, NpInitializeSecurity) #pragma alloc_text(PAGE, NpGetClientSecurityContext) #pragma alloc_text(PAGE, NpUninitializeSecurity) #pragma alloc_text(PAGE, NpFreeClientSecurityContext) #endif NTSTATUS NpInitializeSecurity ( IN PCCB Ccb, IN PSECURITY_QUALITY_OF_SERVICE SecurityQos, IN PETHREAD UserThread ) /*++ Routine Description: This routine initializes the security (impersonation) fields in the ccb. It is called when the client end gets opened. Arguments: Ccb - Supplies the ccb being initialized SecurityQos - Supplies the clients quality of service parameter UserThread - Supplise the client's user thread Return Value: NTSTATUS - Returns the result of the operation --*/ { NTSTATUS Status; PAGED_CODE(); DebugTrace(+1, Dbg, "NpInitializeSecurity, Ccb = %08lx\n", Ccb); // // Either copy the security qos parameter, if it is not null or // create a dummy qos // if (SecurityQos != NULL) { RtlCopyMemory( &Ccb->SecurityQos, SecurityQos, sizeof(SECURITY_QUALITY_OF_SERVICE) ); } else { Ccb->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); Ccb->SecurityQos.ImpersonationLevel = SecurityImpersonation; Ccb->SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; Ccb->SecurityQos.EffectiveOnly = TRUE; } // // Because we might be asked to reinitialize the ccb we need // to first check if the security client context is not null and if so then // free its pool and zero out the context pointer so that if we raise out // this time then a second time through the code we won't try and free the // pool twice. // if (Ccb->SecurityClientContext != NULL) { SeDeleteClientSecurity( Ccb->SecurityClientContext ); NpFreePool( Ccb->SecurityClientContext ); Ccb->SecurityClientContext = NULL; } // // If the tracking mode is static then we need to capture the // client context now otherwise we set the client context field // to null // if (Ccb->SecurityQos.ContextTrackingMode == SECURITY_STATIC_TRACKING) { // // Allocate a client context record, and then initialize it // Ccb->SecurityClientContext = NpAllocatePagedPoolWithQuota ( sizeof(SECURITY_CLIENT_CONTEXT), 'sFpN' ); if (Ccb->SecurityClientContext == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; } else { DebugTrace(0, Dbg, "Static tracking, ClientContext = %08lx\n", Ccb->SecurityClientContext); if (!NT_SUCCESS(Status = SeCreateClientSecurity( UserThread, &Ccb->SecurityQos, FALSE, Ccb->SecurityClientContext ))) { DebugTrace(0, Dbg, "Not successful at creating client security, %08lx\n", Status); NpFreePool( Ccb->SecurityClientContext ); Ccb->SecurityClientContext = NULL; } } } else { DebugTrace(0, Dbg, "Dynamic tracking\n", 0); Ccb->SecurityClientContext = NULL; Status = STATUS_SUCCESS; } DebugTrace(-1, Dbg, "NpInitializeSecurity -> %08lx\n", Status); return Status; } VOID NpUninitializeSecurity ( IN PCCB Ccb ) /*++ Routine Description: This routine deletes the client context referenced by the ccb Arguments: Ccb - Supplies the ccb being uninitialized Return Value: None --*/ { PAGED_CODE(); DebugTrace(+1, Dbg, "NpUninitializeSecurity, Ccb = %08lx\n", Ccb); // // We only have work to do if the client context field is not null // and then we need to delete the client context, and free the memory. // if (Ccb->SecurityClientContext != NULL) { DebugTrace(0, Dbg, "Delete client context, %08lx\n", Ccb->SecurityClientContext); SeDeleteClientSecurity( Ccb->SecurityClientContext ); NpFreePool( Ccb->SecurityClientContext ); Ccb->SecurityClientContext = NULL; } DebugTrace(-1, Dbg, "NpUninitializeSecurity -> VOID\n", 0); return; } VOID NpFreeClientSecurityContext ( IN PSECURITY_CLIENT_CONTEXT SecurityContext ) /*++ Routine Description: This routine frees previously captured security context. Arguments: SecurityContext - Previously captured security context. Return Value: None. --*/ { if (SecurityContext != NULL) { SeDeleteClientSecurity (SecurityContext); NpFreePool (SecurityContext ); } } NTSTATUS NpGetClientSecurityContext ( IN NAMED_PIPE_END NamedPipeEnd, IN PCCB Ccb, IN PETHREAD UserThread, OUT PSECURITY_CLIENT_CONTEXT *ppSecurityContext ) /*++ Routine Description: This routine captures a new client context and stores it in the indicated data entry, but only if the tracking mode is dynamic and only for the client end of the named pipe. Arguments: NamedPipeEnd - Indicates the client or server end of the named pipe. Only the client end does anything. Ccb - Supplies the ccb for this instance of the named pipe. DataEntry - Supplies the data entry to use to store the client context UserThread - Supplies the thread of the client Return Value: NTSTATUS - Returns our success code. --*/ { NTSTATUS Status; PSECURITY_CLIENT_CONTEXT SecurityContext; PAGED_CODE(); DebugTrace(+1, Dbg, "NpSetDataEntryClientContext, Ccb = %08lx\n", Ccb); // // Only do the work if this is the client end and tracking is dynamic // if ((NamedPipeEnd == FILE_PIPE_CLIENT_END) && (Ccb->SecurityQos.ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)) { // // Allocate a client context record, and then initialize it // SecurityContext = NpAllocatePagedPoolWithQuota (sizeof(SECURITY_CLIENT_CONTEXT), 'sFpN'); if (SecurityContext == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } DebugTrace(0, Dbg, "Client End, Dynamic Tracking, ClientContext = %08lx\n", DataEntry->SecurityClientContext); if (!NT_SUCCESS (Status = SeCreateClientSecurity (UserThread, &Ccb->SecurityQos, FALSE, SecurityContext))) { DebugTrace(0, Dbg, "Not successful at creating client security, %08lx\n", Status); NpFreePool (SecurityContext); SecurityContext = NULL; } } else { DebugTrace(0, Dbg, "Static Tracking or Not Client End\n", 0); SecurityContext = NULL; Status = STATUS_SUCCESS; } DebugTrace(-1, Dbg, "NpSetDataEntryClientContext -> %08lx\n", Status); *ppSecurityContext = SecurityContext; return Status; } VOID NpCopyClientContext ( IN PCCB Ccb, IN PDATA_ENTRY DataEntry ) /*++ Routine Description: This routine copies the client context stored in the data entry into the ccb, but only for dynamic tracking. Arguments: Ccb - Supplies the ccb to update. DataEntry - Supplies the DataEntry to copy from. Return Value: --*/ { PAGED_CODE(); DebugTrace(+1, Dbg, "NpCopyClientContext, Ccb = %08lx\n", Ccb); // // Only do the copy if the data entries client context field is not null // which means that we are doing dynamic tracking. Note we will // not be called with a server write data entry that has a non null // client context. // if (DataEntry->SecurityClientContext != NULL) { DebugTrace(0, Dbg, "have something to copy %08lx\n", DataEntry->SecurityClientContext); // // First check if we need to delete and deallocate the client // context in the nonpaged ccb // if (Ccb->SecurityClientContext != NULL) { DebugTrace(0, Dbg, "Remove current client context %08lx\n", Ccb->SecurityClientContext); SeDeleteClientSecurity (Ccb->SecurityClientContext); NpFreePool (Ccb->SecurityClientContext); } // // Now copy over the reference to the client context, and zero // out the reference in the data entry. // Ccb->SecurityClientContext = DataEntry->SecurityClientContext; DataEntry->SecurityClientContext = NULL; } DebugTrace(-1, Dbg, "NpCopyClientContext -> VOID\n", 0 ); return; } NTSTATUS NpImpersonateClientContext ( IN PCCB Ccb ) /*++ Routine Description: This routine impersonates the current client context stored in the ccb Arguments: Ccb - Supplies the ccb for the named pipe Return Value: NTSTATUS - returns our status code. --*/ { NTSTATUS Status; PAGED_CODE(); DebugTrace(+1, Dbg, "NpImpersonateClientContext, Ccb = %08lx\n", Ccb); if (Ccb->SecurityClientContext == NULL) { DebugTrace(0, Dbg, "Cannot impersonate\n", 0); Status = STATUS_CANNOT_IMPERSONATE; } else { Status = SeImpersonateClientEx( Ccb->SecurityClientContext, NULL ); } DebugTrace(-1, Dbg, "NpImpersonateClientContext -> %08lx\n", Status); return Status; }