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