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.

563 lines
15 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. msgapi.cxx
  5. Abstract:
  6. The I_RpcSendReceive API used to send and receive messages as part of
  7. a remote procedure call lives here. This API is used by both clients
  8. (to make calls) and by servers (to make callbacks).
  9. Author:
  10. Michael Montague (mikemon) 07-Nov-1991
  11. Revision History:
  12. Mazhar Mohammed (mazharm) 09-11-95 added I_RpcReceive, I_RpcSend
  13. Mazhar Mohammed (mazharm) 03-31-96 added support for async RPC
  14. I_RpcAsyncSend and I_RpcAsyncReceive
  15. Revision History:
  16. --*/
  17. #include <precomp.hxx>
  18. #define _SND_RECV_CALLED 0x100
  19. RPC_STATUS RPC_ENTRY
  20. I_RpcSendReceive (
  21. IN OUT PRPC_MESSAGE Message
  22. )
  23. /*++
  24. Routine Description:
  25. We do all of the protocol module independent work of making a remote
  26. procedure call; at least the part concerned with sending the request
  27. and receiving the response. The majority of the work is done by
  28. each rpc protocol module.
  29. Arguments:
  30. Message - Supplies and returns the information required to make
  31. the remote procedure call.
  32. Return Values:
  33. RPC_S_OK - The operation completed successfully.
  34. --*/
  35. {
  36. RPC_STATUS retval;
  37. THREAD *Thread;
  38. AssertRpcInitialized();
  39. ASSERT(!RpcpCheckHeap());
  40. Thread = ThreadSelf();
  41. if (!Thread)
  42. {
  43. return RPC_S_OUT_OF_MEMORY;
  44. }
  45. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  46. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
  47. ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
  48. ASSERT( Message->Buffer != 0 );
  49. ASSERT( !COMPLETE(Message) );
  50. retval = MObject->SendReceive(Message);
  51. ASSERT(!RpcpCheckHeap());
  52. // Insure that the buffer is aligned on an eight byte boundary.
  53. #ifdef DEBUGRPC
  54. if ( retval == RPC_S_OK )
  55. {
  56. ASSERT( (((ULONG_PTR) Message->Buffer) % 8) == 0);
  57. // uncomment this to check for 16 byte alignment on 64 bits
  58. // ASSERT( IsBufferAligned(Message->Buffer) );
  59. }
  60. #endif // DEBUGRPC
  61. return(retval);
  62. }
  63. RPC_STATUS RPC_ENTRY
  64. I_RpcSend (
  65. IN OUT PRPC_MESSAGE Message
  66. )
  67. /*++
  68. Routine Description:
  69. This API is used in conjunction with pipes. This is used to send the marshalled
  70. parameters and the marshalled pipe data.
  71. Client: If the RPC_BUFFER_PARTIAL bit is set in Message->RpcFlags,
  72. this routine returns as soon as the buffer is sent. If the
  73. bit is not set, this routine blocks until the first reply fragment arrives.
  74. Server: The send always treated as a partial send.
  75. Arguments:
  76. Message - Supplies the information required to send the request
  77. Return Values:
  78. RPC_S_OK - The operation completed successfully.
  79. RPC_S_SEND_INCOMPLETE - The complete data wasn't sent, Message->Buffer
  80. points to the remaining data and Message->BufferLength indicates the length of the
  81. remaining data. Any additional data needs to be appended to the
  82. end of the buffer.
  83. --*/
  84. {
  85. RPC_STATUS retval;
  86. THREAD *Thread;
  87. PVOID MessageBuffer;
  88. AssertRpcInitialized();
  89. ASSERT(!RpcpCheckHeap());
  90. Thread = ThreadSelf();
  91. if (!Thread)
  92. {
  93. HANDLE_TYPE HandleType = ((CALL *) Message->Handle)->Type(CALL_TYPE);
  94. // ThreadSelf can fail for client calls only, since for server calls
  95. // the thread object would have already been allocated by the runtime.
  96. // If Message is partial and async, then NDR will assume that the runtime
  97. // has already cleaned up. Therefore, if this is a partial async message
  98. // then we need to clean up the call object and the buffer to avoid the leak.
  99. if (PARTIAL(Message) &&
  100. (HandleType & CCALL_TYPE) &&
  101. ASYNC(Message))
  102. {
  103. ((MESSAGE_OBJECT *)Message->Handle)->FreeBuffer(Message);
  104. }
  105. return RPC_S_OUT_OF_MEMORY;
  106. }
  107. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  108. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
  109. ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
  110. MessageBuffer = Message->Buffer;
  111. ASSERT( MessageBuffer != 0 );
  112. if (ASYNC(Message))
  113. {
  114. retval = MObject->AsyncSend(Message);
  115. }
  116. else
  117. {
  118. retval = MObject->Send(Message);
  119. }
  120. ASSERT(!RpcpCheckHeap());
  121. // Insure that the buffer is aligned on an eight byte boundary.
  122. #ifdef DEBUGRPC
  123. if ( retval == RPC_S_OK )
  124. {
  125. ASSERT( (((ULONG_PTR) MessageBuffer) % 8) == 0);
  126. // uncomment this to check for 16 byte alignment on 64 bits
  127. //ASSERT( IsBufferAligned(MessageBuffer) );
  128. }
  129. #endif // DEBUGRPC
  130. return(retval);
  131. }
  132. RPC_STATUS RPC_ENTRY
  133. I_RpcReceive (
  134. IN OUT PRPC_MESSAGE Message,
  135. IN unsigned int Size
  136. )
  137. /*++
  138. Routine Description:
  139. This routine is used in conjunction with pipes. If the RPC_BUFFER_PARTIAL bit
  140. is set in Message->RpcFlags, this call blocks until some data is received. Size is
  141. used as a hint of how much data the caller is requesting. If the partial bit is not set,
  142. this call blocks until the complete buffer is received.
  143. Arguments:
  144. Message - Supplies the information required to make the receive
  145. Size - used as a hint to indicate the amount of data needed by the caller
  146. Return Values:
  147. RPC_S_OK - The operation completed successfully.
  148. --*/
  149. {
  150. RPC_STATUS retval;
  151. THREAD *Thread;
  152. AssertRpcInitialized();
  153. ASSERT(!RpcpCheckHeap());
  154. Thread = ThreadSelf();
  155. if (!Thread)
  156. {
  157. return RPC_S_OUT_OF_MEMORY;
  158. }
  159. RpcpPurgeEEInfoFromThreadIfNecessary(Thread);
  160. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
  161. ASSERT( MObject->InvalidHandle(CALL_TYPE) == 0 );
  162. //
  163. // Temp hack
  164. // Need to get Ryszard to fix
  165. // the NDR engine to never ask for 0 bytes
  166. // We can then change this to an ASSERT
  167. // ASSERT(Size)
  168. //
  169. if (Size == 0)
  170. Size = 1;
  171. if (ASYNC(Message))
  172. {
  173. retval = MObject->AsyncReceive(Message, Size);
  174. }
  175. else
  176. {
  177. retval = MObject->Receive(Message, Size);
  178. }
  179. ASSERT(!RpcpCheckHeap());
  180. // Insure that the buffer is aligned on an eight byte boundary.
  181. #ifdef DEBUGRPC
  182. if ( retval == RPC_S_OK )
  183. {
  184. ASSERT( (((ULONG_PTR) Message->Buffer) % 8) == 0);
  185. // uncomment this to check for 16 byte alignment on 64 bits
  186. // ASSERT( IsBufferAligned(Message->Buffer) );
  187. }
  188. #endif // DEBUGRPC
  189. return(retval);
  190. }
  191. RPC_STATUS RPC_ENTRY
  192. I_RpcAsyncSetHandle (
  193. IN PRPC_MESSAGE Message,
  194. IN PRPC_ASYNC_STATE pAsync
  195. )
  196. /*++
  197. This API is called on the client and server side. If this API is called on the
  198. server, runtime assumes that the call is async
  199. we will add more params later.
  200. --*/
  201. {
  202. RPC_STATUS retval;
  203. AssertRpcInitialized();
  204. ASSERT(!RpcpCheckHeap());
  205. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) Message->Handle;
  206. if (MObject->InvalidHandle(CALL_TYPE))
  207. {
  208. ASSERT(0);
  209. return (RPC_S_INVALID_BINDING);
  210. }
  211. #if DBG
  212. if (!MObject->InvalidHandle(CCALL_TYPE))
  213. {
  214. // if we end up with invalid pAsync here, this means we were either
  215. // called by a private test, or COM. Both should know better. The
  216. // public APIs should pass through NDR and NDR already should have
  217. // validated the parameters.
  218. ASSERT((pAsync->Lock == 0) || (pAsync->Lock == 1));
  219. }
  220. #endif
  221. retval = MObject->SetAsyncHandle(pAsync);
  222. if (retval == RPC_S_OK)
  223. {
  224. pAsync->RuntimeInfo = (void *) MObject;
  225. }
  226. ASSERT(!RpcpCheckHeap());
  227. return(retval);
  228. }
  229. RPC_STATUS RPC_ENTRY
  230. I_RpcAsyncAbortCall (
  231. IN PRPC_ASYNC_STATE pAsync,
  232. IN unsigned long ExceptionCode
  233. )
  234. /*++
  235. Routine Description:
  236. Arguments:
  237. pAsync - the async handle being registered
  238. Return Value:
  239. RPC_S_OK - the call succeeded.
  240. RPC_S_INVALID_HANDLE - the handle was bad.
  241. --*/
  242. {
  243. MESSAGE_OBJECT *MObject = (MESSAGE_OBJECT *) pAsync->RuntimeInfo;
  244. if (!ThreadSelf())
  245. {
  246. return RPC_S_OUT_OF_MEMORY;
  247. }
  248. if (MObject)
  249. {
  250. if (MObject->InvalidHandle(CALL_TYPE))
  251. {
  252. ASSERT(0);
  253. return (RPC_S_INVALID_BINDING);
  254. }
  255. return ((CALL *) MObject)->AbortAsyncCall(pAsync, ExceptionCode);
  256. }
  257. return RPC_S_INVALID_ASYNC_HANDLE;
  258. }
  259. #ifdef __cplusplus
  260. extern "C" {
  261. #endif
  262. const RPC_CHAR *SecurityString = RPC_CONST_STRING("security=");
  263. const int SecurityStringLength = sizeof("security=") - 1; // in characters without terminating NULL
  264. const RPC_CHAR *DynamicString = RPC_CONST_STRING("dynamic");
  265. const int DynamicStringLength = sizeof("dynamic") - 1; // in characters without terminating NULL
  266. const RPC_CHAR *StaticString = RPC_CONST_STRING("static");
  267. const int StaticStringLength = sizeof("static") - 1; // in characters without terminating NULL
  268. const RPC_CHAR *TrueString = RPC_CONST_STRING("true");
  269. const int TrueStringLength = sizeof("true") - 1; // in characters without terminating NULL
  270. const RPC_CHAR *FalseString = RPC_CONST_STRING("false");
  271. const int FalseStringLength = sizeof("false") - 1; // in characters without terminating NULL
  272. const RPC_CHAR *AnonymousString = RPC_CONST_STRING("anonymous");
  273. const int AnonymousStringLength = sizeof("anonymous") - 1; // in characters without terminating NULL
  274. const RPC_CHAR *IdentificationString = RPC_CONST_STRING("identification");
  275. const int IdentificationStringLength = sizeof("identification") - 1; // in characters without terminating NULL
  276. const RPC_CHAR *ImpersonationString = RPC_CONST_STRING("impersonation");
  277. const int ImpersonationStringLength = sizeof("impersonation") - 1; // in characters without terminating NULL
  278. const RPC_CHAR *DelegationString = RPC_CONST_STRING("delegation");
  279. const int DelegationStringLength = sizeof("delegation") - 1; // in characters without terminating NULL
  280. RPC_STATUS
  281. I_RpcParseSecurity (
  282. IN RPC_CHAR * NetworkOptions,
  283. OUT SECURITY_QUALITY_OF_SERVICE * SecurityQualityOfService
  284. )
  285. /*++
  286. Routine Description:
  287. Parse a string of security options and build into the binary format
  288. required by the operating system. The network options must follow
  289. the following syntax. Case is not sensitive.
  290. security=
  291. [anonymous|identification|impersonation|delegation]
  292. [dynamic|static]
  293. [true|false]
  294. All three fields must be present. To specify impersonation
  295. with dynamic tracking and effective only, use the following
  296. string for the network options.
  297. "security=impersonation dynamic true"
  298. Arguments:
  299. NetworkOptions - Supplies the string containing the network options
  300. to be parsed.
  301. SecurityQualityOfService - Returns the binary format of the network
  302. options.
  303. Return Value:
  304. RPC_S_OK - The network options have been correctly parsed into binary
  305. format.
  306. RPC_S_INVALID_NETWORK_OPTIONS - The network options are invalid and
  307. cannot be parsed.
  308. --*/
  309. {
  310. ASSERT(NetworkOptions[0] != 0);
  311. // We need to parse the security information from the network
  312. // options, and then stuff it into the object attributes. To
  313. // begin with, we check for "security=" at the beginning of
  314. // the network options.
  315. if (RpcpStringNCompare(NetworkOptions, SecurityString,
  316. SecurityStringLength) != 0)
  317. {
  318. return(RPC_S_INVALID_NETWORK_OPTIONS);
  319. }
  320. NetworkOptions += SecurityStringLength;
  321. // Ok, now we need to determine if the next field is one of
  322. // Anonymous, Identification, Impersonation, or Delegation.
  323. if (RpcpStringNCompare(NetworkOptions, AnonymousString,
  324. AnonymousStringLength) == 0)
  325. {
  326. SecurityQualityOfService->ImpersonationLevel = SecurityAnonymous;
  327. NetworkOptions += AnonymousStringLength;
  328. }
  329. else if (RpcpStringNCompare(NetworkOptions, IdentificationString,
  330. IdentificationStringLength) == 0)
  331. {
  332. SecurityQualityOfService->ImpersonationLevel = SecurityIdentification;
  333. NetworkOptions += IdentificationStringLength;
  334. }
  335. else if (RpcpStringNCompare(NetworkOptions, ImpersonationString,
  336. ImpersonationStringLength) == 0)
  337. {
  338. SecurityQualityOfService->ImpersonationLevel = SecurityImpersonation;
  339. NetworkOptions += ImpersonationStringLength;
  340. }
  341. else if (RpcpStringNCompare(NetworkOptions, DelegationString,
  342. DelegationStringLength) == 0)
  343. {
  344. SecurityQualityOfService->ImpersonationLevel = SecurityDelegation;
  345. NetworkOptions += DelegationStringLength;
  346. }
  347. else
  348. {
  349. return(RPC_S_INVALID_NETWORK_OPTIONS);
  350. }
  351. if (*NetworkOptions != RPC_CONST_CHAR(' '))
  352. {
  353. return(RPC_S_INVALID_NETWORK_OPTIONS);
  354. }
  355. NetworkOptions++;
  356. // Next comes the context tracking field; it must be one of
  357. // dynamic or static.
  358. if (RpcpStringNCompare(NetworkOptions, DynamicString,
  359. DynamicStringLength) == 0)
  360. {
  361. SecurityQualityOfService->ContextTrackingMode =
  362. SECURITY_DYNAMIC_TRACKING;
  363. NetworkOptions += DynamicStringLength;
  364. }
  365. else if (RpcpStringNCompare(NetworkOptions, StaticString,
  366. StaticStringLength) == 0)
  367. {
  368. SecurityQualityOfService->ContextTrackingMode =
  369. SECURITY_STATIC_TRACKING;
  370. NetworkOptions += StaticStringLength;
  371. }
  372. else
  373. {
  374. return(RPC_S_INVALID_NETWORK_OPTIONS);
  375. }
  376. if (*NetworkOptions != RPC_CONST_CHAR(' '))
  377. {
  378. return(RPC_S_INVALID_NETWORK_OPTIONS);
  379. }
  380. NetworkOptions++;
  381. // Finally, comes the effective only flag. This must be one of
  382. // true or false.
  383. if (RpcpStringNCompare(NetworkOptions, TrueString,
  384. TrueStringLength) == 0)
  385. {
  386. SecurityQualityOfService->EffectiveOnly = TRUE;
  387. NetworkOptions += TrueStringLength;
  388. }
  389. else if (RpcpStringNCompare(NetworkOptions, FalseString,
  390. FalseStringLength) == 0)
  391. {
  392. SecurityQualityOfService->EffectiveOnly = FALSE;
  393. NetworkOptions += FalseStringLength;
  394. }
  395. else
  396. {
  397. return(RPC_S_INVALID_NETWORK_OPTIONS);
  398. }
  399. if (*NetworkOptions != 0)
  400. {
  401. return(RPC_S_INVALID_NETWORK_OPTIONS);
  402. }
  403. SecurityQualityOfService->Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  404. return(RPC_S_OK);
  405. }
  406. #ifdef __cplusplus
  407. }
  408. #endif