xref: /reactos/ntoskrnl/lpc/create.c (revision 7d2f6b65)
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