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