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.

336 lines
8.7 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. lpcpriv.c
  5. Abstract:
  6. Local Inter-Process Communication priviledged procedures that implement
  7. client impersonation.
  8. Author:
  9. Steve Wood (stevewo) 15-Nov-1989
  10. Revision History:
  11. --*/
  12. #include "lpcp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE,LpcpFreePortClientSecurity)
  15. #pragma alloc_text(PAGE,NtImpersonateClientOfPort)
  16. #endif
  17. NTSTATUS
  18. NtImpersonateClientOfPort (
  19. IN HANDLE PortHandle,
  20. IN PPORT_MESSAGE Message
  21. )
  22. /*++
  23. Routine Description:
  24. This procedure is used by the server thread to temporarily acquire the
  25. identifier set of a client thread.
  26. This service establishes an impersonation token for the calling thread.
  27. The impersonation token corresponds to the context provided by the port
  28. client. The client must currently be waiting for a reply to the
  29. specified message.
  30. This service returns an error status code if the client thread is not
  31. waiting for a reply to the message. The security quality of service
  32. parameters specified by the client upon connection dictate what use the
  33. server will have of the client's security context.
  34. For complicated or extended impersonation needs, the server may open a
  35. copy of the client's token (using NtOpenThreadToken()). This must be
  36. done while impersonating the client.
  37. Arguments:
  38. PortHandle - Specifies the handle of the communication port that the
  39. message was received from.
  40. Message - Specifies an address of a message that was received from the
  41. client that is to be impersonated. The ClientId field of the message
  42. identifies the client thread that is to be impersonated. The client
  43. thread must be waiting for a reply to the message in order to
  44. impersonate the client.
  45. Return Value:
  46. NTSTATUS - Status code that indicates whether or not the operation was
  47. successful.
  48. --*/
  49. {
  50. PLPCP_PORT_OBJECT PortObject;
  51. PLPCP_PORT_OBJECT ConnectedPort;
  52. KPROCESSOR_MODE PreviousMode;
  53. NTSTATUS Status;
  54. PETHREAD ClientThread;
  55. CLIENT_ID CapturedClientId;
  56. ULONG CapturedMessageId;
  57. SECURITY_CLIENT_CONTEXT DynamicSecurity;
  58. PAGED_CODE();
  59. //
  60. // Get previous processor mode and probe output arguments if necessary.
  61. //
  62. PreviousMode = KeGetPreviousMode();
  63. if (PreviousMode != KernelMode) {
  64. try {
  65. ProbeForReadSmallStructure( Message, sizeof( PORT_MESSAGE ), sizeof( ULONG ));
  66. CapturedClientId = Message->ClientId;
  67. CapturedMessageId = Message->MessageId;
  68. } except( EXCEPTION_EXECUTE_HANDLER ) {
  69. return( GetExceptionCode() );
  70. }
  71. } else {
  72. CapturedClientId = Message->ClientId;
  73. CapturedMessageId = Message->MessageId;
  74. }
  75. //
  76. // Reference the communication port object by handle. Return status if
  77. // unsuccessful.
  78. //
  79. Status = LpcpReferencePortObject( PortHandle, 0,
  80. PreviousMode, &PortObject );
  81. if (!NT_SUCCESS( Status )) {
  82. return( Status );
  83. }
  84. //
  85. // It is an error to try this on any port other than a server
  86. // communication port
  87. //
  88. if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) {
  89. ObDereferenceObject( PortObject );
  90. return( STATUS_INVALID_PORT_HANDLE );
  91. }
  92. //
  93. // Translate the ClientId from the connection request into a
  94. // thread pointer. This is a referenced pointer to keep the thread
  95. // from evaporating out from under us.
  96. //
  97. Status = PsLookupProcessThreadByCid( &CapturedClientId,
  98. NULL,
  99. &ClientThread );
  100. if (!NT_SUCCESS( Status )) {
  101. ObDereferenceObject( PortObject );
  102. return( Status );
  103. }
  104. //
  105. // Acquire the mutex that guards the LpcReplyMessage field of
  106. // the thread and get the pointer to the message that the thread
  107. // is waiting for a reply to.
  108. //
  109. LpcpAcquireLpcpLock();
  110. //
  111. // The connected port can be in a state with 0 references in a deletion process.
  112. // We need to test this case while referencing it.
  113. //
  114. ConnectedPort = PortObject->ConnectedPort;
  115. if ( ( ConnectedPort == NULL ) ||
  116. ( !ObReferenceObjectSafe( ConnectedPort ) ) ) {
  117. //
  118. // The port is being deleted. Quit this function with
  119. // appropriate return status.
  120. // We don't need to dereference the connected port because
  121. // it is anyway about to be deleted
  122. //
  123. LpcpReleaseLpcpLock();
  124. ObDereferenceObject( PortObject );
  125. ObDereferenceObject( ClientThread );
  126. return( STATUS_PORT_DISCONNECTED );
  127. }
  128. //
  129. // See if the thread is waiting for a reply to the message
  130. // specified on this call, if the user gave us a bad
  131. // message id. If not then a bogus message
  132. // has been specified, so return failure.
  133. //
  134. //
  135. // The W2k fix searched the client thread in the rundown queue, to make sure
  136. // we are not impersonating a port from a different connection. Ones we added the port
  137. // to the thread structure to fix other security issues for reply os accessing data
  138. // we can use that easy test for the impersonation too, w/o searching the rundown queue
  139. //
  140. if ((ClientThread->LpcReplyMessageId != CapturedMessageId)
  141. ||
  142. (CapturedMessageId == 0)
  143. ||
  144. (!LpcpValidateClientPort( ClientThread,
  145. PortObject,
  146. LPCP_VALIDATE_REASON_IMPERSONATION)) ) {
  147. LpcpReleaseLpcpLock();
  148. ObDereferenceObject( PortObject );
  149. ObDereferenceObject( ClientThread );
  150. ObDereferenceObject( ConnectedPort );
  151. return (STATUS_REPLY_MESSAGE_MISMATCH);
  152. }
  153. //
  154. // Test whether the client allows impersonation for this message or not.
  155. //
  156. if (LpcpGetThreadAttributes(ClientThread) & LPCP_NO_IMPERSONATION) {
  157. LpcpReleaseLpcpLock();
  158. ObDereferenceObject( PortObject );
  159. ObDereferenceObject( ClientThread );
  160. ObDereferenceObject( ConnectedPort );
  161. return (STATUS_ACCESS_DENIED);
  162. }
  163. LpcpReleaseLpcpLock();
  164. //
  165. // If the client requested dynamic security tracking, then the client
  166. // security needs to be referenced. Otherwise, (static case)
  167. // it is already in the client's port.
  168. //
  169. if (ConnectedPort->Flags & PORT_DYNAMIC_SECURITY) {
  170. //
  171. // Impersonate the client with information from the queued message
  172. //
  173. Status = LpcpGetDynamicClientSecurity( ClientThread,
  174. ConnectedPort,
  175. &DynamicSecurity );
  176. if (!NT_SUCCESS( Status )) {
  177. ObDereferenceObject( PortObject );
  178. ObDereferenceObject( ClientThread );
  179. ObDereferenceObject( ConnectedPort );
  180. return( Status );
  181. }
  182. Status = SeImpersonateClientEx( &DynamicSecurity, NULL );
  183. LpcpFreeDynamicClientSecurity( &DynamicSecurity );
  184. } else {
  185. //
  186. // Impersonate the client with information from the client's port
  187. //
  188. Status = SeImpersonateClientEx( &ConnectedPort->StaticSecurity, NULL );
  189. }
  190. ObDereferenceObject( PortObject );
  191. ObDereferenceObject( ClientThread );
  192. ObDereferenceObject( ConnectedPort );
  193. //
  194. // And return to our caller
  195. //
  196. return Status;
  197. }
  198. VOID
  199. LpcpFreePortClientSecurity (
  200. IN PLPCP_PORT_OBJECT Port
  201. )
  202. /*++
  203. Routine Description:
  204. This routine cleans up the captured security context for a client port.
  205. The cleanup is typically done when we are deleting a port
  206. Arguments:
  207. Port - Supplies the client port being deleted
  208. Return Value:
  209. None.
  210. --*/
  211. {
  212. //
  213. // We only do this action if supplied with a client communication port
  214. //
  215. if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) {
  216. //
  217. // We only do this action if the port has static security tracking,
  218. // and we have a captured client token. The action is to simply
  219. // delete the client token.
  220. //
  221. if (!(Port->Flags & PORT_DYNAMIC_SECURITY)) {
  222. if ( Port->StaticSecurity.ClientToken ) {
  223. SeDeleteClientSecurity( &(Port)->StaticSecurity );
  224. }
  225. }
  226. }
  227. //
  228. // And return to our caller
  229. //
  230. return;
  231. }