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 #if DBG 54 UNICODE_STRING CapturedPortName; 55 #endif 56 PLPCP_PORT_OBJECT Port; 57 HANDLE Handle; 58 59 PAGED_CODE(); 60 61 RtlInitEmptyUnicodeString(&CapturedObjectName, NULL, 0); 62 63 /* Check if the call comes from user mode */ 64 if (PreviousMode != KernelMode) 65 { 66 _SEH2_TRY 67 { 68 /* Probe the PortHandle */ 69 ProbeForWriteHandle(PortHandle); 70 71 /* Probe the ObjectAttributes and its object name (not the buffer) */ 72 ProbeForRead(ObjectAttributes, sizeof(*ObjectAttributes), sizeof(ULONG)); 73 ObjectName = ((volatile OBJECT_ATTRIBUTES*)ObjectAttributes)->ObjectName; 74 if (ObjectName) 75 CapturedObjectName = ProbeForReadUnicodeString(ObjectName); 76 } 77 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 78 { 79 /* Return the exception code */ 80 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 81 } 82 _SEH2_END; 83 } 84 else 85 { 86 if (ObjectAttributes->ObjectName) 87 CapturedObjectName = *(ObjectAttributes->ObjectName); 88 } 89 90 /* Normalize the buffer pointer in case we don't have 91 * a name, for initializing an unconnected port. */ 92 if (CapturedObjectName.Length == 0) 93 CapturedObjectName.Buffer = NULL; 94 95 #if DBG 96 /* Capture the port name for DPRINT only - ObCreateObject does its 97 * own capture. As it is used only for debugging, ignore any failure; 98 * the string is zeroed out in such case. */ 99 ProbeAndCaptureUnicodeString(&CapturedPortName, PreviousMode, &CapturedObjectName); 100 LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", &CapturedPortName); 101 ReleaseCapturedUnicodeString(&CapturedPortName, PreviousMode); 102 #endif 103 104 /* Create the Object */ 105 Status = ObCreateObject(PreviousMode, 106 LpcPortObjectType, 107 ObjectAttributes, 108 PreviousMode, 109 NULL, 110 sizeof(LPCP_PORT_OBJECT), 111 0, 112 0, 113 (PVOID*)&Port); 114 if (!NT_SUCCESS(Status)) return Status; 115 116 /* Set up the Object */ 117 RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT)); 118 Port->ConnectionPort = Port; 119 Port->Creator = PsGetCurrentThread()->Cid; 120 InitializeListHead(&Port->LpcDataInfoChainHead); 121 InitializeListHead(&Port->LpcReplyChainHead); 122 123 /* Check if we don't have a name */ 124 if (CapturedObjectName.Buffer == NULL) 125 { 126 /* Set up for an unconnected port */ 127 Port->Flags = LPCP_UNCONNECTED_PORT; 128 Port->ConnectedPort = Port; 129 Port->ServerProcess = NULL; 130 } 131 else 132 { 133 /* Set up for a named connection port */ 134 Port->Flags = LPCP_CONNECTION_PORT; 135 Port->ServerProcess = PsGetCurrentProcess(); 136 137 /* Don't let the process die on us */ 138 ObReferenceObject(Port->ServerProcess); 139 } 140 141 /* Check if this is a waitable port */ 142 if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT; 143 144 /* Setup the port queue */ 145 Status = LpcpInitializePortQueue(Port); 146 if (!NT_SUCCESS(Status)) 147 { 148 /* Fail */ 149 ObDereferenceObject(Port); 150 return Status; 151 } 152 153 /* Check if this is a waitable port */ 154 if (Port->Flags & LPCP_WAITABLE_PORT) 155 { 156 /* Setup the wait event */ 157 KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE); 158 } 159 160 /* Set the maximum message size allowed */ 161 Port->MaxMessageLength = LpcpMaxMessageSize - 162 FIELD_OFFSET(LPCP_MESSAGE, Request); 163 164 /* Now subtract the actual message structures and get the data size */ 165 Port->MaxConnectionInfoLength = Port->MaxMessageLength - 166 sizeof(PORT_MESSAGE) - 167 sizeof(LPCP_CONNECTION_MESSAGE); 168 169 /* Validate the sizes */ 170 if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength) 171 { 172 /* Not enough space for your request */ 173 ObDereferenceObject(Port); 174 return STATUS_INVALID_PARAMETER_3; 175 } 176 else if (Port->MaxMessageLength < MaxMessageLength) 177 { 178 /* Not enough space for your request */ 179 ObDereferenceObject(Port); 180 return STATUS_INVALID_PARAMETER_4; 181 } 182 183 /* Now set the custom setting */ 184 Port->MaxMessageLength = MaxMessageLength; 185 186 /* Insert it now */ 187 Status = ObInsertObject(Port, 188 NULL, 189 PORT_ALL_ACCESS, 190 0, 191 NULL, 192 &Handle); 193 if (NT_SUCCESS(Status)) 194 { 195 _SEH2_TRY 196 { 197 /* Write back the handle, pointer was already probed */ 198 *PortHandle = Handle; 199 } 200 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 201 { 202 /* An exception happened, close the opened handle */ 203 ObCloseHandle(Handle, PreviousMode); 204 Status = _SEH2_GetExceptionCode(); 205 } 206 _SEH2_END; 207 } 208 209 /* Return success or the error */ 210 LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %p\n", Port, Handle); 211 return Status; 212 } 213 214 /* PUBLIC FUNCTIONS **********************************************************/ 215 216 /* 217 * @implemented 218 */ 219 NTSTATUS 220 NTAPI 221 NtCreatePort(OUT PHANDLE PortHandle, 222 IN POBJECT_ATTRIBUTES ObjectAttributes, 223 IN ULONG MaxConnectInfoLength, 224 IN ULONG MaxDataLength, 225 IN ULONG MaxPoolUsage) 226 { 227 PAGED_CODE(); 228 229 /* Call the internal API */ 230 return LpcpCreatePort(PortHandle, 231 ObjectAttributes, 232 MaxConnectInfoLength, 233 MaxDataLength, 234 MaxPoolUsage, 235 FALSE); 236 } 237 238 /* 239 * @implemented 240 */ 241 NTSTATUS 242 NTAPI 243 NtCreateWaitablePort(OUT PHANDLE PortHandle, 244 IN POBJECT_ATTRIBUTES ObjectAttributes, 245 IN ULONG MaxConnectInfoLength, 246 IN ULONG MaxDataLength, 247 IN ULONG MaxPoolUsage) 248 { 249 PAGED_CODE(); 250 251 /* Call the internal API */ 252 return LpcpCreatePort(PortHandle, 253 ObjectAttributes, 254 MaxConnectInfoLength, 255 MaxDataLength, 256 MaxPoolUsage, 257 TRUE); 258 } 259 260 /* EOF */ 261