1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/lpc/create.c 5 * PURPOSE: Local Procedure Call: Port/Queue/Message Creation 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* PRIVATE FUNCTIONS *********************************************************/ 16 17 NTSTATUS 18 NTAPI 19 LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port) 20 { 21 PLPCP_NONPAGED_PORT_QUEUE MessageQueue; 22 23 PAGED_CODE(); 24 25 /* Allocate the queue */ 26 MessageQueue = ExAllocatePoolWithTag(NonPagedPool, 27 sizeof(*MessageQueue), 28 'troP'); 29 if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES; 30 31 /* Set it up */ 32 KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG); 33 MessageQueue->BackPointer = Port; 34 35 /* And link it with the Paged Pool part */ 36 Port->MsgQueue.Semaphore = &MessageQueue->Semaphore; 37 InitializeListHead(&Port->MsgQueue.ReceiveHead); 38 return STATUS_SUCCESS; 39 } 40 41 NTSTATUS 42 NTAPI 43 LpcpCreatePort(OUT PHANDLE PortHandle, 44 IN POBJECT_ATTRIBUTES ObjectAttributes, 45 IN ULONG MaxConnectionInfoLength, 46 IN ULONG MaxMessageLength, 47 IN ULONG MaxPoolUsage, 48 IN BOOLEAN Waitable) 49 { 50 NTSTATUS Status; 51 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 52 UNICODE_STRING CapturedObjectName, *ObjectName; 53 PLPCP_PORT_OBJECT Port; 54 HANDLE Handle; 55 56 PAGED_CODE(); 57 LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName); 58 59 RtlInitEmptyUnicodeString(&CapturedObjectName, NULL, 0); 60 61 /* Check if the call comes from user mode */ 62 if (PreviousMode != KernelMode) 63 { 64 _SEH2_TRY 65 { 66 /* Probe the PortHandle */ 67 ProbeForWriteHandle(PortHandle); 68 69 /* Probe the ObjectAttributes and its object name (not the buffer) */ 70 ProbeForRead(ObjectAttributes, sizeof(*ObjectAttributes), sizeof(ULONG)); 71 ObjectName = ((volatile OBJECT_ATTRIBUTES*)ObjectAttributes)->ObjectName; 72 if (ObjectName) 73 { 74 ProbeForRead(ObjectName, sizeof(*ObjectName), 1); 75 CapturedObjectName = *(volatile UNICODE_STRING*)ObjectName; 76 } 77 } 78 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 79 { 80 /* Return the exception code */ 81 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 82 } 83 _SEH2_END; 84 } 85 else 86 { 87 if (ObjectAttributes->ObjectName) 88 CapturedObjectName = *(ObjectAttributes->ObjectName); 89 } 90 91 /* Normalize the buffer pointer in case we don't have a name */ 92 if (CapturedObjectName.Length == 0) 93 CapturedObjectName.Buffer = NULL; 94 95 /* Create the Object */ 96 Status = ObCreateObject(PreviousMode, 97 LpcPortObjectType, 98 ObjectAttributes, 99 PreviousMode, 100 NULL, 101 sizeof(LPCP_PORT_OBJECT), 102 0, 103 0, 104 (PVOID*)&Port); 105 if (!NT_SUCCESS(Status)) return Status; 106 107 /* Set up the Object */ 108 RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT)); 109 Port->ConnectionPort = Port; 110 Port->Creator = PsGetCurrentThread()->Cid; 111 InitializeListHead(&Port->LpcDataInfoChainHead); 112 InitializeListHead(&Port->LpcReplyChainHead); 113 114 /* Check if we don't have a name */ 115 if (CapturedObjectName.Buffer == NULL) 116 { 117 /* Set up for an unconnected port */ 118 Port->Flags = LPCP_UNCONNECTED_PORT; 119 Port->ConnectedPort = Port; 120 Port->ServerProcess = NULL; 121 } 122 else 123 { 124 /* Set up for a named connection port */ 125 Port->Flags = LPCP_CONNECTION_PORT; 126 Port->ServerProcess = PsGetCurrentProcess(); 127 128 /* Don't let the process die on us */ 129 ObReferenceObject(Port->ServerProcess); 130 } 131 132 /* Check if this is a waitable port */ 133 if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT; 134 135 /* Setup the port queue */ 136 Status = LpcpInitializePortQueue(Port); 137 if (!NT_SUCCESS(Status)) 138 { 139 /* Fail */ 140 ObDereferenceObject(Port); 141 return Status; 142 } 143 144 /* Check if this is a waitable port */ 145 if (Port->Flags & LPCP_WAITABLE_PORT) 146 { 147 /* Setup the wait event */ 148 KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE); 149 } 150 151 /* Set the maximum message size allowed */ 152 Port->MaxMessageLength = LpcpMaxMessageSize - 153 FIELD_OFFSET(LPCP_MESSAGE, Request); 154 155 /* Now subtract the actual message structures and get the data size */ 156 Port->MaxConnectionInfoLength = Port->MaxMessageLength - 157 sizeof(PORT_MESSAGE) - 158 sizeof(LPCP_CONNECTION_MESSAGE); 159 160 /* Validate the sizes */ 161 if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength) 162 { 163 /* Not enough space for your request */ 164 ObDereferenceObject(Port); 165 return STATUS_INVALID_PARAMETER_3; 166 } 167 else if (Port->MaxMessageLength < MaxMessageLength) 168 { 169 /* Not enough space for your request */ 170 ObDereferenceObject(Port); 171 return STATUS_INVALID_PARAMETER_4; 172 } 173 174 /* Now set the custom setting */ 175 Port->MaxMessageLength = MaxMessageLength; 176 177 /* Insert it now */ 178 Status = ObInsertObject(Port, 179 NULL, 180 PORT_ALL_ACCESS, 181 0, 182 NULL, 183 &Handle); 184 if (NT_SUCCESS(Status)) 185 { 186 _SEH2_TRY 187 { 188 /* Write back the handle, pointer was already probed */ 189 *PortHandle = Handle; 190 } 191 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 192 { 193 /* An exception happened, close the opened handle */ 194 ObCloseHandle(Handle, PreviousMode); 195 Status = _SEH2_GetExceptionCode(); 196 } 197 _SEH2_END; 198 } 199 200 /* Return success or the error */ 201 LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %p\n", Port, Handle); 202 return Status; 203 } 204 205 /* PUBLIC FUNCTIONS **********************************************************/ 206 207 /* 208 * @implemented 209 */ 210 NTSTATUS 211 NTAPI 212 NtCreatePort(OUT PHANDLE PortHandle, 213 IN POBJECT_ATTRIBUTES ObjectAttributes, 214 IN ULONG MaxConnectInfoLength, 215 IN ULONG MaxDataLength, 216 IN ULONG MaxPoolUsage) 217 { 218 PAGED_CODE(); 219 220 /* Call the internal API */ 221 return LpcpCreatePort(PortHandle, 222 ObjectAttributes, 223 MaxConnectInfoLength, 224 MaxDataLength, 225 MaxPoolUsage, 226 FALSE); 227 } 228 229 /* 230 * @implemented 231 */ 232 NTSTATUS 233 NTAPI 234 NtCreateWaitablePort(OUT PHANDLE PortHandle, 235 IN POBJECT_ATTRIBUTES ObjectAttributes, 236 IN ULONG MaxConnectInfoLength, 237 IN ULONG MaxDataLength, 238 IN ULONG MaxPoolUsage) 239 { 240 PAGED_CODE(); 241 242 /* Call the internal API */ 243 return LpcpCreatePort(PortHandle, 244 ObjectAttributes, 245 MaxConnectInfoLength, 246 MaxDataLength, 247 MaxPoolUsage, 248 TRUE); 249 } 250 251 /* EOF */ 252