Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

460 lines
12 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. lpccreat.c
  5. Abstract:
  6. Local Inter-Process Communication (LPC) connection system services.
  7. Author:
  8. Steve Wood (stevewo) 15-May-1989
  9. Revision History:
  10. --*/
  11. #include "lpcp.h"
  12. //
  13. // Local procedure prototype
  14. //
  15. NTSTATUS
  16. LpcpCreatePort (
  17. OUT PHANDLE PortHandle,
  18. IN POBJECT_ATTRIBUTES ObjectAttributes,
  19. IN ULONG MaxConnectionInfoLength,
  20. IN ULONG MaxMessageLength,
  21. IN ULONG MaxPoolUsage,
  22. IN BOOLEAN Waitable
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(PAGE,NtCreatePort)
  26. #pragma alloc_text(PAGE,NtCreateWaitablePort)
  27. #pragma alloc_text(PAGE,LpcpCreatePort)
  28. #endif
  29. NTSTATUS
  30. NtCreatePort (
  31. OUT PHANDLE PortHandle,
  32. IN POBJECT_ATTRIBUTES ObjectAttributes,
  33. IN ULONG MaxConnectionInfoLength,
  34. IN ULONG MaxMessageLength,
  35. IN ULONG MaxPoolUsage
  36. )
  37. /*++
  38. Routine Description:
  39. See LpcpCreatePort.
  40. Arguments:
  41. See LpcpCreatePort.
  42. Return Value:
  43. NTSTATUS - An appropriate status value
  44. --*/
  45. {
  46. NTSTATUS Status;
  47. PAGED_CODE();
  48. Status = LpcpCreatePort( PortHandle,
  49. ObjectAttributes,
  50. MaxConnectionInfoLength,
  51. MaxMessageLength,
  52. MaxPoolUsage,
  53. FALSE );
  54. return Status ;
  55. }
  56. NTSTATUS
  57. NtCreateWaitablePort (
  58. OUT PHANDLE PortHandle,
  59. IN POBJECT_ATTRIBUTES ObjectAttributes,
  60. IN ULONG MaxConnectionInfoLength,
  61. IN ULONG MaxMessageLength,
  62. IN ULONG MaxPoolUsage
  63. )
  64. /*++
  65. Routine Description:
  66. Same as NtCreatePort.
  67. The only difference between this call and NtCreatePort is that the
  68. working KEVENT that can be used to wait for LPC messages to arrive
  69. asynchronously.
  70. Arguments:
  71. See LpcpCreatePort.
  72. Return Value:
  73. NTSTATUS - An appropriate status value
  74. --*/
  75. {
  76. NTSTATUS Status ;
  77. PAGED_CODE();
  78. Status = LpcpCreatePort( PortHandle,
  79. ObjectAttributes,
  80. MaxConnectionInfoLength,
  81. MaxMessageLength,
  82. MaxPoolUsage,
  83. TRUE );
  84. return Status ;
  85. }
  86. //
  87. // Local support routine
  88. //
  89. NTSTATUS
  90. LpcpCreatePort (
  91. OUT PHANDLE PortHandle,
  92. IN POBJECT_ATTRIBUTES ObjectAttributes,
  93. IN ULONG MaxConnectionInfoLength,
  94. IN ULONG MaxMessageLength,
  95. IN ULONG MaxPoolUsage,
  96. IN BOOLEAN Waitable
  97. )
  98. /*++
  99. Routine Description:
  100. A server process can create a named connection port with the NtCreatePort
  101. service.
  102. A connection port is created with the name and SECURITY_DESCRIPTOR
  103. specified in the ObjectAttributes structure. A handle to the connection
  104. port object is returned in the location pointed to by the PortHandle
  105. parameter. The returned handle can then be used to listen for connection
  106. requests to that port name, using the NtListenPort service.
  107. The standard object architecture defined desired access parameter is not
  108. necessary since this service can only create a new port, not access an
  109. existing port.
  110. Connection ports cannot be used to send and receive messages. They are
  111. only valid as a parameter to the NtListenPort service.
  112. Arguments:
  113. PortHandle - A pointer to a variable that will receive the connection port
  114. object handle value.
  115. ObjectAttributes - A pointer to a structure that specifies the name of the
  116. object, an access control list (SECURITY_DESCRIPTOR) to be applied to
  117. the object, and a set of object attribute flags.
  118. PUNICODE_STRING ObjectName - An optional pointer to a null terminated
  119. port name string. The form of the name is
  120. [\name...\name]\port_name. If no name is specified then an
  121. unconnected communication port is created rather than a connection
  122. port. This is useful for sending and receiving messages between
  123. threads of a single process.
  124. ULONG Attributes - A set of flags that control the port object
  125. attributes.
  126. None of the standard values are relevant for this call.
  127. Connection ports cannot be inherited, are always placed in the
  128. system handle table and are exclusive to the creating process.
  129. This field must be zero. Future implementations might support
  130. specifying the OBJ_PERMANENT attribute.
  131. MaxMessageLength - Specifies the maximum length of messages sent or
  132. received on communication ports created from this connection
  133. port. The value of this parameter cannot exceed
  134. MAX_PORTMSG_LENGTH bytes.
  135. MaxPoolUsage - Specifies the maximum amount of NonPaged pool used for
  136. message storage.
  137. Waitable - Specifies if the event used by the port can be use to wait
  138. for LPC messages to arrive asynchronously.
  139. Return Value:
  140. NTSTATUS - An appropriate status value
  141. --*/
  142. {
  143. PLPCP_PORT_OBJECT ConnectionPort;
  144. HANDLE Handle;
  145. KPROCESSOR_MODE PreviousMode;
  146. NTSTATUS Status;
  147. PUNICODE_STRING NamePtr;
  148. UNICODE_STRING CapturedObjectName;
  149. PAGED_CODE();
  150. UNREFERENCED_PARAMETER (MaxPoolUsage);
  151. //
  152. // Get previous processor mode and probe output arguments if necessary.
  153. //
  154. PreviousMode = KeGetPreviousMode();
  155. RtlInitUnicodeString( &CapturedObjectName, NULL );
  156. if (PreviousMode != KernelMode) {
  157. try {
  158. ProbeForWriteHandle( PortHandle );
  159. ProbeForReadSmallStructure( ObjectAttributes,
  160. sizeof( OBJECT_ATTRIBUTES ),
  161. sizeof( ULONG ));
  162. NamePtr = ObjectAttributes->ObjectName;
  163. if (NamePtr != NULL) {
  164. CapturedObjectName = ProbeAndReadStructure( NamePtr,
  165. UNICODE_STRING );
  166. }
  167. } except( EXCEPTION_EXECUTE_HANDLER ) {
  168. return( GetExceptionCode() );
  169. }
  170. } else {
  171. if (ObjectAttributes->ObjectName != NULL) {
  172. CapturedObjectName = *(ObjectAttributes->ObjectName);
  173. }
  174. }
  175. //
  176. // Make the null buffer indicate an unspecified port name
  177. //
  178. if (CapturedObjectName.Length == 0) {
  179. CapturedObjectName.Buffer = NULL;
  180. }
  181. //
  182. // Allocate and initialize a port object. If an object name was
  183. // specified, then this is a connection port. Otherwise this is an
  184. // unconnected communication port that a process can use to communicate
  185. // between threads.
  186. //
  187. Status = ObCreateObject( PreviousMode,
  188. (Waitable ? LpcWaitablePortObjectType
  189. : LpcPortObjectType),
  190. ObjectAttributes,
  191. PreviousMode,
  192. NULL,
  193. (Waitable ? sizeof( LPCP_PORT_OBJECT )
  194. : FIELD_OFFSET( LPCP_PORT_OBJECT, WaitEvent )),
  195. 0,
  196. 0,
  197. (PVOID *)&ConnectionPort );
  198. if (!NT_SUCCESS( Status )) {
  199. return( Status );
  200. }
  201. //
  202. // Zero out the connection port object and then initialize its fields
  203. //
  204. RtlZeroMemory( ConnectionPort, (Waitable ? sizeof( LPCP_PORT_OBJECT )
  205. : FIELD_OFFSET( LPCP_PORT_OBJECT, WaitEvent )));
  206. ConnectionPort->ConnectionPort = ConnectionPort;
  207. ConnectionPort->Creator = PsGetCurrentThread()->Cid;
  208. InitializeListHead( &ConnectionPort->LpcReplyChainHead );
  209. InitializeListHead( &ConnectionPort->LpcDataInfoChainHead );
  210. //
  211. // Named ports get a connection message queue.
  212. //
  213. if (CapturedObjectName.Buffer == NULL) {
  214. ConnectionPort->Flags = UNCONNECTED_COMMUNICATION_PORT;
  215. ConnectionPort->ConnectedPort = ConnectionPort;
  216. ConnectionPort->ServerProcess = NULL;
  217. } else {
  218. ConnectionPort->Flags = SERVER_CONNECTION_PORT;
  219. ObReferenceObject( PsGetCurrentProcess() );
  220. ConnectionPort->ServerProcess = PsGetCurrentProcess();
  221. }
  222. if ( Waitable ) {
  223. ConnectionPort->Flags |= PORT_WAITABLE;
  224. }
  225. //
  226. // All ports get a request message queue.
  227. //
  228. Status = LpcpInitializePortQueue( ConnectionPort );
  229. if (!NT_SUCCESS(Status)) {
  230. ObDereferenceObject( ConnectionPort );
  231. return(Status);
  232. }
  233. //
  234. // For a waitable port, create the KEVENT that will
  235. // be used to signal clients
  236. //
  237. if (ConnectionPort->Flags & PORT_WAITABLE) {
  238. KeInitializeEvent( &ConnectionPort->WaitEvent,
  239. NotificationEvent,
  240. FALSE );
  241. }
  242. //
  243. // Set the maximum message length and connection info length based on the
  244. // zone block size less the structs overhead.
  245. //
  246. ConnectionPort->MaxMessageLength = (USHORT) (LpcpGetMaxMessageLength() -
  247. FIELD_OFFSET( LPCP_MESSAGE, Request ));
  248. ConnectionPort->MaxConnectionInfoLength = (USHORT) (ConnectionPort->MaxMessageLength -
  249. sizeof( PORT_MESSAGE ) -
  250. sizeof( LPCP_CONNECTION_MESSAGE ));
  251. #if DBG
  252. LpcpTrace(( "Created port %ws (%x) - MaxMsgLen == %x MaxConnectInfoLen == %x\n",
  253. CapturedObjectName.Buffer == NULL ? L"** UnNamed **" : ObjectAttributes->ObjectName->Buffer,
  254. ConnectionPort,
  255. ConnectionPort->MaxMessageLength,
  256. ConnectionPort->MaxConnectionInfoLength ));
  257. #endif
  258. //
  259. // Sanity check that the max message length being asked for is not
  260. // greater than the max message length possible in the system
  261. //
  262. if (ConnectionPort->MaxMessageLength < MaxMessageLength) {
  263. #if DBG
  264. LpcpPrint(( "MaxMessageLength granted is %x but requested %x\n",
  265. ConnectionPort->MaxMessageLength,
  266. MaxMessageLength ));
  267. #endif
  268. ObDereferenceObject( ConnectionPort );
  269. return STATUS_INVALID_PARAMETER_4;
  270. }
  271. //
  272. // Save the MaxMessageLength to the connection port
  273. //
  274. ConnectionPort->MaxMessageLength = (USHORT) MaxMessageLength;
  275. //
  276. // Sanity check that the max connection info length being asked for is
  277. // not greater than the maximum possible in the system
  278. //
  279. if (ConnectionPort->MaxConnectionInfoLength < MaxConnectionInfoLength) {
  280. #if DBG
  281. LpcpPrint(( "MaxConnectionInfoLength granted is %x but requested %x\n",
  282. ConnectionPort->MaxConnectionInfoLength,
  283. MaxConnectionInfoLength ));
  284. #endif
  285. ObDereferenceObject( ConnectionPort );
  286. return STATUS_INVALID_PARAMETER_3;
  287. }
  288. //
  289. // NTRAID 539413: Save the max connection length to the port
  290. //
  291. ConnectionPort->MaxConnectionInfoLength = (USHORT)MaxConnectionInfoLength;
  292. //
  293. // Insert connection port object in specified object table. Set port
  294. // handle value if successful. If not successful, then the port will
  295. // have been dereferenced, which will cause it to be freed, after our
  296. // delete procedure is called. The delete procedure will undo the work
  297. // done to initialize the port. Finally, return the system server status.
  298. //
  299. Status = ObInsertObject( ConnectionPort,
  300. NULL,
  301. PORT_ALL_ACCESS,
  302. 0,
  303. (PVOID *)NULL,
  304. &Handle );
  305. if (NT_SUCCESS( Status )) {
  306. //
  307. // Set the output variable protected against access faults
  308. //
  309. try {
  310. *PortHandle = Handle;
  311. } except( EXCEPTION_EXECUTE_HANDLER ) {
  312. NtClose( Handle );
  313. Status = GetExceptionCode();
  314. }
  315. }
  316. //
  317. // And return to our caller
  318. //
  319. return Status;
  320. }