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