/* * @implemented */ PCONTROLLER_OBJECT NTAPI IoCreateController(IN ULONG Size) { PCONTROLLER_OBJECT Controller; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE Handle; NTSTATUS Status; PAGED_CODE(); /* Initialize an empty OBA */ InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); /* Create the Object */ Status = ObCreateObject(KernelMode, IoControllerObjectType, &ObjectAttributes, KernelMode, NULL, sizeof(CONTROLLER_OBJECT) + Size, 0, 0, (PVOID*)&Controller); if (!NT_SUCCESS(Status)) return NULL; /* Insert it */ Status = ObInsertObject(Controller, NULL, FILE_READ_DATA | FILE_WRITE_DATA, 1, (PVOID*)&Controller, &Handle); if (!NT_SUCCESS(Status)) return NULL; /* Close the dummy handle */ ObCloseHandle(Handle, KernelMode); /* Zero the Object and set its data */ RtlZeroMemory(Controller, sizeof(CONTROLLER_OBJECT) + Size); Controller->Type = IO_TYPE_CONTROLLER; Controller->Size = sizeof(CONTROLLER_OBJECT) + (CSHORT)Size; Controller->ControllerExtension = (Controller + 1); /* Initialize its Queue */ KeInitializeDeviceQueue(&Controller->DeviceWaitQueue); /* Return Controller */ return Controller; }
BOOLEAN obtest( void ) { ULONG i; HANDLE Handles[ 2 ]; NTSTATUS Status; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; ObpDumpObjectTable( ObpGetObjectTable(), NULL ); RtlInitString( &ObjectTypeAName, "ObjectTypeA" ); RtlInitString( &ObjectTypeBName, "ObjectTypeB" ); RtlZeroMemory( &ObjectTypeInitializer, sizeof( ObjectTypeInitializer ) ); ObjectTypeInitializer.Length = sizeof( ObjectTypeInitializer ); ObjectTypeInitializer.ValidAccessMask = -1; ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.MaintainHandleCount = TRUE; ObjectTypeInitializer.DumpProcedure = DumpAProc; ObjectTypeInitializer.OpenProcedure = OpenAProc; ObjectTypeInitializer.CloseProcedure = CloseAProc; ObjectTypeInitializer.DeleteProcedure = DeleteAProc; ObjectTypeInitializer.ParseProcedure = ParseAProc; ObCreateObjectType( &ObjectTypeAName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ObjectTypeA ); ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.MaintainHandleCount = FALSE; ObjectTypeInitializer.GenericMapping = MyGenericMapping; ObjectTypeInitializer.DumpProcedure = DumpBProc; ObjectTypeInitializer.OpenProcedure = NULL; ObjectTypeInitializer.CloseProcedure = NULL; ObjectTypeInitializer.DeleteProcedure = DeleteBProc; ObjectTypeInitializer.ParseProcedure = NULL; ObCreateObjectType( &ObjectTypeBName, &ObjectTypeInitializer, (PSECURITY_DESCRIPTOR)NULL, &ObjectTypeB ); ObpDumpTypes( NULL ); RtlInitString( &DirectoryName, "\\MyObjects" ); InitializeObjectAttributes( &DirectoryObjA, &DirectoryName, OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, NULL, NULL ); NtCreateDirectoryObject( &DirectoryHandle, 0, &DirectoryObjA ); NtClose( DirectoryHandle ); RtlInitString( &ObjectAName, "\\myobjects\\ObjectA" ); InitializeObjectAttributes( &ObjectAObjA, &ObjectAName, OBJ_CASE_INSENSITIVE, NULL, NULL ); RtlInitString( &ObjectBName, "\\myobjects\\ObjectB" ); InitializeObjectAttributes( &ObjectBObjA, &ObjectBName, OBJ_CASE_INSENSITIVE, NULL, NULL ); Status = ObCreateObject( KernelMode, ObjectTypeA, &ObjectAObjA, KernelMode, NULL, (ULONG)sizeof( OBJECTTYPEA ), 0L, 0L, (PVOID *)&ObjectBodyA ); ObjectA = (POBJECTTYPEA)ObjectBodyA; ObjectA->TypeALength = sizeof( *ObjectA ); for (i=0; i<4; i++) { ObjectA->Stuff[i] = i+1; } KeInitializeEvent( &ObjectA->Event, NotificationEvent, TRUE ); Status = ObCreateObject( KernelMode, ObjectTypeB, &ObjectBObjA, KernelMode, NULL, (ULONG)sizeof( OBJECTTYPEB ), 0L, 0L, (PVOID *)&ObjectBodyB ); ObjectB = (POBJECTTYPEB)ObjectBodyB; ObjectB->TypeBLength = sizeof( *ObjectB ); for (i=0; i<16; i++) { ObjectB->Stuff[i] = i+1; } KeInitializeSemaphore ( &ObjectB->Semaphore, 2L, 2L ); Status = ObInsertObject( ObjectBodyA, SYNCHRONIZE | 0x3, NULL, 1, &ObjectBodyA, &ObjectHandleA1 ); DbgPrint( "Status: %lx ObjectBodyA: %lx ObjectHandleA1: %lx\n", Status, ObjectBodyA, ObjectHandleA1 ); Status = ObInsertObject( ObjectBodyB, SYNCHRONIZE | 0x1, NULL, 1, &ObjectBodyB, &ObjectHandleB1 ); DbgPrint( "Status: %lx ObjectBodyB: %lx ObjectHandleB1: %lx\n", Status, ObjectBodyB, ObjectHandleB1 ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); RtlInitString( &ObjectAName, "\\MyObjects\\ObjectA" ); InitializeObjectAttributes( &ObjectAObjA, &ObjectAName, OBJ_OPENIF, NULL, NULL ); Status = ObCreateObject( KernelMode, ObjectTypeA, &ObjectAObjA, KernelMode, NULL, (ULONG)sizeof( OBJECTTYPEA ), 0L, 0L, (PVOID *)&ObjectBodyA1 ); Status = ObInsertObject( ObjectBodyA1, SYNCHRONIZE | 0x3, NULL, 1, &ObjectBodyA2, &ObjectHandleA2 ); DbgPrint( "Status: %lx ObjectBodyA1: %lx ObjectBodyA2: %lx ObjectHandleA2: %lx\n", Status, ObjectBodyA1, ObjectBodyA2, ObjectHandleA2 ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); NtClose( ObjectHandleA2 ); ObDereferenceObject( ObjectBodyA2 ); // ObInsertObject,ObjectPointerBias NtWaitForSingleObject( ObjectHandleB1, TRUE, NULL ); Handles[ 0 ] = ObjectHandleA1; Handles[ 1 ] = ObjectHandleB1; NtWaitForMultipleObjects( 2, Handles, WaitAny, TRUE, NULL ); ObReferenceObjectByHandle( ObjectHandleA1, 0L, ObjectTypeA, KernelMode, &ObjectBodyA, NULL ); ObReferenceObjectByHandle( ObjectHandleB1, 0L, ObjectTypeB, KernelMode, &ObjectBodyB, NULL ); DbgPrint( "Reference Handle %lx = %lx\n", ObjectHandleA1, ObjectBodyA ); DbgPrint( "Reference Handle %lx = %lx\n", ObjectHandleB1, ObjectBodyB ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); ObReferenceObjectByPointer( ObjectBodyA, 0L, ObjectTypeA, KernelMode ); ObReferenceObjectByPointer( ObjectBodyB, 0L, ObjectTypeB, KernelMode ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); RtlInitString( &ObjectAPathName, "\\MyObjects\\ObjectA" ); RtlInitString( &ObjectBPathName, "\\MyObjects\\ObjectB" ); ObReferenceObjectByName( &ObjectAPathName, OBJ_CASE_INSENSITIVE, 0L, ObjectTypeA, KernelMode, NULL, &ObjectBodyA ); ObReferenceObjectByName( &ObjectBPathName, OBJ_CASE_INSENSITIVE, 0L, ObjectTypeB, KernelMode, NULL, &ObjectBodyB ); DbgPrint( "Reference Name %s = %lx\n", ObjectAPathName.Buffer, ObjectBodyA ); DbgPrint( "Reference Name %s = %lx\n", ObjectBPathName.Buffer, ObjectBodyB ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); ObDereferenceObject( ObjectBodyA ); // ObInsertObject,ObjectPointerBias ObDereferenceObject( ObjectBodyB ); ObDereferenceObject( ObjectBodyA ); // ObReferenceObjectByHandle ObDereferenceObject( ObjectBodyB ); ObDereferenceObject( ObjectBodyA ); // ObReferenceObjectByPointer ObDereferenceObject( ObjectBodyB ); ObDereferenceObject( ObjectBodyA ); // ObReferenceObjectByName ObDereferenceObject( ObjectBodyB ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); InitializeObjectAttributes( &ObjectAObjA, &ObjectAPathName, OBJ_CASE_INSENSITIVE, NULL, NULL ); ObOpenObjectByName( &ObjectAObjA, 0L, NULL, ObjectTypeA, KernelMode, NULL, &ObjectHandleA2 ); InitializeObjectAttributes( &ObjectBObjA, &ObjectBPathName, OBJ_CASE_INSENSITIVE, NULL, NULL ); ObOpenObjectByName( &ObjectBObjA, 0L, NULL, ObjectTypeB, KernelMode, NULL, &ObjectHandleB2 ); DbgPrint( "Open Object Name %s = %lx\n", ObjectAPathName.Buffer, ObjectHandleA2 ); DbgPrint( "Open Object Name %s = %lx\n", ObjectBPathName.Buffer, ObjectHandleB2 ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); NtClose( ObjectHandleA1 ); NtClose( ObjectHandleB1 ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); ObReferenceObjectByHandle( ObjectHandleA2, 0L, ObjectTypeA, KernelMode, &ObjectBodyA, NULL ); ObReferenceObjectByHandle( ObjectHandleB2, 0L, ObjectTypeB, KernelMode, &ObjectBodyB, NULL ); DbgPrint( "Reference Handle %lx = %lx\n", ObjectHandleA2, ObjectBodyA ); DbgPrint( "Reference Handle %lx = %lx\n", ObjectHandleB2, ObjectBodyB ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); ObOpenObjectByPointer( ObjectBodyA, OBJ_CASE_INSENSITIVE, 0L, NULL, ObjectTypeA, KernelMode, &ObjectHandleA1 ); ObOpenObjectByPointer( ObjectBodyB, OBJ_CASE_INSENSITIVE, 0L, NULL, ObjectTypeB, KernelMode, &ObjectHandleB1 ); DbgPrint( "Open Object Pointer %lx = %lx\n", ObjectBodyA, ObjectHandleA1 ); DbgPrint( "Open Object Pointer %lx = %lx\n", ObjectBodyB, ObjectHandleB1 ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); ObReferenceObjectByHandle( ObjectHandleA1, 0L, ObjectTypeA, KernelMode, &ObjectBodyA, NULL ); ObReferenceObjectByHandle( ObjectHandleB1, 0L, ObjectTypeB, KernelMode, &ObjectBodyB, NULL ); DbgPrint( "Reference Handle %lx = %lx\n", ObjectHandleA1, ObjectBodyA ); DbgPrint( "Reference Handle %lx = %lx\n", ObjectHandleB1, ObjectBodyB ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); ObDereferenceObject( ObjectBodyA ); // ObReferenceObjectByHandle ObDereferenceObject( ObjectBodyB ); ObDereferenceObject( ObjectBodyA ); // ObReferenceObjectByHandle ObDereferenceObject( ObjectBodyB ); NtClose( ObjectHandleA1 ); NtClose( ObjectHandleB1 ); NtClose( ObjectHandleA2 ); NtClose( ObjectHandleB2 ); ObpDumpObjectTable( ObpGetObjectTable(), NULL ); TestFunction = NULL; return( TRUE ); }
NTSTATUS NtCreateEvent ( __out PHANDLE EventHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in EVENT_TYPE EventType, __in BOOLEAN InitialState ) /*++ Routine Description: This function creates an event object, sets it initial state to the specified value, and opens a handle to the object with the specified desired access. Arguments: EventHandle - Supplies a pointer to a variable that will receive the event object handle. DesiredAccess - Supplies the desired types of access for the event object. ObjectAttributes - Supplies a pointer to an object attributes structure. EventType - Supplies the type of the event (autoclearing or notification). InitialState - Supplies the initial state of the event object. Return Value: NTSTATUS. --*/ { PVOID Event; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(EventHandle); } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } // // Check argument validity. // if ((EventType != NotificationEvent) && (EventType != SynchronizationEvent)) { return STATUS_INVALID_PARAMETER; } // // Allocate event object. // Status = ObCreateObject(PreviousMode, ExEventObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KEVENT), 0, 0, &Event); // // If the event object was successfully allocated, then initialize the // event object and attempt to insert the event object in the current // process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeEvent((PKEVENT)Event, EventType, InitialState); Status = ObInsertObject(Event, NULL, DesiredAccess, 0, NULL, &Handle); // // If the event object was successfully inserted in the current // process' handle table, then attempt to write the event object // handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, // an access violation will occur. // if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { try { *EventHandle = Handle; } except(EXCEPTION_EXECUTE_HANDLER) { NOTHING; } } else { *EventHandle = Handle; } } }
NTSTATUS NtCreateEvent ( OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN EVENT_TYPE EventType, IN BOOLEAN InitialState ) /*++ Routine Description: This function creates an event object, sets it initial state to the specified value, and opens a handle to the object with the specified desired access. Arguments: EventHandle - Supplies a pointer to a variable that will receive the event object handle. DesiredAccess - Supplies the desired types of access for the event object. ObjectAttributes - Supplies a pointer to an object attributes structure. EventType - Supplies the type of the event (autoclearing or notification). InitialState - Supplies the initial state of the event object. Return Value: TBS --*/ { PVOID Event; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create an event object. If the probe fails, then return the // exception code as the service status. Otherwise return the status value // returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(EventHandle); } // // Check argument validity. // if ((EventType != NotificationEvent) && (EventType != SynchronizationEvent)) { return STATUS_INVALID_PARAMETER; } // // Allocate event object. // Status = ObCreateObject(PreviousMode, ExEventObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KEVENT), 0, 0, (PVOID *)&Event); // // If the event object was successfully allocated, then initialize the // event object and attempt to insert the event object in the current // process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeEvent((PKEVENT)Event, EventType, InitialState); Status = ObInsertObject(Event, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the event object was successfully inserted in the current // process' handle table, then attempt to write the event object // handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, // an access violation will occur. // if (NT_SUCCESS(Status)) { try { *EventHandle = Handle; } except(ExSystemExceptionFilter()) { } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS NtCreateTimer ( OUT PHANDLE TimerHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN TIMER_TYPE TimerType ) /*++ Routine Description: This function creates an timer object and opens a handle to the object with the specified desired access. Arguments: TimerHandle - Supplies a pointer to a variable that will receive the timer object handle. DesiredAccess - Supplies the desired types of access for the timer object. ObjectAttributes - Supplies a pointer to an object attributes structure. TimerType - Supplies the type of the timer (autoclearing or notification). Return Value: TBS --*/ { PETIMER ExTimer; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create a timer object. If the probe fails, then return the // exception code as the service status. Otherwise return the status value // returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(TimerHandle); } // // Check argument validity. // if ((TimerType != NotificationTimer) && (TimerType != SynchronizationTimer)) { return STATUS_INVALID_PARAMETER_4; } // // Allocate timer object. // Status = ObCreateObject(PreviousMode, ExTimerObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(ETIMER), 0, 0, (PVOID *)&ExTimer); // // If the timer object was successfully allocated, then initialize the // timer object and attempt to insert the time object in the current // process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeDpc(&ExTimer->TimerDpc, ExpTimerDpcRoutine, (PVOID)ExTimer); KeInitializeTimerEx(&ExTimer->KeTimer, TimerType); KeInitializeSpinLock(&ExTimer->Lock); ExTimer->ApcAssociated = FALSE; ExTimer->WakeTimer = FALSE; ExTimer->WakeTimerListEntry.Flink = NULL; Status = ObInsertObject((PVOID)ExTimer, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the timer object was successfully inserted in the current // process' handle table, then attempt to write the timer object // handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, // an access violation will occur. // if (NT_SUCCESS(Status)) { try { *TimerHandle = Handle; } except(ExSystemExceptionFilter()) { } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS NtCreateIoCompletion ( __out PHANDLE IoCompletionHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in ULONG Count OPTIONAL ) /*++ Routine Description: This function creates an I/O completion object, sets the maximum target concurrent thread count to the specified value, and opens a handle to the object with the specified desired access. Arguments: IoCompletionHandle - Supplies a pointer to a variable that receives the I/O completion object handle. DesiredAccess - Supplies the desired types of access for the I/O completion object. ObjectAttributes - Supplies a pointer to an object attributes structure. Count - Supplies the target maximum number of threads that should be concurrently active. If this parameter is not specified, then the number of processors is used. Return Value: STATUS_SUCCESS is returned if the function is success. Otherwise, an error status is returned. --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; PVOID IoCompletion; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create an I/O completion object. If the probe fails, then // return the exception code as the service status. Otherwise, return the // status value returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(IoCompletionHandle); } // // Allocate I/O completion object. // Status = ObCreateObject(PreviousMode, IoCompletionObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KQUEUE), 0, 0, (PVOID *)&IoCompletion); // // If the I/O completion object was successfully allocated, then // initialize the object and attempt to insert it in the handle // table of the current process. // if (NT_SUCCESS(Status)) { KeInitializeQueue((PKQUEUE)IoCompletion, Count); Status = ObInsertObject(IoCompletion, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the I/O completion object was successfully inserted in // the handle table of the current process, then attempt to // write the handle value. If the write attempt fails, then // do not report an error. When the caller attempts to access // the handle value, an access violation will occur. // if (NT_SUCCESS(Status)) { try { *IoCompletionHandle = Handle; } except(ExSystemExceptionFilter()) { NOTHING; } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { Status = GetExceptionCode(); } // // Return service status. // return Status; }
/* * @implemented */ NTSTATUS NTAPI NtSecureConnectPort(OUT PHANDLE PortHandle, IN PUNICODE_STRING PortName, IN PSECURITY_QUALITY_OF_SERVICE Qos, IN OUT PPORT_VIEW ClientView OPTIONAL, IN PSID ServerSid OPTIONAL, IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL, OUT PULONG MaxMessageLength OPTIONAL, IN OUT PVOID ConnectionInformation OPTIONAL, IN OUT PULONG ConnectionInformationLength OPTIONAL) { ULONG ConnectionInfoLength = 0; PLPCP_PORT_OBJECT Port, ClientPort; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); NTSTATUS Status = STATUS_SUCCESS; HANDLE Handle; PVOID SectionToMap; PLPCP_MESSAGE Message; PLPCP_CONNECTION_MESSAGE ConnectMessage; PETHREAD Thread = PsGetCurrentThread(); ULONG PortMessageLength; LARGE_INTEGER SectionOffset; PTOKEN Token; PTOKEN_USER TokenUserInfo; PAGED_CODE(); LPCTRACE(LPC_CONNECT_DEBUG, "Name: %wZ. Qos: %p. Views: %p/%p. Sid: %p\n", PortName, Qos, ClientView, ServerView, ServerSid); /* Validate client view */ if ((ClientView) && (ClientView->Length != sizeof(PORT_VIEW))) { /* Fail */ return STATUS_INVALID_PARAMETER; } /* Validate server view */ if ((ServerView) && (ServerView->Length != sizeof(REMOTE_PORT_VIEW))) { /* Fail */ return STATUS_INVALID_PARAMETER; } /* Check if caller sent connection information length */ if (ConnectionInformationLength) { /* Retrieve the input length */ ConnectionInfoLength = *ConnectionInformationLength; } /* Get the port */ Status = ObReferenceObjectByName(PortName, 0, NULL, PORT_CONNECT, LpcPortObjectType, PreviousMode, NULL, (PVOID *)&Port); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to reference port '%wZ': 0x%lx\n", PortName, Status); return Status; } /* This has to be a connection port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT) { /* It isn't, so fail */ ObDereferenceObject(Port); return STATUS_INVALID_PORT_HANDLE; } /* Check if we have a SID */ if (ServerSid) { /* Make sure that we have a server */ if (Port->ServerProcess) { /* Get its token and query user information */ Token = PsReferencePrimaryToken(Port->ServerProcess); //Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo); // FIXME: Need SeQueryInformationToken Status = STATUS_SUCCESS; TokenUserInfo = ExAllocatePoolWithTag(PagedPool, sizeof(TOKEN_USER), TAG_SE); TokenUserInfo->User.Sid = ServerSid; PsDereferencePrimaryToken(Token); /* Check for success */ if (NT_SUCCESS(Status)) { /* Compare the SIDs */ if (!RtlEqualSid(ServerSid, TokenUserInfo->User.Sid)) { /* Fail */ Status = STATUS_SERVER_SID_MISMATCH; } /* Free token information */ ExFreePoolWithTag(TokenUserInfo, TAG_SE); } } else { /* Invalid SID */ Status = STATUS_SERVER_SID_MISMATCH; } /* Check if SID failed */ if (!NT_SUCCESS(Status)) { /* Quit */ ObDereferenceObject(Port); return Status; } } /* Create the client port */ Status = ObCreateObject(PreviousMode, LpcPortObjectType, NULL, PreviousMode, NULL, sizeof(LPCP_PORT_OBJECT), 0, 0, (PVOID *)&ClientPort); if (!NT_SUCCESS(Status)) { /* Failed, dereference the server port and return */ ObDereferenceObject(Port); return Status; } /* Setup the client port */ RtlZeroMemory(ClientPort, sizeof(LPCP_PORT_OBJECT)); ClientPort->Flags = LPCP_CLIENT_PORT; ClientPort->ConnectionPort = Port; ClientPort->MaxMessageLength = Port->MaxMessageLength; ClientPort->SecurityQos = *Qos; InitializeListHead(&ClientPort->LpcReplyChainHead); InitializeListHead(&ClientPort->LpcDataInfoChainHead); /* Check if we have dynamic security */ if (Qos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING) { /* Remember that */ ClientPort->Flags |= LPCP_SECURITY_DYNAMIC; } else { /* Create our own client security */ Status = SeCreateClientSecurity(Thread, Qos, FALSE, &ClientPort->StaticSecurity); if (!NT_SUCCESS(Status)) { /* Security failed, dereference and return */ ObDereferenceObject(ClientPort); return Status; } } /* Initialize the port queue */ Status = LpcpInitializePortQueue(ClientPort); if (!NT_SUCCESS(Status)) { /* Failed */ ObDereferenceObject(ClientPort); return Status; } /* Check if we have a client view */ if (ClientView) { /* Get the section handle */ Status = ObReferenceObjectByHandle(ClientView->SectionHandle, SECTION_MAP_READ | SECTION_MAP_WRITE, MmSectionObjectType, PreviousMode, (PVOID*)&SectionToMap, NULL); if (!NT_SUCCESS(Status)) { /* Fail */ ObDereferenceObject(Port); return Status; } /* Set the section offset */ SectionOffset.QuadPart = ClientView->SectionOffset; /* Map it */ Status = MmMapViewOfSection(SectionToMap, PsGetCurrentProcess(), &ClientPort->ClientSectionBase, 0, 0, &SectionOffset, &ClientView->ViewSize, ViewUnmap, 0, PAGE_READWRITE); /* Update the offset */ ClientView->SectionOffset = SectionOffset.LowPart; /* Check for failure */ if (!NT_SUCCESS(Status)) { /* Fail */ ObDereferenceObject(SectionToMap); ObDereferenceObject(Port); return Status; } /* Update the base */ ClientView->ViewBase = ClientPort->ClientSectionBase; /* Reference and remember the process */ ClientPort->MappingProcess = PsGetCurrentProcess(); ObReferenceObject(ClientPort->MappingProcess); } else { /* No section */ SectionToMap = NULL; } /* Normalize connection information */ if (ConnectionInfoLength > Port->MaxConnectionInfoLength) { /* Use the port's maximum allowed value */ ConnectionInfoLength = Port->MaxConnectionInfoLength; } /* Allocate a message from the port zone */ Message = LpcpAllocateFromPortZone(); if (!Message) { /* Fail if we couldn't allocate a message */ if (SectionToMap) ObDereferenceObject(SectionToMap); ObDereferenceObject(ClientPort); return STATUS_NO_MEMORY; } /* Set pointer to the connection message and fill in the CID */ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1); Message->Request.ClientId = Thread->Cid; /* Check if we have a client view */ if (ClientView) { /* Set the view size */ Message->Request.ClientViewSize = ClientView->ViewSize; /* Copy the client view and clear the server view */ RtlCopyMemory(&ConnectMessage->ClientView, ClientView, sizeof(PORT_VIEW)); RtlZeroMemory(&ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW)); } else { /* Set the size to 0 and clear the connect message */ Message->Request.ClientViewSize = 0; RtlZeroMemory(ConnectMessage, sizeof(LPCP_CONNECTION_MESSAGE)); } /* Set the section and client port. Port is NULL for now */ ConnectMessage->ClientPort = NULL; ConnectMessage->SectionToMap = SectionToMap; /* Set the data for the connection request message */ Message->Request.u1.s1.DataLength = (CSHORT)ConnectionInfoLength + sizeof(LPCP_CONNECTION_MESSAGE); Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) + Message->Request.u1.s1.DataLength; Message->Request.u2.s2.Type = LPC_CONNECTION_REQUEST; /* Check if we have connection information */ if (ConnectionInformation) { /* Copy it in */ RtlCopyMemory(ConnectMessage + 1, ConnectionInformation, ConnectionInfoLength); } /* Acquire the port lock */ KeAcquireGuardedMutex(&LpcpLock); /* Check if someone already deleted the port name */ if (Port->Flags & LPCP_NAME_DELETED) { /* Fail the request */ Status = STATUS_OBJECT_NAME_NOT_FOUND; } else { /* Associate no thread yet */ Message->RepliedToThread = NULL; /* Generate the Message ID and set it */ Message->Request.MessageId = LpcpNextMessageId++; if (!LpcpNextMessageId) LpcpNextMessageId = 1; Thread->LpcReplyMessageId = Message->Request.MessageId; /* Insert the message into the queue and thread chain */ InsertTailList(&Port->MsgQueue.ReceiveHead, &Message->Entry); InsertTailList(&Port->LpcReplyChainHead, &Thread->LpcReplyChain); Thread->LpcReplyMessage = Message; /* Now we can finally reference the client port and link it*/ ObReferenceObject(ClientPort); ConnectMessage->ClientPort = ClientPort; /* Enter a critical region */ KeEnterCriticalRegion(); } /* Add another reference to the port */ ObReferenceObject(Port); /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); /* Check for success */ if (NT_SUCCESS(Status)) { LPCTRACE(LPC_CONNECT_DEBUG, "Messages: %p/%p. Ports: %p/%p. Status: %lx\n", Message, ConnectMessage, Port, ClientPort, Status); /* If this is a waitable port, set the event */ if (Port->Flags & LPCP_WAITABLE_PORT) KeSetEvent(&Port->WaitEvent, 1, FALSE); /* Release the queue semaphore and leave the critical region */ LpcpCompleteWait(Port->MsgQueue.Semaphore); KeLeaveCriticalRegion(); /* Now wait for a reply */ LpcpConnectWait(&Thread->LpcReplySemaphore, PreviousMode); } /* Check for failure */ if (!NT_SUCCESS(Status)) goto Cleanup; /* Free the connection message */ SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread); /* Check if we got a message back */ if (Message) { /* Check for new return length */ if ((Message->Request.u1.s1.DataLength - sizeof(LPCP_CONNECTION_MESSAGE)) < ConnectionInfoLength) { /* Set new normalized connection length */ ConnectionInfoLength = Message->Request.u1.s1.DataLength - sizeof(LPCP_CONNECTION_MESSAGE); } /* Check if we had connection information */ if (ConnectionInformation) { /* Check if we had a length pointer */ if (ConnectionInformationLength) { /* Return the length */ *ConnectionInformationLength = ConnectionInfoLength; } /* Return the connection information */ RtlCopyMemory(ConnectionInformation, ConnectMessage + 1, ConnectionInfoLength ); } /* Make sure we had a connected port */ if (ClientPort->ConnectedPort) { /* Get the message length before the port might get killed */ PortMessageLength = Port->MaxMessageLength; /* Insert the client port */ Status = ObInsertObject(ClientPort, NULL, PORT_ALL_ACCESS, 0, (PVOID *)NULL, &Handle); if (NT_SUCCESS(Status)) { /* Return the handle */ *PortHandle = Handle; LPCTRACE(LPC_CONNECT_DEBUG, "Handle: %p. Length: %lx\n", Handle, PortMessageLength); /* Check if maximum length was requested */ if (MaxMessageLength) *MaxMessageLength = PortMessageLength; /* Check if we had a client view */ if (ClientView) { /* Copy it back */ RtlCopyMemory(ClientView, &ConnectMessage->ClientView, sizeof(PORT_VIEW)); } /* Check if we had a server view */ if (ServerView) { /* Copy it back */ RtlCopyMemory(ServerView, &ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW)); } } } else { /* No connection port, we failed */ if (SectionToMap) ObDereferenceObject(SectionToMap); /* Acquire the lock */ KeAcquireGuardedMutex(&LpcpLock); /* Check if it's because the name got deleted */ if (!(ClientPort->ConnectionPort) || (Port->Flags & LPCP_NAME_DELETED)) { /* Set the correct status */ Status = STATUS_OBJECT_NAME_NOT_FOUND; } else { /* Otherwise, the caller refused us */ Status = STATUS_PORT_CONNECTION_REFUSED; } /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); /* Kill the port */ ObDereferenceObject(ClientPort); } /* Free the message */ LpcpFreeToPortZone(Message, 0); } else { /* No reply message, fail */ if (SectionToMap) ObDereferenceObject(SectionToMap); ObDereferenceObject(ClientPort); Status = STATUS_PORT_CONNECTION_REFUSED; } /* Return status */ ObDereferenceObject(Port); return Status; Cleanup: /* We failed, free the message */ SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread); /* Check if the semaphore got signaled */ if (KeReadStateSemaphore(&Thread->LpcReplySemaphore)) { /* Wait on it */ KeWaitForSingleObject(&Thread->LpcReplySemaphore, WrExecutive, KernelMode, FALSE, NULL); } /* Check if we had a message and free it */ if (Message) LpcpFreeToPortZone(Message, 0); /* Dereference other objects */ if (SectionToMap) ObDereferenceObject(SectionToMap); ObDereferenceObject(ClientPort); /* Return status */ ObDereferenceObject(Port); return Status; }
HWINSTA APIENTRY NtUserCreateWindowStation( POBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK dwDesiredAccess, DWORD Unknown2, DWORD Unknown3, DWORD Unknown4, DWORD Unknown5, DWORD Unknown6) { UNICODE_STRING WindowStationName; PWINSTATION_OBJECT WindowStationObject; HWINSTA WindowStation; NTSTATUS Status; TRACE("NtUserCreateWindowStation called\n"); Status = ObOpenObjectByName(ObjectAttributes, ExWindowStationObjectType, UserMode, NULL, dwDesiredAccess, NULL, (PVOID*)&WindowStation); if (NT_SUCCESS(Status)) { TRACE("NtUserCreateWindowStation opened window station %wZ\n", ObjectAttributes->ObjectName); return (HWINSTA)WindowStation; } /* * No existing window station found, try to create new one */ /* Capture window station name */ _SEH2_TRY { ProbeForRead( ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1); Status = IntSafeCopyUnicodeStringTerminateNULL(&WindowStationName, ObjectAttributes->ObjectName); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status =_SEH2_GetExceptionCode(); } _SEH2_END if (! NT_SUCCESS(Status)) { ERR("Failed reading capturing window station name\n"); SetLastNtError(Status); return NULL; } /* Create the window station object */ Status = ObCreateObject(UserMode, ExWindowStationObjectType, ObjectAttributes, UserMode, NULL, sizeof(WINSTATION_OBJECT), 0, 0, (PVOID*)&WindowStationObject); if (!NT_SUCCESS(Status)) { ERR("ObCreateObject failed with %lx for window station %wZ\n", Status, &WindowStationName); ExFreePoolWithTag(WindowStationName.Buffer, TAG_STRING); SetLastNtError(STATUS_INSUFFICIENT_RESOURCES); return 0; } /* Initialize the window station */ RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT)); InitializeListHead(&WindowStationObject->DesktopListHead); WindowStationObject->Name = WindowStationName; WindowStationObject->dwSessionId = NtCurrentPeb()->SessionId; Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable); if (!NT_SUCCESS(Status)) { ERR("RtlCreateAtomTable failed with %lx for window station %wZ\n", Status, &WindowStationName); ObDereferenceObject(WindowStationObject); SetLastNtError(STATUS_INSUFFICIENT_RESOURCES); return 0; } Status = ObInsertObject((PVOID)WindowStationObject, NULL, dwDesiredAccess, 0, NULL, (PVOID*)&WindowStation); if (!NT_SUCCESS(Status)) { ERR("ObInsertObject failed with %lx for window station\n", Status); SetLastNtError(STATUS_INSUFFICIENT_RESOURCES); return 0; } if (InputWindowStation == NULL) { ERR("Initializing input window station\n"); InputWindowStation = WindowStationObject; WindowStationObject->Flags &= ~WSS_NOIO; InitCursorImpl(); } else { WindowStationObject->Flags |= WSS_NOIO; } TRACE("NtUserCreateWindowStation created object %p with name %wZ handle %p\n", WindowStation, &WindowStationObject->Name, WindowStation); return WindowStation; }
NTSTATUS NtOpenThreadToken( IN HANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN BOOLEAN OpenAsSelf, OUT PHANDLE TokenHandle ) /*++ Routine Description: Open a token object associated with a thread and return a handle that may be used to access that token. Arguments: ThreadHandle - Specifies the thread whose token is to be opened. DesiredAccess - Is an access mask indicating which access types are desired to the token. These access types are reconciled with the Discretionary Access Control list of the token to determine whether the accesses will be granted or denied. OpenAsSelf - Is a boolean value indicating whether the access should be made using the calling thread's current security context, which may be that of a client if impersonating, or using the caller's process-level security context. A value of FALSE indicates the caller's current context should be used un-modified. A value of TRUE indicates the request should be fulfilled using the process level security context. This parameter is necessary to allow a server process to open a client's token when the client specified IDENTIFICATION level impersonation. In this case, the caller would not be able to open the client's token using the client's context (because you can't create executive level objects using IDENTIFICATION level impersonation). TokenHandle - Receives the handle of the newly opened token. Return Value: STATUS_SUCCESS - Indicates the operation was successful. STATUS_NO_TOKEN - Indicates an attempt has been made to open a token associated with a thread that is not currently impersonating a client. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous impersonation level. An anonymous token can not be openned. --*/ { KPROCESSOR_MODE PreviousMode; NTSTATUS Status; PVOID Token; PTOKEN NewToken = NULL; BOOLEAN CopyOnOpen; BOOLEAN EffectiveOnly; SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; SE_IMPERSONATION_STATE DisabledImpersonationState; BOOLEAN RestoreImpersonationState = FALSE; HANDLE LocalHandle; SECURITY_DESCRIPTOR SecurityDescriptor; OBJECT_ATTRIBUTES ObjectAttributes; PACL NewAcl = NULL; PETHREAD Thread; PETHREAD OriginalThread = NULL; PACCESS_TOKEN PrimaryToken; SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; PAGED_CODE(); PreviousMode = KeGetPreviousMode(); // // Probe parameters // if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(TokenHandle); } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } // end_try } //end_if // // Valdiate access to the thread and obtain a pointer to the // thread's token (if there is one). If successful, this will // cause the token's reference count to be incremented. // // This routine disabled impersonation as necessary to properly // honor the OpenAsSelf flag. // Status = SepOpenTokenOfThread( ThreadHandle, OpenAsSelf, ((PACCESS_TOKEN *)&Token), &OriginalThread, &CopyOnOpen, &EffectiveOnly, &ImpersonationLevel ); if (!NT_SUCCESS(Status)) { return Status; } // // The token was successfully referenced. // // // We need to create and/or open a token object, so disable impersonation // if necessary. // if (OpenAsSelf) { RestoreImpersonationState = PsDisableImpersonation( PsGetCurrentThread(), &DisabledImpersonationState ); } // // If the CopyOnOpen flag is not set, then the token can be // opened directly. Otherwise, the token must be duplicated, // and a handle to the duplicate returned. // if (CopyOnOpen) { // // Create the new security descriptor for the token. // // We must obtain the correct SID to put into the Dacl. Do this // by finding the process associated with the passed thread // and grabbing the User SID out of that process's token. // If we just use the current SubjectContext, we'll get the // SID of whoever is calling us, which isn't what we want. // Status = ObReferenceObjectByHandle( ThreadHandle, THREAD_ALL_ACCESS, PsThreadType, KernelMode, (PVOID)&Thread, NULL ); // // Verify that the handle is still pointer to the same thread\ // BUGBUG: wrong error code. // if (NT_SUCCESS(Status) && (Thread != OriginalThread)) { Status = STATUS_OBJECT_TYPE_MISMATCH; } if (NT_SUCCESS(Status)) { PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess); Status = SepCreateImpersonationTokenDacl( (PTOKEN)Token, PrimaryToken, &NewAcl ); PsDereferencePrimaryToken( PrimaryToken ); if (NT_SUCCESS( Status )) { if (NewAcl != NULL) { // // There exist tokens that either do not have security descriptors at all, // or have security descriptors, but do not have DACLs. In either case, do // nothing. // Status = RtlCreateSecurityDescriptor ( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); ASSERT( NT_SUCCESS( Status )); Status = RtlSetDaclSecurityDescriptor ( &SecurityDescriptor, TRUE, NewAcl, FALSE ); ASSERT( NT_SUCCESS( Status )); } InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NewAcl == NULL ? NULL : &SecurityDescriptor ); // // Open a copy of the token // Status = SepDuplicateToken( (PTOKEN)Token, // ExistingToken &ObjectAttributes, // ObjectAttributes EffectiveOnly, // EffectiveOnly TokenImpersonation, // TokenType ImpersonationLevel, // ImpersonationLevel KernelMode, // RequestorMode must be kernel mode &NewToken ); if (NT_SUCCESS( Status )) { // // Reference the token so it doesn't go away // ObReferenceObject(NewToken); // // Insert the new token // Status = ObInsertObject( NewToken, NULL, DesiredAccess, 0, (PVOID *)NULL, &LocalHandle ); } } } } else { // // We do not have to modify the security on the token in the static case, // because in all the places in the system where impersonation takes place // over a secure transport (e.g., LPC), CopyOnOpen is set. The only reason // we'be be here is if the impersonation is taking place because someone did // an NtSetInformationThread and passed in a token. // // In that case, we absolutely do not want to give the caller guaranteed // access, because that would allow anyone who has access to a thread to // impersonate any of that thread's clients for any access. // // // Open the existing token // Status = ObOpenObjectByPointer( (PVOID)Token, // Object 0, // HandleAttributes NULL, // AccessState DesiredAccess, // DesiredAccess SepTokenObjectType, // ObjectType PreviousMode, // AccessMode &LocalHandle // Handle ); } if (NewAcl != NULL) { ExFreePool( NewAcl ); } if (RestoreImpersonationState) { PsRestoreImpersonation( PsGetCurrentThread(), &DisabledImpersonationState ); } // // And decrement the reference count of the existing token to counter // the action performed by PsOpenTokenOfThread. If the open // was successful, the handle will have caused the token's // reference count to have been incremented. // ObDereferenceObject( Token ); if (NT_SUCCESS( Status ) && CopyOnOpen) { // // Assign the newly duplicated token to the thread. // PsImpersonateClient( Thread, NewToken, FALSE, // turn off CopyOnOpen flag EffectiveOnly, ImpersonationLevel ); } // // We've impersonated the token so let go of oure reference // if (NewToken != NULL) { ObDereferenceObject( NewToken ); } if (CopyOnOpen && (Thread != NULL)) { ObDereferenceObject( Thread ); } if (OriginalThread != NULL) { ObDereferenceObject(OriginalThread); } // // Return the new handle // if (NT_SUCCESS(Status)) { try { *TokenHandle = LocalHandle; } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } return Status; }
NTSTATUS ExCreateCallback ( OUT PCALLBACK_OBJECT * CallbackObject, IN POBJECT_ATTRIBUTES ObjectAttributes, IN BOOLEAN Create, IN BOOLEAN AllowMultipleCallbacks ) /*++ Routine Description: This function opens a callback object with the specified callback object. If the callback object does not exist or it is a NULL then a callback object will be created if create is TRUE. If a callbackobject is created it will only support mulitiple registered callbacks if AllowMulitipleCallbacks is TRUE. Arguments: CallbackObject - Supplies a pointer to a variable that will receive the Callback object. CallbackName - Supplies a pointer to a object name that will receive the Create - Supplies a flag which indicates whether a callback object will be created or not . AllowMultipleCallbacks - Supplies a flag which indicates only support mulitiple registered callbacks. Return Value: Returns STATUS_SUCESS unless fali... --*/ { PCALLBACK_OBJECT cbObject; NTSTATUS Status; HANDLE Handle; PAGED_CODE(); #ifndef _PNP_POWER_ return STATUS_NOT_IMPLEMENTED; #else // // If named callback, open handle to it // if (ObjectAttributes->ObjectName) { Status = ObOpenObjectByName(ObjectAttributes, ExCallbackObjectType, KernelMode, NULL, 0, // DesiredAccess, NULL, &Handle); } else { Status = STATUS_UNSUCCESSFUL; } // // If not opened, check if callback should be created // if(!NT_SUCCESS(Status) && Create ) { Status = ObCreateObject(KernelMode, ExCallbackObjectType, ObjectAttributes, KernelMode, NULL, sizeof(CALLBACK_OBJECT), 0, 0, (PVOID *)&cbObject ); if(NT_SUCCESS(Status)){ // // Fill in structure signature // cbObject->Signature = 'llaC'; // // It will support multiple registered callbacks if // AllowMultipleCallbacks is TRUE. // cbObject->AllowMultipleCallbacks = AllowMultipleCallbacks; // // Initialize CallbackObject queue. // InitializeListHead( &cbObject->RegisteredCallbacks ); // // Initialize spinlock // KeInitializeSpinLock (&cbObject->Lock); // // Put the object in the root directory // Status = ObInsertObject ( cbObject, NULL, FILE_READ_DATA, 0, NULL, &Handle ); } } if(NT_SUCCESS(Status)){ // // Add one to callback object reference count // Status = ObReferenceObjectByHandle ( Handle, 0, // DesiredAccess ExCallbackObjectType, KernelMode, &cbObject, NULL ); ZwClose (Handle); } // // If SUCEESS , returns a referenced pointer to the CallbackObject. // if (NT_SUCCESS(Status)) { *CallbackObject = cbObject; } return Status; #endif }
NTSTATUS NtCreateMutant ( OUT PHANDLE MutantHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN BOOLEAN InitialOwner ) /*++ Routine Description: This function creates a mutant object, sets its initial count to one (signaled), and opens a handle to the object with the specified desired access. Arguments: MutantHandle - Supplies a pointer to a variable that will receive the mutant object handle. DesiredAccess - Supplies the desired types of access for the mutant object. ObjectAttributes - Supplies a pointer to an object attributes structure. InitialOwner - Supplies a boolean value that determines whether the creator of the object desires immediate ownership of the object. Return Value: TBS --*/ { HANDLE Handle; PVOID Mutant; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create a mutant object. If the probe fails, then return the // exception code as the service status. Otherwise return the status value // returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(MutantHandle); } // // Allocate mutant object. // Status = ObCreateObject(PreviousMode, ExMutantObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KMUTANT), 0, 0, (PVOID *)&Mutant); // // If the mutant object was successfully allocated, then initialize // the mutant object and attempt to insert the mutant object in the // current process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeMutant((PKMUTANT)Mutant, InitialOwner); Status = ObInsertObject(Mutant, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the mutant object was successfully inserted in the current // process' handle table, then attempt to write the mutant object // handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, // an access violation will occur. // if (NT_SUCCESS(Status)) { try { *MutantHandle = Handle; } except(ExSystemExceptionFilter()) { } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS NtCreateSemaphore ( __out PHANDLE SemaphoreHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in LONG InitialCount, __in LONG MaximumCount ) /*++ Routine Description: This function creates a semaphore object, sets its initial count to the specified value, sets its maximum count to the specified value, and opens a handle to the object with the specified desired access. Arguments: SemaphoreHandle - Supplies a pointer to a variable that will receive the semaphore object handle. DesiredAccess - Supplies the desired types of access for the semaphore object. ObjectAttributes - Supplies a pointer to an object attributes structure. InitialCount - Supplies the initial count of the semaphore object. MaximumCount - Supplies the maximum count of the semaphore object. Return Value: NTSTATUS. --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; PVOID Semaphore; NTSTATUS Status; // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(SemaphoreHandle); } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } // // Check argument validity. // if ((MaximumCount <= 0) || (InitialCount < 0) || (InitialCount > MaximumCount)) { return STATUS_INVALID_PARAMETER; } // // Allocate semaphore object. // Status = ObCreateObject(PreviousMode, ExSemaphoreObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KSEMAPHORE), 0, 0, &Semaphore); // // If the semaphore object was successfully allocated, then initialize // the semaphore object and attempt to insert the semaphore object in // the current process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeSemaphore((PKSEMAPHORE)Semaphore, InitialCount, MaximumCount); Status = ObInsertObject(Semaphore, NULL, DesiredAccess, 0, NULL, &Handle); // // If the semaphore object was successfully inserted in the current // process' handle table, then attempt to write the semaphore handle // value. If the write attempt fails, then do not report an error. // When the caller attempts to access the handle value, an access // violation will occur. // if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { try { *SemaphoreHandle = Handle; } except(EXCEPTION_EXECUTE_HANDLER) { NOTHING; } } else { *SemaphoreHandle = Handle; } } }
/*++ * @name ExCreateCallback * @implemented * * Opens or creates a Callback Object. Creates only if Create is true. * Allows multiple Callback Functions to be registred only if * AllowMultipleCallbacks is true. * See: http://www.osronline.com/ddkx/kmarch/k102_967m.htm * http://www.osronline.com/article.cfm?id=24 * * @param CallbackObject * Pointer that will receive the Callback Object. * * @param CallbackName * Name of Callback * * @param Create * Determines if the object will be created if it doesn't exit * * @param AllowMultipleCallbacks * Determines if more then one registered callback function * can be attached to this Callback Object. * * @return STATUS_SUCESS if not failed. * * @remarks Must be called at IRQL = PASSIVE_LEVEL * *--*/ NTSTATUS NTAPI ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject, IN POBJECT_ATTRIBUTES ObjectAttributes, IN BOOLEAN Create, IN BOOLEAN AllowMultipleCallbacks) { PCALLBACK_OBJECT Callback = NULL; NTSTATUS Status; HANDLE Handle = NULL; PAGED_CODE(); /* Open a handle to the callback if it exists */ if (ObjectAttributes->ObjectName) { /* Open the handle */ Status = ObOpenObjectByName(ObjectAttributes, ExCallbackObjectType, KernelMode, NULL, 0, NULL, &Handle); } else { /* Otherwise, fail */ Status = STATUS_UNSUCCESSFUL; } /* We weren't able to open it...should we create it? */ if (!(NT_SUCCESS(Status)) && (Create)) { /* Create the object */ Status = ObCreateObject(KernelMode, ExCallbackObjectType, ObjectAttributes, KernelMode, NULL, sizeof(CALLBACK_OBJECT), 0, 0, (PVOID *)&Callback); if (NT_SUCCESS(Status)) { /* Set it up */ Callback->Signature = 'llaC'; KeInitializeSpinLock(&Callback->Lock); InitializeListHead(&Callback->RegisteredCallbacks); Callback->AllowMultipleCallbacks = AllowMultipleCallbacks; /* Insert the object into the object namespace */ Status = ObInsertObject(Callback, NULL, FILE_READ_DATA, 0, NULL, &Handle); } } /* Check if we have success until here */ if (NT_SUCCESS(Status)) { /* Get a pointer to the new object from the handle we just got */ Status = ObReferenceObjectByHandle(Handle, 0, ExCallbackObjectType, KernelMode, (PVOID *)&Callback, NULL); /* Close the Handle, since we now have the pointer */ ZwClose(Handle); } /* Everything went fine, so return a pointer to the Object */ if (NT_SUCCESS(Status)) { *CallbackObject = Callback; } return Status; }
NTSTATUS NTAPI PspCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle, IN PEPROCESS TargetProcess, OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, IN PINITIAL_TEB InitialTeb, IN BOOLEAN CreateSuspended, IN PKSTART_ROUTINE StartRoutine OPTIONAL, IN PVOID StartContext OPTIONAL) { HANDLE hThread; PEPROCESS Process; PETHREAD Thread; PTEB TebBase = NULL; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status, AccessStatus; HANDLE_TABLE_ENTRY CidEntry; ACCESS_STATE LocalAccessState; PACCESS_STATE AccessState = &LocalAccessState; AUX_ACCESS_DATA AuxData; BOOLEAN Result, SdAllocated; PSECURITY_DESCRIPTOR SecurityDescriptor; SECURITY_SUBJECT_CONTEXT SubjectContext; PAGED_CODE(); PSTRACE(PS_THREAD_DEBUG, "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n", ThreadContext, TargetProcess, ProcessHandle); /* If we were called from PsCreateSystemThread, then we're kernel mode */ if (StartRoutine) PreviousMode = KernelMode; /* Reference the Process by handle or pointer, depending on what we got */ if (ProcessHandle) { /* Normal thread or System Thread */ Status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_CREATE_THREAD, PsProcessType, PreviousMode, (PVOID*)&Process, NULL); PSREFTRACE(Process); } else { /* System thread inside System Process, or Normal Thread with a bug */ if (StartRoutine) { /* Reference the Process by Pointer */ ObReferenceObject(TargetProcess); Process = TargetProcess; Status = STATUS_SUCCESS; } else { /* Fake ObReference returning this */ Status = STATUS_INVALID_HANDLE; } } /* Check for success */ if (!NT_SUCCESS(Status)) return Status; /* Also make sure that User-Mode isn't trying to create a system thread */ if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) { /* Fail */ ObDereferenceObject(Process); return STATUS_INVALID_HANDLE; } /* Create Thread Object */ Status = ObCreateObject(PreviousMode, PsThreadType, ObjectAttributes, PreviousMode, NULL, sizeof(ETHREAD), 0, 0, (PVOID*)&Thread); if (!NT_SUCCESS(Status)) { /* We failed; dereference the process and exit */ ObDereferenceObject(Process); return Status; } /* Zero the Object entirely */ RtlZeroMemory(Thread, sizeof(ETHREAD)); /* Initialize rundown protection */ ExInitializeRundownProtection(&Thread->RundownProtect); /* Initialize exit code */ Thread->ExitStatus = STATUS_PENDING; /* Set the Process CID */ Thread->ThreadsProcess = Process; Thread->Cid.UniqueProcess = Process->UniqueProcessId; /* Create Cid Handle */ CidEntry.Object = Thread; CidEntry.GrantedAccess = 0; Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry); if (!Thread->Cid.UniqueThread) { /* We couldn't create the CID, dereference the thread and fail */ ObDereferenceObject(Thread); return STATUS_INSUFFICIENT_RESOURCES; } /* Save the read cluster size */ Thread->ReadClusterSize = MmReadClusterSize; /* Initialize the LPC Reply Semaphore */ KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1); /* Initialize the list heads and locks */ InitializeListHead(&Thread->LpcReplyChain); InitializeListHead(&Thread->IrpList); InitializeListHead(&Thread->PostBlockList); InitializeListHead(&Thread->ActiveTimerListHead); KeInitializeSpinLock(&Thread->ActiveTimerListLock); /* Acquire rundown protection */ if (!ExAcquireRundownProtection (&Process->RundownProtect)) { /* Fail */ ObDereferenceObject(Thread); return STATUS_PROCESS_IS_TERMINATING; } /* Now let the kernel initialize the context */ if (ThreadContext) { /* User-mode Thread, create Teb */ Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase); if (!NT_SUCCESS(Status)) { /* Failed to create the TEB. Release rundown and dereference */ ExReleaseRundownProtection(&Process->RundownProtect); ObDereferenceObject(Thread); return Status; } /* Set the Start Addresses */ Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext); Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext); /* Let the kernel intialize the Thread */ Status = KeInitThread(&Thread->Tcb, NULL, PspUserThreadStartup, NULL, Thread->StartAddress, ThreadContext, TebBase, &Process->Pcb); } else { /* System Thread */ Thread->StartAddress = StartRoutine; PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT); /* Let the kernel intialize the Thread */ Status = KeInitThread(&Thread->Tcb, NULL, PspSystemThreadStartup, StartRoutine, StartContext, NULL, NULL, &Process->Pcb); } /* Check if we failed */ if (!NT_SUCCESS(Status)) { /* Delete the TEB if we had done */ if (TebBase) MmDeleteTeb(Process, TebBase); /* Release rundown and dereference */ ExReleaseRundownProtection(&Process->RundownProtect); ObDereferenceObject(Thread); return Status; } /* Lock the process */ KeEnterCriticalRegion(); ExAcquirePushLockExclusive(&Process->ProcessLock); /* Make sure the proces didn't just die on us */ if (Process->ProcessDelete) goto Quickie; /* Check if the thread was ours, terminated and it was user mode */ if ((Thread->Terminated) && (ThreadContext) && (Thread->ThreadsProcess == Process)) { /* Cleanup, we don't want to start it up and context switch */ goto Quickie; } /* * Insert the Thread into the Process's Thread List * Note, this is the ETHREAD Thread List. It is removed in * ps/kill.c!PspExitThread. */ InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); Process->ActiveThreads++; /* Start the thread */ KeStartThread(&Thread->Tcb); /* Release the process lock */ ExReleasePushLockExclusive(&Process->ProcessLock); KeLeaveCriticalRegion(); /* Release rundown */ ExReleaseRundownProtection(&Process->RundownProtect); /* Notify WMI */ //WmiTraceProcess(Process, TRUE); //WmiTraceThread(Thread, InitialTeb, TRUE); /* Notify Thread Creation */ PspRunCreateThreadNotifyRoutines(Thread, TRUE); /* Reference ourselves as a keep-alive */ ObReferenceObjectEx(Thread, 2); /* Suspend the Thread if we have to */ if (CreateSuspended) KeSuspendThread(&Thread->Tcb); /* Check if we were already terminated */ if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb); /* Create an access state */ Status = SeCreateAccessStateEx(NULL, ThreadContext ? PsGetCurrentProcess() : Process, &LocalAccessState, &AuxData, DesiredAccess, &PsThreadType->TypeInfo.GenericMapping); if (!NT_SUCCESS(Status)) { /* Access state failed, thread is dead */ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); /* If we were suspended, wake it up */ if (CreateSuspended) KeResumeThread(&Thread->Tcb); /* Dispatch thread */ KeReadyThread(&Thread->Tcb); /* Dereference completely to kill it */ ObDereferenceObjectEx(Thread, 2); return Status; } /* Insert the Thread into the Object Manager */ Status = ObInsertObject(Thread, AccessState, DesiredAccess, 0, NULL, &hThread); /* Delete the access state if we had one */ if (AccessState) SeDeleteAccessState(AccessState); /* Check for success */ if (NT_SUCCESS(Status)) { /* Wrap in SEH to protect against bad user-mode pointers */ _SEH2_TRY { /* Return Cid and Handle */ if (ClientId) *ClientId = Thread->Cid; *ThreadHandle = hThread; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Thread insertion failed, thread is dead */ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); /* If we were suspended, wake it up */ if (CreateSuspended) KeResumeThread(&Thread->Tcb); /* Dispatch thread */ KeReadyThread(&Thread->Tcb); /* Dereference it, leaving only the keep-alive */ ObDereferenceObject(Thread); /* Close its handle, killing it */ ObCloseHandle(ThreadHandle, PreviousMode); /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else {