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