xref: /reactos/dll/win32/rpcrt4/rpc_server.c (revision da5f10af)
1 /*
2  * RPC server API
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  * Copyright 2004 Filip Navara
6  * Copyright 2006-2008 Robert Shearman (for CodeWeavers)
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 #include "config.h"
24 #include "wine/port.h"
25 
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30 
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34 
35 #include "rpc.h"
36 #include "rpcndr.h"
37 #include "excpt.h"
38 
39 #include "wine/debug.h"
40 #include "wine/exception.h"
41 
42 #include "rpc_server.h"
43 #include "rpc_assoc.h"
44 #include "rpc_message.h"
45 #include "rpc_defs.h"
46 #include "ncastatus.h"
47 #include "secext.h"
48 
49 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
50 
51 typedef struct _RpcPacket
52 {
53   struct _RpcConnection* conn;
54   RpcPktHdr* hdr;
55   RPC_MESSAGE* msg;
56   unsigned char *auth_data;
57   ULONG auth_length;
58 } RpcPacket;
59 
60 typedef struct _RpcObjTypeMap
61 {
62   /* FIXME: a hash table would be better. */
63   struct _RpcObjTypeMap *next;
64   UUID Object;
65   UUID Type;
66 } RpcObjTypeMap;
67 
68 static RpcObjTypeMap *RpcObjTypeMaps;
69 
70 /* list of type RpcServerProtseq */
71 static struct list protseqs = LIST_INIT(protseqs);
72 static struct list server_interfaces = LIST_INIT(server_interfaces);
73 static struct list server_registered_auth_info = LIST_INIT(server_registered_auth_info);
74 
75 static CRITICAL_SECTION server_cs;
76 static CRITICAL_SECTION_DEBUG server_cs_debug =
77 {
78     0, 0, &server_cs,
79     { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },
80       0, 0, { (DWORD_PTR)(__FILE__ ": server_cs") }
81 };
82 static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };
83 
84 static CRITICAL_SECTION listen_cs;
85 static CRITICAL_SECTION_DEBUG listen_cs_debug =
86 {
87     0, 0, &listen_cs,
88     { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },
89       0, 0, { (DWORD_PTR)(__FILE__ ": listen_cs") }
90 };
91 static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };
92 
93 static CRITICAL_SECTION server_auth_info_cs;
94 static CRITICAL_SECTION_DEBUG server_auth_info_cs_debug =
95 {
96     0, 0, &server_auth_info_cs,
97     { &server_auth_info_cs_debug.ProcessLocksList, &server_auth_info_cs_debug.ProcessLocksList },
98       0, 0, { (DWORD_PTR)(__FILE__ ": server_auth_info_cs") }
99 };
100 static CRITICAL_SECTION server_auth_info_cs = { &server_auth_info_cs_debug, -1, 0, 0, 0, 0 };
101 
102 /* whether the server is currently listening */
103 static BOOL std_listen;
104 /* total listeners including auto listeners */
105 static LONG listen_count;
106 /* event set once all manual listening is finished */
107 static HANDLE listen_done_event;
108 
109 static UUID uuid_nil;
110 
111 static inline RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid)
112 {
113   RpcObjTypeMap *rslt = RpcObjTypeMaps;
114   RPC_STATUS dummy;
115 
116   while (rslt) {
117     if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break;
118     rslt = rslt->next;
119   }
120 
121   return rslt;
122 }
123 
124 static inline UUID *LookupObjType(UUID *ObjUuid)
125 {
126   RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid);
127   if (map)
128     return &map->Type;
129   else
130     return &uuid_nil;
131 }
132 
133 static RpcServerInterface* RPCRT4_find_interface(UUID* object,
134                                                  const RPC_SYNTAX_IDENTIFIER *if_id,
135                                                  const RPC_SYNTAX_IDENTIFIER *transfer_syntax,
136                                                  BOOL check_object)
137 {
138   UUID* MgrType = NULL;
139   RpcServerInterface* cif;
140   RPC_STATUS status;
141 
142   if (check_object)
143     MgrType = LookupObjType(object);
144   EnterCriticalSection(&server_cs);
145   LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) {
146     if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) &&
147         (!transfer_syntax || !memcmp(transfer_syntax, &cif->If->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER))) &&
148         (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) &&
149         std_listen) {
150       InterlockedIncrement(&cif->CurrentCalls);
151       break;
152     }
153   }
154   LeaveCriticalSection(&server_cs);
155   if (&cif->entry == &server_interfaces) cif = NULL;
156   TRACE("returning %p for object %s, if_id { %d.%d %s }\n", cif,
157     debugstr_guid(object), if_id->SyntaxVersion.MajorVersion,
158     if_id->SyntaxVersion.MinorVersion, debugstr_guid(&if_id->SyntaxGUID));
159   return cif;
160 }
161 
162 static void RPCRT4_release_server_interface(RpcServerInterface *sif)
163 {
164   if (!InterlockedDecrement(&sif->CurrentCalls) &&
165       sif->Delete) {
166     /* sif must have been removed from server_interfaces before
167      * CallsCompletedEvent is set */
168     if (sif->CallsCompletedEvent)
169       SetEvent(sif->CallsCompletedEvent);
170     HeapFree(GetProcessHeap(), 0, sif);
171   }
172 }
173 
174 static RpcPktHdr *handle_bind_error(RpcConnection *conn, RPC_STATUS error)
175 {
176     unsigned int reject_reason;
177     switch (error)
178     {
179     case RPC_S_SERVER_TOO_BUSY:
180         reject_reason = REJECT_TEMPORARY_CONGESTION;
181         break;
182     case ERROR_OUTOFMEMORY:
183     case RPC_S_OUT_OF_RESOURCES:
184         reject_reason = REJECT_LOCAL_LIMIT_EXCEEDED;
185         break;
186     case RPC_S_PROTOCOL_ERROR:
187         reject_reason = REJECT_PROTOCOL_VERSION_NOT_SUPPORTED;
188         break;
189     case RPC_S_UNKNOWN_AUTHN_SERVICE:
190         reject_reason = REJECT_UNKNOWN_AUTHN_SERVICE;
191         break;
192     case ERROR_ACCESS_DENIED:
193         reject_reason = REJECT_INVALID_CHECKSUM;
194         break;
195     default:
196         FIXME("unexpected status value %d\n", error);
197         /* fall through */
198     case RPC_S_INVALID_BOUND:
199         reject_reason = REJECT_REASON_NOT_SPECIFIED;
200         break;
201     }
202     return RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
203                                       RPC_VER_MAJOR, RPC_VER_MINOR,
204                                       reject_reason);
205 }
206 
207 static RPC_STATUS process_bind_packet_no_send(
208     RpcConnection *conn, RpcPktBindHdr *hdr, RPC_MESSAGE *msg,
209     unsigned char *auth_data, ULONG auth_length, RpcPktHdr **ack_response,
210     unsigned char **auth_data_out, ULONG *auth_length_out)
211 {
212   RPC_STATUS status;
213   RpcContextElement *ctxt_elem;
214   unsigned int i;
215   RpcResult *results;
216 
217   /* validate data */
218   for (i = 0, ctxt_elem = msg->Buffer;
219        i < hdr->num_elements;
220        i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes])
221   {
222       if (((char *)ctxt_elem - (char *)msg->Buffer) > msg->BufferLength ||
223           ((char *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes] - (char *)msg->Buffer) > msg->BufferLength)
224       {
225           ERR("inconsistent data in packet - packet length %d, num elements %d\n",
226               msg->BufferLength, hdr->num_elements);
227           return RPC_S_INVALID_BOUND;
228       }
229   }
230 
231   if (hdr->max_tsize < RPC_MIN_PACKET_SIZE ||
232       !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status) ||
233       conn->server_binding)
234   {
235     TRACE("packet size less than min size, or active interface syntax guid non-null\n");
236 
237     return RPC_S_INVALID_BOUND;
238   }
239 
240   results = HeapAlloc(GetProcessHeap(), 0,
241                       hdr->num_elements * sizeof(*results));
242   if (!results)
243     return RPC_S_OUT_OF_RESOURCES;
244 
245   for (i = 0, ctxt_elem = (RpcContextElement *)msg->Buffer;
246        i < hdr->num_elements;
247        i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes])
248   {
249       RpcServerInterface* sif = NULL;
250       unsigned int j;
251 
252       for (j = 0; !sif && j < ctxt_elem->num_syntaxes; j++)
253       {
254           sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax,
255                                       &ctxt_elem->transfer_syntaxes[j], FALSE);
256           if (sif)
257               break;
258       }
259       if (sif)
260       {
261           RPCRT4_release_server_interface(sif);
262           TRACE("accepting bind request on connection %p for %s\n", conn,
263                 debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
264           results[i].result = RESULT_ACCEPT;
265           results[i].reason = REASON_NONE;
266           results[i].transfer_syntax = ctxt_elem->transfer_syntaxes[j];
267 
268           /* save the interface for later use */
269           /* FIXME: save linked list */
270           conn->ActiveInterface = ctxt_elem->abstract_syntax;
271       }
272       else if ((sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax,
273                                             NULL, FALSE)) != NULL)
274       {
275           RPCRT4_release_server_interface(sif);
276           TRACE("not accepting bind request on connection %p for %s - no transfer syntaxes supported\n",
277                 conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
278           results[i].result = RESULT_PROVIDER_REJECTION;
279           results[i].reason = REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED;
280           memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax));
281       }
282       else
283       {
284           TRACE("not accepting bind request on connection %p for %s - abstract syntax not supported\n",
285                 conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
286           results[i].result = RESULT_PROVIDER_REJECTION;
287           results[i].reason = REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
288           memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax));
289       }
290   }
291 
292   /* create temporary binding */
293   status = RPCRT4_MakeBinding(&conn->server_binding, conn);
294   if (status != RPC_S_OK)
295   {
296       HeapFree(GetProcessHeap(), 0, results);
297       return status;
298   }
299 
300   status = RpcServerAssoc_GetAssociation(rpcrt4_conn_get_name(conn),
301                                          conn->NetworkAddr, conn->Endpoint,
302                                          conn->NetworkOptions,
303                                          hdr->assoc_gid,
304                                          &conn->server_binding->Assoc);
305   if (status != RPC_S_OK)
306   {
307       HeapFree(GetProcessHeap(), 0, results);
308       return status;
309   }
310 
311   if (auth_length)
312   {
313       status = RPCRT4_ServerConnectionAuth(conn, TRUE,
314                                            (RpcAuthVerifier *)auth_data,
315                                            auth_length, auth_data_out,
316                                            auth_length_out);
317       if (status != RPC_S_OK)
318       {
319           HeapFree(GetProcessHeap(), 0, results);
320           return status;
321       }
322   }
323 
324   *ack_response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
325                                             RPC_MAX_PACKET_SIZE,
326                                             RPC_MAX_PACKET_SIZE,
327                                             conn->server_binding->Assoc->assoc_group_id,
328                                             conn->Endpoint, hdr->num_elements,
329                                             results);
330   HeapFree(GetProcessHeap(), 0, results);
331 
332   if (*ack_response)
333       conn->MaxTransmissionSize = hdr->max_tsize;
334   else
335       status = RPC_S_OUT_OF_RESOURCES;
336 
337   return status;
338 }
339 
340 static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr,
341                                       RPC_MESSAGE *msg,
342                                       unsigned char *auth_data,
343                                       ULONG auth_length)
344 {
345     RPC_STATUS status;
346     RpcPktHdr *response = NULL;
347     unsigned char *auth_data_out = NULL;
348     ULONG auth_length_out = 0;
349 
350     status = process_bind_packet_no_send(conn, hdr, msg, auth_data, auth_length,
351                                          &response, &auth_data_out,
352                                          &auth_length_out);
353     if (status != RPC_S_OK)
354         response = handle_bind_error(conn, status);
355     if (response)
356         status = RPCRT4_SendWithAuth(conn, response, NULL, 0, auth_data_out, auth_length_out);
357     else
358         status = ERROR_OUTOFMEMORY;
359     RPCRT4_FreeHeader(response);
360 
361     return status;
362 }
363 
364 
365 static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr *hdr, RPC_MESSAGE *msg)
366 {
367   RPC_STATUS status;
368   RpcPktHdr *response = NULL;
369   RpcServerInterface* sif;
370   RPC_DISPATCH_FUNCTION func;
371   BOOL exception;
372   UUID *object_uuid;
373   NDR_SCONTEXT context_handle;
374   void *buf = msg->Buffer;
375 
376   /* fail if the connection isn't bound with an interface */
377   if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
378     /* FIXME: should send BindNack instead */
379     response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
380                                        status);
381 
382     RPCRT4_Send(conn, response, NULL, 0);
383     RPCRT4_FreeHeader(response);
384     return RPC_S_OK;
385   }
386 
387   if (hdr->common.flags & RPC_FLG_OBJECT_UUID) {
388     object_uuid = (UUID*)(hdr + 1);
389   } else {
390     object_uuid = NULL;
391   }
392 
393   sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, NULL, TRUE);
394   if (!sif) {
395     WARN("interface %s no longer registered, returning fault packet\n", debugstr_guid(&conn->ActiveInterface.SyntaxGUID));
396     response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
397                                        NCA_S_UNK_IF);
398 
399     RPCRT4_Send(conn, response, NULL, 0);
400     RPCRT4_FreeHeader(response);
401     return RPC_S_OK;
402   }
403   msg->RpcInterfaceInformation = sif->If;
404   /* copy the endpoint vector from sif to msg so that midl-generated code will use it */
405   msg->ManagerEpv = sif->MgrEpv;
406   if (object_uuid != NULL) {
407     RPCRT4_SetBindingObject(msg->Handle, object_uuid);
408   }
409 
410   /* find dispatch function */
411   msg->ProcNum = hdr->opnum;
412   if (sif->Flags & RPC_IF_OLE) {
413     /* native ole32 always gives us a dispatch table with a single entry
414     * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
415     func = *sif->If->DispatchTable->DispatchTable;
416   } else {
417     if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
418       WARN("invalid procnum (%d/%d)\n", msg->ProcNum, sif->If->DispatchTable->DispatchTableCount);
419       response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
420                                          NCA_S_OP_RNG_ERROR);
421 
422       RPCRT4_Send(conn, response, NULL, 0);
423       RPCRT4_FreeHeader(response);
424     }
425     func = sif->If->DispatchTable->DispatchTable[msg->ProcNum];
426   }
427 
428   /* put in the drep. FIXME: is this more universally applicable?
429     perhaps we should move this outward... */
430   msg->DataRepresentation =
431     MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]),
432               MAKEWORD(hdr->common.drep[2], hdr->common.drep[3]));
433 
434   exception = FALSE;
435 
436   /* dispatch */
437   RPCRT4_SetThreadCurrentCallHandle(msg->Handle);
438   __TRY {
439     if (func) func(msg);
440   } __EXCEPT_ALL {
441     WARN("exception caught with code 0x%08x = %d\n", GetExceptionCode(), GetExceptionCode());
442     exception = TRUE;
443     if (GetExceptionCode() == STATUS_ACCESS_VIOLATION)
444       status = ERROR_NOACCESS;
445     else
446       status = GetExceptionCode();
447     response = RPCRT4_BuildFaultHeader(msg->DataRepresentation,
448                                        RPC2NCA_STATUS(status));
449   } __ENDTRY
450     RPCRT4_SetThreadCurrentCallHandle(NULL);
451 
452   /* release any unmarshalled context handles */
453   while ((context_handle = RPCRT4_PopThreadContextHandle()) != NULL)
454     RpcServerAssoc_ReleaseContextHandle(conn->server_binding->Assoc, context_handle, TRUE);
455 
456   if (!exception)
457     response = RPCRT4_BuildResponseHeader(msg->DataRepresentation,
458                                           msg->BufferLength);
459 
460   /* send response packet */
461   if (response) {
462     status = RPCRT4_Send(conn, response, exception ? NULL : msg->Buffer,
463                          exception ? 0 : msg->BufferLength);
464     RPCRT4_FreeHeader(response);
465   } else
466     ERR("out of memory\n");
467 
468   msg->RpcInterfaceInformation = NULL;
469   RPCRT4_release_server_interface(sif);
470 
471   if (msg->Buffer == buf) buf = NULL;
472   TRACE("freeing Buffer=%p\n", buf);
473   I_RpcFree(buf);
474 
475   return status;
476 }
477 
478 static RPC_STATUS process_auth3_packet(RpcConnection *conn,
479                                        RpcPktCommonHdr *hdr,
480                                        RPC_MESSAGE *msg,
481                                        unsigned char *auth_data,
482                                        ULONG auth_length)
483 {
484     RPC_STATUS status;
485 
486     if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status) ||
487         !auth_length || msg->BufferLength != 0)
488         status = RPC_S_PROTOCOL_ERROR;
489     else
490     {
491         status = RPCRT4_ServerConnectionAuth(conn, FALSE,
492                                              (RpcAuthVerifier *)auth_data,
493                                              auth_length, NULL, NULL);
494     }
495 
496     /* FIXME: client doesn't expect a response to this message so must store
497      * status in connection so that fault packet can be returned when next
498      * packet is received */
499 
500     return RPC_S_OK;
501 }
502 
503 static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr,
504                                   RPC_MESSAGE* msg, unsigned char *auth_data,
505                                   ULONG auth_length)
506 {
507   msg->Handle = (RPC_BINDING_HANDLE)conn->server_binding;
508 
509   switch (hdr->common.ptype) {
510     case PKT_BIND:
511       TRACE("got bind packet\n");
512       process_bind_packet(conn, &hdr->bind, msg, auth_data, auth_length);
513       break;
514 
515     case PKT_REQUEST:
516       TRACE("got request packet\n");
517       process_request_packet(conn, &hdr->request, msg);
518       break;
519 
520     case PKT_AUTH3:
521       TRACE("got auth3 packet\n");
522       process_auth3_packet(conn, &hdr->common, msg, auth_data, auth_length);
523       break;
524     default:
525       FIXME("unhandled packet type %u\n", hdr->common.ptype);
526       break;
527   }
528 
529   /* clean up */
530   I_RpcFree(msg->Buffer);
531   RPCRT4_FreeHeader(hdr);
532   HeapFree(GetProcessHeap(), 0, msg);
533   HeapFree(GetProcessHeap(), 0, auth_data);
534 }
535 
536 static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
537 {
538   RpcPacket *pkt = the_arg;
539   RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg, pkt->auth_data,
540                         pkt->auth_length);
541   RPCRT4_ReleaseConnection(pkt->conn);
542   HeapFree(GetProcessHeap(), 0, pkt);
543   return 0;
544 }
545 
546 static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
547 {
548   RpcConnection* conn = the_arg;
549   RpcPktHdr *hdr;
550   RPC_MESSAGE *msg;
551   RPC_STATUS status;
552   RpcPacket *packet;
553   unsigned char *auth_data;
554   ULONG auth_length;
555 
556   TRACE("(%p)\n", conn);
557 
558   for (;;) {
559     msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));
560     if (!msg) break;
561 
562     status = RPCRT4_ReceiveWithAuth(conn, &hdr, msg, &auth_data, &auth_length);
563     if (status != RPC_S_OK) {
564       WARN("receive failed with error %x\n", status);
565       HeapFree(GetProcessHeap(), 0, msg);
566       break;
567     }
568 
569     switch (hdr->common.ptype) {
570     case PKT_BIND:
571       TRACE("got bind packet\n");
572 
573       status = process_bind_packet(conn, &hdr->bind, msg, auth_data,
574                                    auth_length);
575       break;
576 
577     case PKT_REQUEST:
578       TRACE("got request packet\n");
579 
580       packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));
581       if (!packet) {
582         I_RpcFree(msg->Buffer);
583         RPCRT4_FreeHeader(hdr);
584         HeapFree(GetProcessHeap(), 0, msg);
585         HeapFree(GetProcessHeap(), 0, auth_data);
586         goto exit;
587       }
588       packet->conn = RPCRT4_GrabConnection( conn );
589       packet->hdr = hdr;
590       packet->msg = msg;
591       packet->auth_data = auth_data;
592       packet->auth_length = auth_length;
593       if (!QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION)) {
594         ERR("couldn't queue work item for worker thread, error was %d\n", GetLastError());
595         HeapFree(GetProcessHeap(), 0, packet);
596         status = RPC_S_OUT_OF_RESOURCES;
597       } else {
598         continue;
599       }
600       break;
601 
602     case PKT_AUTH3:
603       TRACE("got auth3 packet\n");
604 
605       status = process_auth3_packet(conn, &hdr->common, msg, auth_data,
606                                     auth_length);
607       break;
608     default:
609       FIXME("unhandled packet type %u\n", hdr->common.ptype);
610       break;
611     }
612 
613     I_RpcFree(msg->Buffer);
614     RPCRT4_FreeHeader(hdr);
615     HeapFree(GetProcessHeap(), 0, msg);
616     HeapFree(GetProcessHeap(), 0, auth_data);
617 
618     if (status != RPC_S_OK) {
619       WARN("processing packet failed with error %u\n", status);
620       break;
621     }
622   }
623 exit:
624   RPCRT4_ReleaseConnection(conn);
625   return 0;
626 }
627 
628 void RPCRT4_new_client(RpcConnection* conn)
629 {
630   HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL);
631   if (!thread) {
632     DWORD err = GetLastError();
633     ERR("failed to create thread, error=%08x\n", err);
634     RPCRT4_ReleaseConnection(conn);
635   }
636   /* we could set conn->thread, but then we'd have to make the io_thread wait
637    * for that, otherwise the thread might finish, destroy the connection, and
638    * free the memory we'd write to before we did, causing crashes and stuff -
639    * so let's implement that later, when we really need conn->thread */
640 
641   CloseHandle( thread );
642 }
643 
644 static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
645 {
646   int res;
647   unsigned int count;
648   void *objs = NULL;
649   RpcServerProtseq* cps = the_arg;
650   RpcConnection* conn;
651   BOOL set_ready_event = FALSE;
652 
653   TRACE("(the_arg == ^%p)\n", the_arg);
654 
655   for (;;) {
656     objs = cps->ops->get_wait_array(cps, objs, &count);
657 
658     if (set_ready_event)
659     {
660         /* signal to function that changed state that we are now sync'ed */
661         SetEvent(cps->server_ready_event);
662         set_ready_event = FALSE;
663     }
664 
665     /* start waiting */
666     res = cps->ops->wait_for_new_connection(cps, count, objs);
667 
668     if (res == -1 || (res == 0 && !std_listen))
669     {
670       /* cleanup */
671       cps->ops->free_wait_array(cps, objs);
672       break;
673     }
674     else if (res == 0)
675       set_ready_event = TRUE;
676   }
677 
678   TRACE("closing connections\n");
679 
680   EnterCriticalSection(&cps->cs);
681   LIST_FOR_EACH_ENTRY(conn, &cps->listeners, RpcConnection, protseq_entry)
682     RPCRT4_CloseConnection(conn);
683   LIST_FOR_EACH_ENTRY(conn, &cps->connections, RpcConnection, protseq_entry)
684   {
685     RPCRT4_GrabConnection(conn);
686     rpcrt4_conn_close_read(conn);
687   }
688   LeaveCriticalSection(&cps->cs);
689 
690   if (res == 0 && !std_listen)
691       SetEvent(cps->server_ready_event);
692 
693   TRACE("waiting for active connections to close\n");
694 
695   EnterCriticalSection(&cps->cs);
696   while (!list_empty(&cps->connections))
697   {
698     conn = LIST_ENTRY(list_head(&cps->connections), RpcConnection, protseq_entry);
699     LeaveCriticalSection(&cps->cs);
700     rpcrt4_conn_release_and_wait(conn);
701     EnterCriticalSection(&cps->cs);
702   }
703   LeaveCriticalSection(&cps->cs);
704 
705   EnterCriticalSection(&listen_cs);
706   CloseHandle(cps->server_thread);
707   cps->server_thread = NULL;
708   LeaveCriticalSection(&listen_cs);
709   TRACE("done\n");
710   return 0;
711 }
712 
713 /* tells the server thread that the state has changed and waits for it to
714  * make the changes */
715 static void RPCRT4_sync_with_server_thread(RpcServerProtseq *ps)
716 {
717   /* make sure we are the only thread sync'ing the server state, otherwise
718    * there is a race with the server thread setting an older state and setting
719    * the server_ready_event when the new state hasn't yet been applied */
720   WaitForSingleObject(ps->mgr_mutex, INFINITE);
721 
722   ps->ops->signal_state_changed(ps);
723 
724   /* wait for server thread to make the requested changes before returning */
725   WaitForSingleObject(ps->server_ready_event, INFINITE);
726 
727   ReleaseMutex(ps->mgr_mutex);
728 }
729 
730 static RPC_STATUS RPCRT4_start_listen_protseq(RpcServerProtseq *ps, BOOL auto_listen)
731 {
732   RPC_STATUS status = RPC_S_OK;
733 
734   EnterCriticalSection(&listen_cs);
735   if (ps->server_thread) goto done;
736 
737   if (!ps->mgr_mutex) ps->mgr_mutex = CreateMutexW(NULL, FALSE, NULL);
738   if (!ps->server_ready_event) ps->server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
739   ps->server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL);
740   if (!ps->server_thread)
741     status = RPC_S_OUT_OF_RESOURCES;
742 
743 done:
744   LeaveCriticalSection(&listen_cs);
745   return status;
746 }
747 
748 static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen)
749 {
750   RPC_STATUS status = RPC_S_ALREADY_LISTENING;
751   RpcServerProtseq *cps;
752 
753   TRACE("\n");
754 
755   EnterCriticalSection(&listen_cs);
756   if (auto_listen || !listen_done_event)
757   {
758     status = RPC_S_OK;
759     if(!auto_listen)
760       listen_done_event = CreateEventW(NULL, TRUE, FALSE, NULL);
761     if (++listen_count == 1)
762       std_listen = TRUE;
763   }
764   LeaveCriticalSection(&listen_cs);
765   if (status) return status;
766 
767   if (std_listen)
768   {
769     EnterCriticalSection(&server_cs);
770     LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
771     {
772       status = RPCRT4_start_listen_protseq(cps, TRUE);
773       if (status != RPC_S_OK)
774         break;
775 
776       /* make sure server is actually listening on the interface before
777        * returning */
778       RPCRT4_sync_with_server_thread(cps);
779     }
780     LeaveCriticalSection(&server_cs);
781   }
782 
783   return status;
784 }
785 
786 static RPC_STATUS RPCRT4_stop_listen(BOOL auto_listen)
787 {
788   BOOL stop_listen = FALSE;
789   RPC_STATUS status = RPC_S_OK;
790 
791   EnterCriticalSection(&listen_cs);
792   if (!std_listen && (auto_listen || !listen_done_event))
793   {
794     status = RPC_S_NOT_LISTENING;
795   }
796   else
797   {
798     stop_listen = listen_count != 0 && --listen_count == 0;
799     assert(listen_count >= 0);
800     if (stop_listen)
801       std_listen = FALSE;
802   }
803   LeaveCriticalSection(&listen_cs);
804 
805   if (status) return status;
806 
807   if (stop_listen) {
808     RpcServerProtseq *cps;
809     EnterCriticalSection(&server_cs);
810     LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
811       RPCRT4_sync_with_server_thread(cps);
812     LeaveCriticalSection(&server_cs);
813   }
814 
815   if (!auto_listen)
816   {
817       EnterCriticalSection(&listen_cs);
818       SetEvent( listen_done_event );
819       LeaveCriticalSection(&listen_cs);
820   }
821   return RPC_S_OK;
822 }
823 
824 static BOOL RPCRT4_protseq_is_endpoint_registered(RpcServerProtseq *protseq, const char *endpoint)
825 {
826   RpcConnection *conn;
827   BOOL registered = FALSE;
828   EnterCriticalSection(&protseq->cs);
829   LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection, protseq_entry) {
830     if (!endpoint || !strcmp(endpoint, conn->Endpoint)) {
831       registered = TRUE;
832       break;
833     }
834   }
835   LeaveCriticalSection(&protseq->cs);
836   return registered;
837 }
838 
839 static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps, const char *endpoint)
840 {
841   RPC_STATUS status;
842 
843   EnterCriticalSection(&ps->cs);
844 
845   if (RPCRT4_protseq_is_endpoint_registered(ps, endpoint))
846     status = RPC_S_OK;
847   else
848     status = ps->ops->open_endpoint(ps, endpoint);
849 
850   LeaveCriticalSection(&ps->cs);
851 
852   if (status != RPC_S_OK)
853     return status;
854 
855   if (std_listen)
856   {
857     status = RPCRT4_start_listen_protseq(ps, FALSE);
858     if (status == RPC_S_OK)
859       RPCRT4_sync_with_server_thread(ps);
860   }
861 
862   return status;
863 }
864 
865 /***********************************************************************
866  *             RpcServerInqBindings (RPCRT4.@)
867  */
868 RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
869 {
870   RPC_STATUS status;
871   DWORD count;
872   RpcServerProtseq* ps;
873   RpcConnection* conn;
874 
875   if (BindingVector)
876     TRACE("(*BindingVector == ^%p)\n", *BindingVector);
877   else
878     ERR("(BindingVector == NULL!!?)\n");
879 
880   EnterCriticalSection(&server_cs);
881   /* count connections */
882   count = 0;
883   LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) {
884     EnterCriticalSection(&ps->cs);
885     LIST_FOR_EACH_ENTRY(conn, &ps->listeners, RpcConnection, protseq_entry)
886       count++;
887     LeaveCriticalSection(&ps->cs);
888   }
889   if (count) {
890     /* export bindings */
891     *BindingVector = HeapAlloc(GetProcessHeap(), 0,
892                               sizeof(RPC_BINDING_VECTOR) +
893                               sizeof(RPC_BINDING_HANDLE)*(count-1));
894     (*BindingVector)->Count = count;
895     count = 0;
896     LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) {
897       EnterCriticalSection(&ps->cs);
898       LIST_FOR_EACH_ENTRY(conn, &ps->listeners, RpcConnection, protseq_entry) {
899        RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
900                           conn);
901        count++;
902       }
903       LeaveCriticalSection(&ps->cs);
904     }
905     status = RPC_S_OK;
906   } else {
907     *BindingVector = NULL;
908     status = RPC_S_NO_BINDINGS;
909   }
910   LeaveCriticalSection(&server_cs);
911   return status;
912 }
913 
914 /***********************************************************************
915  *             RpcServerUseProtseqEpA (RPCRT4.@)
916  */
917 RPC_STATUS WINAPI RpcServerUseProtseqEpA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor )
918 {
919   RPC_POLICY policy;
920 
921   TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
922 
923   /* This should provide the default behaviour */
924   policy.Length        = sizeof( policy );
925   policy.EndpointFlags = 0;
926   policy.NICFlags      = 0;
927 
928   return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
929 }
930 
931 /***********************************************************************
932  *             RpcServerUseProtseqEpW (RPCRT4.@)
933  */
934 RPC_STATUS WINAPI RpcServerUseProtseqEpW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor )
935 {
936   RPC_POLICY policy;
937 
938   TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
939 
940   /* This should provide the default behaviour */
941   policy.Length        = sizeof( policy );
942   policy.EndpointFlags = 0;
943   policy.NICFlags      = 0;
944 
945   return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
946 }
947 
948 /***********************************************************************
949  *             alloc_serverprotoseq (internal)
950  *
951  * Must be called with server_cs held.
952  */
953 static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, const char *Protseq, RpcServerProtseq **ps)
954 {
955   const struct protseq_ops *ops = rpcrt4_get_protseq_ops(Protseq);
956 
957   if (!ops)
958   {
959     FIXME("protseq %s not supported\n", debugstr_a(Protseq));
960     return RPC_S_PROTSEQ_NOT_SUPPORTED;
961   }
962 
963   *ps = ops->alloc();
964   if (!*ps)
965     return RPC_S_OUT_OF_RESOURCES;
966   (*ps)->MaxCalls = MaxCalls;
967   (*ps)->Protseq = RPCRT4_strdupA(Protseq);
968   (*ps)->ops = ops;
969   list_init(&(*ps)->listeners);
970   list_init(&(*ps)->connections);
971   InitializeCriticalSection(&(*ps)->cs);
972   (*ps)->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcServerProtseq.cs");
973 
974   list_add_head(&protseqs, &(*ps)->entry);
975 
976   TRACE("new protseq %p created for %s\n", *ps, Protseq);
977 
978   return RPC_S_OK;
979 }
980 
981 /* must be called with server_cs held */
982 static void destroy_serverprotoseq(RpcServerProtseq *ps)
983 {
984     RPCRT4_strfree(ps->Protseq);
985     ps->cs.DebugInfo->Spare[0] = 0;
986     DeleteCriticalSection(&ps->cs);
987     CloseHandle(ps->mgr_mutex);
988     CloseHandle(ps->server_ready_event);
989     list_remove(&ps->entry);
990     HeapFree(GetProcessHeap(), 0, ps);
991 }
992 
993 /* Finds a given protseq or creates a new one if one doesn't already exist */
994 static RPC_STATUS RPCRT4_get_or_create_serverprotseq(UINT MaxCalls, const char *Protseq, RpcServerProtseq **ps)
995 {
996     RPC_STATUS status;
997     RpcServerProtseq *cps;
998 
999     EnterCriticalSection(&server_cs);
1000 
1001     LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
1002         if (!strcmp(cps->Protseq, Protseq))
1003         {
1004             TRACE("found existing protseq object for %s\n", Protseq);
1005             *ps = cps;
1006             LeaveCriticalSection(&server_cs);
1007             return S_OK;
1008         }
1009 
1010     status = alloc_serverprotoseq(MaxCalls, Protseq, ps);
1011 
1012     LeaveCriticalSection(&server_cs);
1013 
1014     return status;
1015 }
1016 
1017 /***********************************************************************
1018  *             RpcServerUseProtseqEpExA (RPCRT4.@)
1019  */
1020 RPC_STATUS WINAPI RpcServerUseProtseqEpExA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor,
1021                                             PRPC_POLICY lpPolicy )
1022 {
1023   RpcServerProtseq* ps;
1024   RPC_STATUS status;
1025 
1026   TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_a((const char *)Protseq),
1027        MaxCalls, debugstr_a((const char *)Endpoint), SecurityDescriptor,
1028        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
1029 
1030   status = RPCRT4_get_or_create_serverprotseq(MaxCalls, (const char *)Protseq, &ps);
1031   if (status != RPC_S_OK)
1032     return status;
1033 
1034   return RPCRT4_use_protseq(ps, (const char *)Endpoint);
1035 }
1036 
1037 /***********************************************************************
1038  *             RpcServerUseProtseqEpExW (RPCRT4.@)
1039  */
1040 RPC_STATUS WINAPI RpcServerUseProtseqEpExW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor,
1041                                             PRPC_POLICY lpPolicy )
1042 {
1043   RpcServerProtseq* ps;
1044   RPC_STATUS status;
1045   LPSTR ProtseqA;
1046   LPSTR EndpointA;
1047 
1048   TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_w( Protseq ), MaxCalls,
1049        debugstr_w( Endpoint ), SecurityDescriptor,
1050        lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );
1051 
1052   ProtseqA = RPCRT4_strdupWtoA(Protseq);
1053   status = RPCRT4_get_or_create_serverprotseq(MaxCalls, ProtseqA, &ps);
1054   RPCRT4_strfree(ProtseqA);
1055   if (status != RPC_S_OK)
1056     return status;
1057 
1058   EndpointA = RPCRT4_strdupWtoA(Endpoint);
1059   status = RPCRT4_use_protseq(ps, EndpointA);
1060   RPCRT4_strfree(EndpointA);
1061   return status;
1062 }
1063 
1064 /***********************************************************************
1065  *             RpcServerUseProtseqA (RPCRT4.@)
1066  */
1067 RPC_STATUS WINAPI RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
1068 {
1069   RPC_STATUS status;
1070   RpcServerProtseq* ps;
1071 
1072   TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a((char*)Protseq), MaxCalls, SecurityDescriptor);
1073 
1074   status = RPCRT4_get_or_create_serverprotseq(MaxCalls, (const char *)Protseq, &ps);
1075   if (status != RPC_S_OK)
1076     return status;
1077 
1078   return RPCRT4_use_protseq(ps, NULL);
1079 }
1080 
1081 /***********************************************************************
1082  *             RpcServerUseProtseqW (RPCRT4.@)
1083  */
1084 RPC_STATUS WINAPI RpcServerUseProtseqW(RPC_WSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
1085 {
1086   RPC_STATUS status;
1087   RpcServerProtseq* ps;
1088   LPSTR ProtseqA;
1089 
1090   TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor);
1091 
1092   ProtseqA = RPCRT4_strdupWtoA(Protseq);
1093   status = RPCRT4_get_or_create_serverprotseq(MaxCalls, ProtseqA, &ps);
1094   RPCRT4_strfree(ProtseqA);
1095   if (status != RPC_S_OK)
1096     return status;
1097 
1098   return RPCRT4_use_protseq(ps, NULL);
1099 }
1100 
1101 void RPCRT4_destroy_all_protseqs(void)
1102 {
1103     RpcServerProtseq *cps, *cursor2;
1104 
1105     if (listen_count != 0)
1106         std_listen = FALSE;
1107 
1108     EnterCriticalSection(&server_cs);
1109     LIST_FOR_EACH_ENTRY_SAFE(cps, cursor2, &protseqs, RpcServerProtseq, entry)
1110     {
1111         if (listen_count != 0)
1112             RPCRT4_sync_with_server_thread(cps);
1113         destroy_serverprotoseq(cps);
1114     }
1115     LeaveCriticalSection(&server_cs);
1116     DeleteCriticalSection(&server_cs);
1117     DeleteCriticalSection(&listen_cs);
1118 }
1119 
1120 /***********************************************************************
1121  *             RpcServerRegisterIf (RPCRT4.@)
1122  */
1123 RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
1124 {
1125   TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
1126   return RpcServerRegisterIf3( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL, NULL );
1127 }
1128 
1129 /***********************************************************************
1130  *             RpcServerRegisterIfEx (RPCRT4.@)
1131  */
1132 RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
1133                        UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
1134 {
1135   TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
1136   return RpcServerRegisterIf3( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn, NULL );
1137 }
1138 
1139 /***********************************************************************
1140  *             RpcServerRegisterIf2 (RPCRT4.@)
1141  */
1142 RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
1143                       UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
1144 {
1145   return RpcServerRegisterIf3( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, MaxRpcSize, IfCallbackFn, NULL );
1146 }
1147 
1148 /***********************************************************************
1149  *             RpcServerRegisterIf3 (RPCRT4.@)
1150  */
1151 RPC_STATUS WINAPI RpcServerRegisterIf3( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
1152     UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn, void* SecurityDescriptor)
1153 {
1154   PRPC_SERVER_INTERFACE If = IfSpec;
1155   RpcServerInterface* sif;
1156   unsigned int i;
1157 
1158   TRACE("(%p,%s,%p,%u,%u,%u,%p,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
1159         MaxRpcSize, IfCallbackFn, SecurityDescriptor);
1160 
1161   if (SecurityDescriptor)
1162       FIXME("Unsupported SecurityDescriptor argument.\n");
1163 
1164   TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
1165                                      If->InterfaceId.SyntaxVersion.MajorVersion,
1166                                      If->InterfaceId.SyntaxVersion.MinorVersion);
1167   TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),
1168                                         If->TransferSyntax.SyntaxVersion.MajorVersion,
1169                                         If->TransferSyntax.SyntaxVersion.MinorVersion);
1170   TRACE(" dispatch table: %p\n", If->DispatchTable);
1171   if (If->DispatchTable) {
1172     TRACE("  dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
1173     for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
1174       TRACE("   entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
1175     }
1176     TRACE("  reserved: %ld\n", If->DispatchTable->Reserved);
1177   }
1178   TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
1179   TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
1180   TRACE(" interpreter info: %p\n", If->InterpreterInfo);
1181 
1182   sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
1183   sif->If           = If;
1184   if (MgrTypeUuid) {
1185     sif->MgrTypeUuid = *MgrTypeUuid;
1186     sif->MgrEpv       = MgrEpv;
1187   } else {
1188     memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
1189     sif->MgrEpv       = If->DefaultManagerEpv;
1190   }
1191   sif->Flags        = Flags;
1192   sif->MaxCalls     = MaxCalls;
1193   sif->MaxRpcSize   = MaxRpcSize;
1194   sif->IfCallbackFn = IfCallbackFn;
1195 
1196   EnterCriticalSection(&server_cs);
1197   list_add_head(&server_interfaces, &sif->entry);
1198   LeaveCriticalSection(&server_cs);
1199 
1200   if (sif->Flags & RPC_IF_AUTOLISTEN)
1201       RPCRT4_start_listen(TRUE);
1202 
1203   return RPC_S_OK;
1204 }
1205 
1206 /***********************************************************************
1207  *             RpcServerUnregisterIf (RPCRT4.@)
1208  */
1209 RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete )
1210 {
1211   PRPC_SERVER_INTERFACE If = IfSpec;
1212   HANDLE event = NULL;
1213   BOOL found = FALSE;
1214   BOOL completed = TRUE;
1215   RpcServerInterface *cif;
1216   RPC_STATUS status;
1217 
1218   TRACE("(IfSpec == (RPC_IF_HANDLE)^%p (%s), MgrTypeUuid == %s, WaitForCallsToComplete == %u)\n",
1219     IfSpec, debugstr_guid(&If->InterfaceId.SyntaxGUID), debugstr_guid(MgrTypeUuid), WaitForCallsToComplete);
1220 
1221   EnterCriticalSection(&server_cs);
1222   LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) {
1223     if ((!IfSpec || !memcmp(&If->InterfaceId, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER))) &&
1224         UuidEqual(MgrTypeUuid, &cif->MgrTypeUuid, &status)) {
1225       list_remove(&cif->entry);
1226       TRACE("unregistering cif %p\n", cif);
1227       if (cif->CurrentCalls) {
1228         completed = FALSE;
1229         cif->Delete = TRUE;
1230         if (WaitForCallsToComplete)
1231           cif->CallsCompletedEvent = event = CreateEventW(NULL, FALSE, FALSE, NULL);
1232       }
1233       found = TRUE;
1234       break;
1235     }
1236   }
1237   LeaveCriticalSection(&server_cs);
1238 
1239   if (!found) {
1240     ERR("not found for object %s\n", debugstr_guid(MgrTypeUuid));
1241     return RPC_S_UNKNOWN_IF;
1242   }
1243 
1244   if (completed)
1245     HeapFree(GetProcessHeap(), 0, cif);
1246   else if (event) {
1247     /* sif will be freed when the last call is completed, so be careful not to
1248      * touch that memory here as that could happen before we get here */
1249     WaitForSingleObject(event, INFINITE);
1250     CloseHandle(event);
1251   }
1252 
1253   return RPC_S_OK;
1254 }
1255 
1256 /***********************************************************************
1257  *             RpcServerUnregisterIfEx (RPCRT4.@)
1258  */
1259 RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )
1260 {
1261   FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",
1262     IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);
1263 
1264   return RPC_S_OK;
1265 }
1266 
1267 /***********************************************************************
1268  *             RpcObjectSetType (RPCRT4.@)
1269  *
1270  * PARAMS
1271  *   ObjUuid  [I] "Object" UUID
1272  *   TypeUuid [I] "Type" UUID
1273  *
1274  * RETURNS
1275  *   RPC_S_OK                 The call succeeded
1276  *   RPC_S_INVALID_OBJECT     The provided object (nil) is not valid
1277  *   RPC_S_ALREADY_REGISTERED The provided object is already registered
1278  *
1279  * Maps "Object" UUIDs to "Type" UUIDs.  Passing the nil UUID as the type
1280  * resets the mapping for the specified object UUID to nil (the default).
1281  * The nil object is always associated with the nil type and cannot be
1282  * reassigned.  Servers can support multiple implementations on the same
1283  * interface by registering different end-point vectors for the different
1284  * types.  There's no need to call this if a server only supports the nil
1285  * type, as is typical.
1286  */
1287 RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid )
1288 {
1289   RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL;
1290   RPC_STATUS dummy;
1291 
1292   TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid));
1293   if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) {
1294     /* nil uuid cannot be remapped */
1295     return RPC_S_INVALID_OBJECT;
1296   }
1297 
1298   /* find the mapping for this object if there is one ... */
1299   while (map) {
1300     if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break;
1301     prev = map;
1302     map = map->next;
1303   }
1304   if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) {
1305     /* ... and drop it from the list */
1306     if (map) {
1307       if (prev)
1308         prev->next = map->next;
1309       else
1310         RpcObjTypeMaps = map->next;
1311       HeapFree(GetProcessHeap(), 0, map);
1312     }
1313   } else {
1314     /* ... , fail if we found it ... */
1315     if (map)
1316       return RPC_S_ALREADY_REGISTERED;
1317     /* ... otherwise create a new one and add it in. */
1318     map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap));
1319     map->Object = *ObjUuid;
1320     map->Type = *TypeUuid;
1321     map->next = NULL;
1322     if (prev)
1323       prev->next = map; /* prev is the last map in the linklist */
1324     else
1325       RpcObjTypeMaps = map;
1326   }
1327 
1328   return RPC_S_OK;
1329 }
1330 
1331 struct rpc_server_registered_auth_info
1332 {
1333     struct list entry;
1334     USHORT auth_type;
1335     WCHAR *package_name;
1336     WCHAR *principal;
1337     ULONG max_token;
1338 };
1339 
1340 static RPC_STATUS find_security_package(ULONG auth_type, SecPkgInfoW **packages_buf, SecPkgInfoW **ret)
1341 {
1342     SECURITY_STATUS sec_status;
1343     SecPkgInfoW *packages;
1344     ULONG package_count;
1345     ULONG i;
1346 
1347     sec_status = EnumerateSecurityPackagesW(&package_count, &packages);
1348     if (sec_status != SEC_E_OK)
1349     {
1350         ERR("EnumerateSecurityPackagesW failed with error 0x%08x\n", sec_status);
1351         return RPC_S_SEC_PKG_ERROR;
1352     }
1353 
1354     for (i = 0; i < package_count; i++)
1355         if (packages[i].wRPCID == auth_type)
1356             break;
1357 
1358     if (i == package_count)
1359     {
1360         WARN("unsupported AuthnSvc %u\n", auth_type);
1361         FreeContextBuffer(packages);
1362         return RPC_S_UNKNOWN_AUTHN_SERVICE;
1363     }
1364 
1365     TRACE("found package %s for service %u\n", debugstr_w(packages[i].Name), auth_type);
1366     *packages_buf = packages;
1367     *ret = packages + i;
1368     return RPC_S_OK;
1369 }
1370 
1371 RPC_STATUS RPCRT4_ServerGetRegisteredAuthInfo(
1372     USHORT auth_type, CredHandle *cred, TimeStamp *exp, ULONG *max_token)
1373 {
1374     RPC_STATUS status = RPC_S_UNKNOWN_AUTHN_SERVICE;
1375     struct rpc_server_registered_auth_info *auth_info;
1376     SECURITY_STATUS sec_status;
1377 
1378     EnterCriticalSection(&server_auth_info_cs);
1379     LIST_FOR_EACH_ENTRY(auth_info, &server_registered_auth_info, struct rpc_server_registered_auth_info, entry)
1380     {
1381         if (auth_info->auth_type == auth_type)
1382         {
1383             sec_status = AcquireCredentialsHandleW((SEC_WCHAR *)auth_info->principal, auth_info->package_name,
1384                                                    SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL,
1385                                                    cred, exp);
1386             if (sec_status != SEC_E_OK)
1387             {
1388                 status = RPC_S_SEC_PKG_ERROR;
1389                 break;
1390             }
1391 
1392             *max_token = auth_info->max_token;
1393             status = RPC_S_OK;
1394             break;
1395         }
1396     }
1397     LeaveCriticalSection(&server_auth_info_cs);
1398 
1399     return status;
1400 }
1401 
1402 void RPCRT4_ServerFreeAllRegisteredAuthInfo(void)
1403 {
1404     struct rpc_server_registered_auth_info *auth_info, *cursor2;
1405 
1406     EnterCriticalSection(&server_auth_info_cs);
1407     LIST_FOR_EACH_ENTRY_SAFE(auth_info, cursor2, &server_registered_auth_info, struct rpc_server_registered_auth_info, entry)
1408     {
1409         HeapFree(GetProcessHeap(), 0, auth_info->package_name);
1410         HeapFree(GetProcessHeap(), 0, auth_info->principal);
1411         HeapFree(GetProcessHeap(), 0, auth_info);
1412     }
1413     LeaveCriticalSection(&server_auth_info_cs);
1414     DeleteCriticalSection(&server_auth_info_cs);
1415 }
1416 
1417 /***********************************************************************
1418  *             RpcServerRegisterAuthInfoA (RPCRT4.@)
1419  */
1420 RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( RPC_CSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
1421                             LPVOID Arg )
1422 {
1423     WCHAR *principal_name = NULL;
1424     RPC_STATUS status;
1425 
1426     TRACE("(%s,%u,%p,%p)\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg);
1427 
1428     if(ServerPrincName && !(principal_name = RPCRT4_strdupAtoW((const char*)ServerPrincName)))
1429         return RPC_S_OUT_OF_RESOURCES;
1430 
1431     status = RpcServerRegisterAuthInfoW(principal_name, AuthnSvc, GetKeyFn, Arg);
1432 
1433     HeapFree(GetProcessHeap(), 0, principal_name);
1434     return status;
1435 }
1436 
1437 /***********************************************************************
1438  *             RpcServerRegisterAuthInfoW (RPCRT4.@)
1439  */
1440 RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( RPC_WSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
1441                             LPVOID Arg )
1442 {
1443     struct rpc_server_registered_auth_info *auth_info;
1444     SecPkgInfoW *packages, *package;
1445     WCHAR *package_name;
1446     ULONG max_token;
1447     RPC_STATUS status;
1448 
1449     TRACE("(%s,%u,%p,%p)\n", debugstr_w(ServerPrincName), AuthnSvc, GetKeyFn, Arg);
1450 
1451     status = find_security_package(AuthnSvc, &packages, &package);
1452     if (status != RPC_S_OK)
1453         return status;
1454 
1455     package_name = RPCRT4_strdupW(package->Name);
1456     max_token = package->cbMaxToken;
1457     FreeContextBuffer(packages);
1458     if (!package_name)
1459         return RPC_S_OUT_OF_RESOURCES;
1460 
1461     auth_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*auth_info));
1462     if (!auth_info) {
1463         HeapFree(GetProcessHeap(), 0, package_name);
1464         return RPC_S_OUT_OF_RESOURCES;
1465     }
1466 
1467     if (ServerPrincName && !(auth_info->principal = RPCRT4_strdupW(ServerPrincName))) {
1468         HeapFree(GetProcessHeap(), 0, package_name);
1469         HeapFree(GetProcessHeap(), 0, auth_info);
1470         return RPC_S_OUT_OF_RESOURCES;
1471     }
1472 
1473     auth_info->auth_type = AuthnSvc;
1474     auth_info->package_name = package_name;
1475     auth_info->max_token = max_token;
1476 
1477     EnterCriticalSection(&server_auth_info_cs);
1478     list_add_tail(&server_registered_auth_info, &auth_info->entry);
1479     LeaveCriticalSection(&server_auth_info_cs);
1480 
1481     return RPC_S_OK;
1482 }
1483 
1484 /******************************************************************************
1485  * RpcServerInqDefaultPrincNameA   (rpcrt4.@)
1486  */
1487 RPC_STATUS RPC_ENTRY RpcServerInqDefaultPrincNameA(ULONG AuthnSvc, RPC_CSTR *PrincName)
1488 {
1489     RPC_STATUS ret;
1490     RPC_WSTR principalW;
1491 
1492     TRACE("%u, %p\n", AuthnSvc, PrincName);
1493 
1494     if ((ret = RpcServerInqDefaultPrincNameW( AuthnSvc, &principalW )) == RPC_S_OK)
1495     {
1496         if (!(*PrincName = (RPC_CSTR)RPCRT4_strdupWtoA( principalW ))) return RPC_S_OUT_OF_MEMORY;
1497         RpcStringFreeW( &principalW );
1498     }
1499     return ret;
1500 }
1501 
1502 /******************************************************************************
1503  * RpcServerInqDefaultPrincNameW   (rpcrt4.@)
1504  */
1505 RPC_STATUS RPC_ENTRY RpcServerInqDefaultPrincNameW(ULONG AuthnSvc, RPC_WSTR *PrincName)
1506 {
1507     ULONG len = 0;
1508 
1509     FIXME("%u, %p\n", AuthnSvc, PrincName);
1510 
1511     if (AuthnSvc != RPC_C_AUTHN_WINNT) return RPC_S_UNKNOWN_AUTHN_SERVICE;
1512 
1513     GetUserNameExW( NameSamCompatible, NULL, &len );
1514     if (GetLastError() != ERROR_MORE_DATA) return RPC_S_INTERNAL_ERROR;
1515 
1516     if (!(*PrincName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1517         return RPC_S_OUT_OF_MEMORY;
1518 
1519     GetUserNameExW( NameSamCompatible, *PrincName, &len );
1520     return RPC_S_OK;
1521 }
1522 
1523 /***********************************************************************
1524  *             RpcServerListen (RPCRT4.@)
1525  */
1526 RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
1527 {
1528   RPC_STATUS status = RPC_S_OK;
1529 
1530   TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);
1531 
1532   if (list_empty(&protseqs))
1533     return RPC_S_NO_PROTSEQS_REGISTERED;
1534 
1535   status = RPCRT4_start_listen(FALSE);
1536 
1537   if (DontWait || (status != RPC_S_OK)) return status;
1538 
1539   return RpcMgmtWaitServerListen();
1540 }
1541 
1542 /***********************************************************************
1543  *             RpcMgmtServerWaitListen (RPCRT4.@)
1544  */
1545 RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
1546 {
1547   RpcServerProtseq *protseq;
1548   HANDLE event, wait_thread;
1549 
1550   TRACE("()\n");
1551 
1552   EnterCriticalSection(&listen_cs);
1553   event = listen_done_event;
1554   LeaveCriticalSection(&listen_cs);
1555 
1556   if (!event)
1557       return RPC_S_NOT_LISTENING;
1558 
1559   TRACE( "waiting for server calls to finish\n" );
1560   WaitForSingleObject( event, INFINITE );
1561   TRACE( "done waiting\n" );
1562 
1563   EnterCriticalSection(&listen_cs);
1564   /* wait for server threads to finish */
1565   while(1)
1566   {
1567       if (listen_count)
1568           break;
1569 
1570       wait_thread = NULL;
1571       EnterCriticalSection(&server_cs);
1572       LIST_FOR_EACH_ENTRY(protseq, &protseqs, RpcServerProtseq, entry)
1573       {
1574           if ((wait_thread = protseq->server_thread))
1575               break;
1576       }
1577       LeaveCriticalSection(&server_cs);
1578       if (!wait_thread)
1579           break;
1580 
1581       TRACE("waiting for thread %u\n", GetThreadId(wait_thread));
1582       LeaveCriticalSection(&listen_cs);
1583       WaitForSingleObject(wait_thread, INFINITE);
1584       EnterCriticalSection(&listen_cs);
1585   }
1586   if (listen_done_event == event)
1587   {
1588       listen_done_event = NULL;
1589       CloseHandle( event );
1590   }
1591   LeaveCriticalSection(&listen_cs);
1592   return RPC_S_OK;
1593 }
1594 
1595 /***********************************************************************
1596  *             RpcMgmtStopServerListening (RPCRT4.@)
1597  */
1598 RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )
1599 {
1600   TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);
1601 
1602   if (Binding) {
1603     FIXME("client-side invocation not implemented.\n");
1604     return RPC_S_WRONG_KIND_OF_BINDING;
1605   }
1606 
1607   return RPCRT4_stop_listen(FALSE);
1608 }
1609 
1610 /***********************************************************************
1611  *             RpcMgmtEnableIdleCleanup (RPCRT4.@)
1612  */
1613 RPC_STATUS WINAPI RpcMgmtEnableIdleCleanup(void)
1614 {
1615     FIXME("(): stub\n");
1616     return RPC_S_OK;
1617 }
1618 
1619 /***********************************************************************
1620  *             I_RpcServerStartListening (RPCRT4.@)
1621  */
1622 RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd )
1623 {
1624   FIXME( "(%p): stub\n", hWnd );
1625 
1626   return RPC_S_OK;
1627 }
1628 
1629 /***********************************************************************
1630  *             I_RpcServerStopListening (RPCRT4.@)
1631  */
1632 RPC_STATUS WINAPI I_RpcServerStopListening( void )
1633 {
1634   FIXME( "(): stub\n" );
1635 
1636   return RPC_S_OK;
1637 }
1638 
1639 /***********************************************************************
1640  *             I_RpcWindowProc (RPCRT4.@)
1641  */
1642 UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )
1643 {
1644   FIXME( "(%p,%08x,%08x,%08x): stub\n", hWnd, Message, wParam, lParam );
1645 
1646   return 0;
1647 }
1648 
1649 /***********************************************************************
1650  *             RpcMgmtInqIfIds (RPCRT4.@)
1651  */
1652 RPC_STATUS WINAPI RpcMgmtInqIfIds(RPC_BINDING_HANDLE Binding, RPC_IF_ID_VECTOR **IfIdVector)
1653 {
1654   FIXME("(%p,%p): stub\n", Binding, IfIdVector);
1655   return RPC_S_INVALID_BINDING;
1656 }
1657 
1658 /***********************************************************************
1659  *             RpcMgmtInqStats (RPCRT4.@)
1660  */
1661 RPC_STATUS WINAPI RpcMgmtInqStats(RPC_BINDING_HANDLE Binding, RPC_STATS_VECTOR **Statistics)
1662 {
1663   RPC_STATS_VECTOR *stats;
1664 
1665   FIXME("(%p,%p)\n", Binding, Statistics);
1666 
1667   if ((stats = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_STATS_VECTOR))))
1668   {
1669     stats->Count = 1;
1670     stats->Stats[0] = 0;
1671     *Statistics = stats;
1672     return RPC_S_OK;
1673   }
1674   return RPC_S_OUT_OF_RESOURCES;
1675 }
1676 
1677 /***********************************************************************
1678  *             RpcMgmtStatsVectorFree (RPCRT4.@)
1679  */
1680 RPC_STATUS WINAPI RpcMgmtStatsVectorFree(RPC_STATS_VECTOR **StatsVector)
1681 {
1682   FIXME("(%p)\n", StatsVector);
1683 
1684   if (StatsVector)
1685   {
1686     HeapFree(GetProcessHeap(), 0, *StatsVector);
1687     *StatsVector = NULL;
1688   }
1689   return RPC_S_OK;
1690 }
1691 
1692 /***********************************************************************
1693  *             RpcMgmtEpEltInqBegin (RPCRT4.@)
1694  */
1695 RPC_STATUS WINAPI RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE Binding, ULONG InquiryType,
1696     RPC_IF_ID *IfId, ULONG VersOption, UUID *ObjectUuid, RPC_EP_INQ_HANDLE* InquiryContext)
1697 {
1698   FIXME("(%p,%u,%p,%u,%p,%p): stub\n",
1699         Binding, InquiryType, IfId, VersOption, ObjectUuid, InquiryContext);
1700   return RPC_S_INVALID_BINDING;
1701 }
1702 
1703 /***********************************************************************
1704  *             RpcMgmtIsServerListening (RPCRT4.@)
1705  */
1706 RPC_STATUS WINAPI RpcMgmtIsServerListening(RPC_BINDING_HANDLE Binding)
1707 {
1708   RPC_STATUS status = RPC_S_NOT_LISTENING;
1709 
1710   TRACE("(%p)\n", Binding);
1711 
1712   if (Binding) {
1713     RpcBinding *rpc_binding = (RpcBinding*)Binding;
1714     status = RPCRT4_IsServerListening(rpc_binding->Protseq, rpc_binding->Endpoint);
1715   }else {
1716     EnterCriticalSection(&listen_cs);
1717     if (listen_done_event && std_listen) status = RPC_S_OK;
1718     LeaveCriticalSection(&listen_cs);
1719   }
1720 
1721   return status;
1722 }
1723 
1724 /***********************************************************************
1725  *             RpcMgmtSetAuthorizationFn (RPCRT4.@)
1726  */
1727 RPC_STATUS WINAPI RpcMgmtSetAuthorizationFn(RPC_MGMT_AUTHORIZATION_FN fn)
1728 {
1729   FIXME("(%p): stub\n", fn);
1730   return RPC_S_OK;
1731 }
1732 
1733 /***********************************************************************
1734  *             RpcMgmtSetServerStackSize (RPCRT4.@)
1735  */
1736 RPC_STATUS WINAPI RpcMgmtSetServerStackSize(ULONG ThreadStackSize)
1737 {
1738   FIXME("(0x%x): stub\n", ThreadStackSize);
1739   return RPC_S_OK;
1740 }
1741 
1742 /***********************************************************************
1743  *             I_RpcGetCurrentCallHandle (RPCRT4.@)
1744  */
1745 RPC_BINDING_HANDLE WINAPI I_RpcGetCurrentCallHandle(void)
1746 {
1747     TRACE("\n");
1748     return RPCRT4_GetThreadCurrentCallHandle();
1749 }
1750