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
LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)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
LpcpCreatePort(OUT PHANDLE PortHandle,IN POBJECT_ATTRIBUTES ObjectAttributes,IN ULONG MaxConnectionInfoLength,IN ULONG MaxMessageLength,IN ULONG MaxPoolUsage,IN BOOLEAN Waitable)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
NtCreatePort(OUT PHANDLE PortHandle,IN POBJECT_ATTRIBUTES ObjectAttributes,IN ULONG MaxConnectInfoLength,IN ULONG MaxDataLength,IN ULONG MaxPoolUsage)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
NtCreateWaitablePort(OUT PHANDLE PortHandle,IN POBJECT_ATTRIBUTES ObjectAttributes,IN ULONG MaxConnectInfoLength,IN ULONG MaxDataLength,IN ULONG MaxPoolUsage)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