rpc_server.c 52.6 KB
Newer Older
1 2 3
/*
 * RPC server API
 *
4
 * Copyright 2001 Ove Kåven, TransGaming Technologies
5
 * Copyright 2004 Filip Navara
6
 * Copyright 2006-2008 Robert Shearman (for CodeWeavers)
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
 */

Alexandre Julliard's avatar
Alexandre Julliard committed
23 24 25
#include "config.h"
#include "wine/port.h"

26
#include <stdarg.h>
27 28
#include <stdio.h>
#include <string.h>
29
#include <assert.h>
30 31 32 33 34 35

#include "windef.h"
#include "winbase.h"
#include "winerror.h"

#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 52 53
typedef struct _RpcPacket
{
  struct _RpcConnection* conn;
54 55
  RpcPktHdr* hdr;
  RPC_MESSAGE* msg;
56 57
  unsigned char *auth_data;
  ULONG auth_length;
58 59
} RpcPacket;

60 61 62 63 64 65 66 67 68 69
typedef struct _RpcObjTypeMap
{
  /* FIXME: a hash table would be better. */
  struct _RpcObjTypeMap *next;
  UUID Object;
  UUID Type;
} RpcObjTypeMap;

static RpcObjTypeMap *RpcObjTypeMaps;

70 71
/* list of type RpcServerProtseq */
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 76 77 78 79
static CRITICAL_SECTION server_cs;
static CRITICAL_SECTION_DEBUG server_cs_debug =
{
    0, 0, &server_cs,
    { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList },
80
      0, 0, { (DWORD_PTR)(__FILE__ ": server_cs") }
81 82 83 84 85 86 87 88
};
static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 };

static CRITICAL_SECTION listen_cs;
static CRITICAL_SECTION_DEBUG listen_cs_debug =
{
    0, 0, &listen_cs,
    { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList },
89
      0, 0, { (DWORD_PTR)(__FILE__ ": listen_cs") }
90 91 92
};
static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 };

93 94 95 96 97 98 99 100 101
static CRITICAL_SECTION server_auth_info_cs;
static CRITICAL_SECTION_DEBUG server_auth_info_cs_debug =
{
    0, 0, &server_auth_info_cs,
    { &server_auth_info_cs_debug.ProcessLocksList, &server_auth_info_cs_debug.ProcessLocksList },
      0, 0, { (DWORD_PTR)(__FILE__ ": server_auth_info_cs") }
};
static CRITICAL_SECTION server_auth_info_cs = { &server_auth_info_cs_debug, -1, 0, 0, 0, 0 };

102
/* whether the server is currently listening */
103
static BOOL std_listen;
104 105 106 107
/* number of manual listeners (calls to RpcServerListen) */
static LONG manual_listen_count;
/* total listeners including auto listeners */
static LONG listen_count;
108 109
/* event set once all listening is finished */
static HANDLE listen_done_event;
110

111 112
static UUID uuid_nil;

113
static inline RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid)
114 115 116 117 118 119 120 121 122 123 124 125
{
  RpcObjTypeMap *rslt = RpcObjTypeMaps;
  RPC_STATUS dummy;

  while (rslt) {
    if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break;
    rslt = rslt->next;
  }

  return rslt;
}

126
static inline UUID *LookupObjType(UUID *ObjUuid)
127 128 129 130 131 132 133 134
{
  RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid);
  if (map)
    return &map->Type;
  else
    return &uuid_nil;
}

135
static RpcServerInterface* RPCRT4_find_interface(UUID* object,
136 137
                                                 const RPC_SYNTAX_IDENTIFIER *if_id,
                                                 const RPC_SYNTAX_IDENTIFIER *transfer_syntax,
138
                                                 BOOL check_object)
139 140
{
  UUID* MgrType = NULL;
141
  RpcServerInterface* cif;
142 143
  RPC_STATUS status;

144 145
  if (check_object)
    MgrType = LookupObjType(object);
146
  EnterCriticalSection(&server_cs);
147
  LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) {
148
    if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) &&
149
        (!transfer_syntax || !memcmp(transfer_syntax, &cif->If->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER))) &&
150
        (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) &&
151 152 153 154
        std_listen) {
      InterlockedIncrement(&cif->CurrentCalls);
      break;
    }
155 156
  }
  LeaveCriticalSection(&server_cs);
157
  if (&cif->entry == &server_interfaces) cif = NULL;
158 159 160
  TRACE("returning %p for object %s, if_id { %d.%d %s }\n", cif,
    debugstr_guid(object), if_id->SyntaxVersion.MajorVersion,
    if_id->SyntaxVersion.MinorVersion, debugstr_guid(&if_id->SyntaxGUID));
161 162 163
  return cif;
}

164 165 166
static void RPCRT4_release_server_interface(RpcServerInterface *sif)
{
  if (!InterlockedDecrement(&sif->CurrentCalls) &&
167
      sif->Delete) {
168 169
    /* sif must have been removed from server_interfaces before
     * CallsCompletedEvent is set */
170 171
    if (sif->CallsCompletedEvent)
      SetEvent(sif->CallsCompletedEvent);
172 173 174 175
    HeapFree(GetProcessHeap(), 0, sif);
  }
}

176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
static RpcPktHdr *handle_bind_error(RpcConnection *conn, RPC_STATUS error)
{
    unsigned int reject_reason;
    switch (error)
    {
    case RPC_S_SERVER_TOO_BUSY:
        reject_reason = REJECT_TEMPORARY_CONGESTION;
        break;
    case ERROR_OUTOFMEMORY:
    case RPC_S_OUT_OF_RESOURCES:
        reject_reason = REJECT_LOCAL_LIMIT_EXCEEDED;
        break;
    case RPC_S_PROTOCOL_ERROR:
        reject_reason = REJECT_PROTOCOL_VERSION_NOT_SUPPORTED;
        break;
    case RPC_S_UNKNOWN_AUTHN_SERVICE:
        reject_reason = REJECT_UNKNOWN_AUTHN_SERVICE;
        break;
    case ERROR_ACCESS_DENIED:
        reject_reason = REJECT_INVALID_CHECKSUM;
        break;
    default:
        FIXME("unexpected status value %d\n", error);
        /* fall through */
    case RPC_S_INVALID_BOUND:
        reject_reason = REJECT_REASON_NOT_SPECIFIED;
        break;
    }
    return RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION,
                                      RPC_VER_MAJOR, RPC_VER_MINOR,
                                      reject_reason);
}

static RPC_STATUS process_bind_packet_no_send(
    RpcConnection *conn, RpcPktBindHdr *hdr, RPC_MESSAGE *msg,
    unsigned char *auth_data, ULONG auth_length, RpcPktHdr **ack_response,
    unsigned char **auth_data_out, ULONG *auth_length_out)
213
{
214
  RPC_STATUS status;
215 216
  RpcContextElement *ctxt_elem;
  unsigned int i;
217
  RpcResult *results;
218

219
  /* validate data */
220 221 222 223 224 225 226 227 228
  for (i = 0, ctxt_elem = msg->Buffer;
       i < hdr->num_elements;
       i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes])
  {
      if (((char *)ctxt_elem - (char *)msg->Buffer) > msg->BufferLength ||
          ((char *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes] - (char *)msg->Buffer) > msg->BufferLength)
      {
          ERR("inconsistent data in packet - packet length %d, num elements %d\n",
              msg->BufferLength, hdr->num_elements);
229
          return RPC_S_INVALID_BOUND;
230 231
      }
  }
232 233 234

  if (hdr->max_tsize < RPC_MIN_PACKET_SIZE ||
      !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status) ||
235 236
      conn->server_binding)
  {
237
    TRACE("packet size less than min size, or active interface syntax guid non-null\n");
238

239
    return RPC_S_INVALID_BOUND;
240
  }
241 242 243 244 245 246 247 248 249

  results = HeapAlloc(GetProcessHeap(), 0,
                      hdr->num_elements * sizeof(*results));
  if (!results)
    return RPC_S_OUT_OF_RESOURCES;

  for (i = 0, ctxt_elem = (RpcContextElement *)msg->Buffer;
       i < hdr->num_elements;
       i++, ctxt_elem = (RpcContextElement *)&ctxt_elem->transfer_syntaxes[ctxt_elem->num_syntaxes])
250
  {
251 252
      RpcServerInterface* sif = NULL;
      unsigned int j;
253

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
      for (j = 0; !sif && j < ctxt_elem->num_syntaxes; j++)
      {
          sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax,
                                      &ctxt_elem->transfer_syntaxes[j], FALSE);
          if (sif)
              break;
      }
      if (sif)
      {
          RPCRT4_release_server_interface(sif);
          TRACE("accepting bind request on connection %p for %s\n", conn,
                debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
          results[i].result = RESULT_ACCEPT;
          results[i].reason = REASON_NONE;
          results[i].transfer_syntax = ctxt_elem->transfer_syntaxes[j];

          /* save the interface for later use */
          /* FIXME: save linked list */
          conn->ActiveInterface = ctxt_elem->abstract_syntax;
      }
      else if ((sif = RPCRT4_find_interface(NULL, &ctxt_elem->abstract_syntax,
                                            NULL, FALSE)) != NULL)
      {
          RPCRT4_release_server_interface(sif);
          TRACE("not accepting bind request on connection %p for %s - no transfer syntaxes supported\n",
                conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
          results[i].result = RESULT_PROVIDER_REJECTION;
          results[i].reason = REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED;
          memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax));
      }
      else
      {
          TRACE("not accepting bind request on connection %p for %s - abstract syntax not supported\n",
                conn, debugstr_guid(&ctxt_elem->abstract_syntax.SyntaxGUID));
          results[i].result = RESULT_PROVIDER_REJECTION;
          results[i].reason = REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED;
          memset(&results[i].transfer_syntax, 0, sizeof(results[i].transfer_syntax));
      }
  }
293

294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
  /* create temporary binding */
  status = RPCRT4_MakeBinding(&conn->server_binding, conn);
  if (status != RPC_S_OK)
  {
      HeapFree(GetProcessHeap(), 0, results);
      return status;
  }

  status = RpcServerAssoc_GetAssociation(rpcrt4_conn_get_name(conn),
                                         conn->NetworkAddr, conn->Endpoint,
                                         conn->NetworkOptions,
                                         hdr->assoc_gid,
                                         &conn->server_binding->Assoc);
  if (status != RPC_S_OK)
  {
      HeapFree(GetProcessHeap(), 0, results);
      return status;
311 312
  }

313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
  if (auth_length)
  {
      status = RPCRT4_ServerConnectionAuth(conn, TRUE,
                                           (RpcAuthVerifier *)auth_data,
                                           auth_length, auth_data_out,
                                           auth_length_out);
      if (status != RPC_S_OK)
      {
          HeapFree(GetProcessHeap(), 0, results);
          return status;
      }
  }

  *ack_response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION,
                                            RPC_MAX_PACKET_SIZE,
                                            RPC_MAX_PACKET_SIZE,
                                            conn->server_binding->Assoc->assoc_group_id,
                                            conn->Endpoint, hdr->num_elements,
                                            results);
  HeapFree(GetProcessHeap(), 0, results);

  if (*ack_response)
      conn->MaxTransmissionSize = hdr->max_tsize;
336
  else
337
      status = RPC_S_OUT_OF_RESOURCES;
338 339 340 341

  return status;
}

342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
static RPC_STATUS process_bind_packet(RpcConnection *conn, RpcPktBindHdr *hdr,
                                      RPC_MESSAGE *msg,
                                      unsigned char *auth_data,
                                      ULONG auth_length)
{
    RPC_STATUS status;
    RpcPktHdr *response = NULL;
    unsigned char *auth_data_out = NULL;
    ULONG auth_length_out = 0;

    status = process_bind_packet_no_send(conn, hdr, msg, auth_data, auth_length,
                                         &response, &auth_data_out,
                                         &auth_length_out);
    if (status != RPC_S_OK)
        response = handle_bind_error(conn, status);
    if (response)
        status = RPCRT4_SendWithAuth(conn, response, NULL, 0, auth_data_out, auth_length_out);
    else
        status = ERROR_OUTOFMEMORY;
    RPCRT4_FreeHeader(response);

    return status;
}


367 368
static RPC_STATUS process_request_packet(RpcConnection *conn, RpcPktRequestHdr *hdr, RPC_MESSAGE *msg)
{
369
  RPC_STATUS status;
370 371 372
  RpcPktHdr *response = NULL;
  RpcServerInterface* sif;
  RPC_DISPATCH_FUNCTION func;
373
  BOOL exception;
374
  UUID *object_uuid;
375
  NDR_SCONTEXT context_handle;
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
  void *buf = msg->Buffer;

  /* fail if the connection isn't bound with an interface */
  if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) {
    /* FIXME: should send BindNack instead */
    response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
                                       status);

    RPCRT4_Send(conn, response, NULL, 0);
    RPCRT4_FreeHeader(response);
    return RPC_S_OK;
  }

  if (hdr->common.flags & RPC_FLG_OBJECT_UUID) {
    object_uuid = (UUID*)(hdr + 1);
  } else {
    object_uuid = NULL;
  }

395
  sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, NULL, TRUE);
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
  if (!sif) {
    WARN("interface %s no longer registered, returning fault packet\n", debugstr_guid(&conn->ActiveInterface.SyntaxGUID));
    response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
                                       NCA_S_UNK_IF);

    RPCRT4_Send(conn, response, NULL, 0);
    RPCRT4_FreeHeader(response);
    return RPC_S_OK;
  }
  msg->RpcInterfaceInformation = sif->If;
  /* copy the endpoint vector from sif to msg so that midl-generated code will use it */
  msg->ManagerEpv = sif->MgrEpv;
  if (object_uuid != NULL) {
    RPCRT4_SetBindingObject(msg->Handle, object_uuid);
  }

  /* find dispatch function */
  msg->ProcNum = hdr->opnum;
  if (sif->Flags & RPC_IF_OLE) {
    /* native ole32 always gives us a dispatch table with a single entry
    * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */
    func = *sif->If->DispatchTable->DispatchTable;
  } else {
    if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) {
      WARN("invalid procnum (%d/%d)\n", msg->ProcNum, sif->If->DispatchTable->DispatchTableCount);
      response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION,
                                         NCA_S_OP_RNG_ERROR);

      RPCRT4_Send(conn, response, NULL, 0);
      RPCRT4_FreeHeader(response);
    }
    func = sif->If->DispatchTable->DispatchTable[msg->ProcNum];
  }

  /* put in the drep. FIXME: is this more universally applicable?
    perhaps we should move this outward... */
  msg->DataRepresentation =
    MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]),
              MAKEWORD(hdr->common.drep[2], hdr->common.drep[3]));

  exception = FALSE;

  /* dispatch */
  RPCRT4_SetThreadCurrentCallHandle(msg->Handle);
  __TRY {
    if (func) func(msg);
442
  } __EXCEPT_ALL {
443
    WARN("exception caught with code 0x%08x = %d\n", GetExceptionCode(), GetExceptionCode());
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
    exception = TRUE;
    if (GetExceptionCode() == STATUS_ACCESS_VIOLATION)
      status = ERROR_NOACCESS;
    else
      status = GetExceptionCode();
    response = RPCRT4_BuildFaultHeader(msg->DataRepresentation,
                                       RPC2NCA_STATUS(status));
  } __ENDTRY
    RPCRT4_SetThreadCurrentCallHandle(NULL);

  /* release any unmarshalled context handles */
  while ((context_handle = RPCRT4_PopThreadContextHandle()) != NULL)
    RpcServerAssoc_ReleaseContextHandle(conn->server_binding->Assoc, context_handle, TRUE);

  if (!exception)
    response = RPCRT4_BuildResponseHeader(msg->DataRepresentation,
                                          msg->BufferLength);

  /* send response packet */
  if (response) {
    status = RPCRT4_Send(conn, response, exception ? NULL : msg->Buffer,
                         exception ? 0 : msg->BufferLength);
    RPCRT4_FreeHeader(response);
  } else
    ERR("out of memory\n");

  msg->RpcInterfaceInformation = NULL;
  RPCRT4_release_server_interface(sif);

  if (msg->Buffer == buf) buf = NULL;
  TRACE("freeing Buffer=%p\n", buf);
  I_RpcFree(buf);

  return status;
}

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
static RPC_STATUS process_auth3_packet(RpcConnection *conn,
                                       RpcPktCommonHdr *hdr,
                                       RPC_MESSAGE *msg,
                                       unsigned char *auth_data,
                                       ULONG auth_length)
{
    RPC_STATUS status;

    if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status) ||
        !auth_length || msg->BufferLength != 0)
        status = RPC_S_PROTOCOL_ERROR;
    else
    {
        status = RPCRT4_ServerConnectionAuth(conn, FALSE,
                                             (RpcAuthVerifier *)auth_data,
                                             auth_length, NULL, NULL);
    }

    /* FIXME: client doesn't expect a response to this message so must store
     * status in connection so that fault packet can be returned when next
     * packet is received */

    return RPC_S_OK;
}

static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr,
                                  RPC_MESSAGE* msg, unsigned char *auth_data,
                                  ULONG auth_length)
508
{
509 510
  msg->Handle = (RPC_BINDING_HANDLE)conn->server_binding;

511 512 513
  switch (hdr->common.ptype) {
    case PKT_BIND:
      TRACE("got bind packet\n");
514
      process_bind_packet(conn, &hdr->bind, msg, auth_data, auth_length);
515 516
      break;

517
    case PKT_REQUEST:
518
      TRACE("got request packet\n");
519
      process_request_packet(conn, &hdr->request, msg);
520
      break;
521

522 523
    case PKT_AUTH3:
      TRACE("got auth3 packet\n");
524
      process_auth3_packet(conn, &hdr->common, msg, auth_data, auth_length);
525
      break;
526
    default:
527
      FIXME("unhandled packet type %u\n", hdr->common.ptype);
528 529 530 531
      break;
  }

  /* clean up */
532
  I_RpcFree(msg->Buffer);
533
  RPCRT4_FreeHeader(hdr);
534
  HeapFree(GetProcessHeap(), 0, msg);
535
  HeapFree(GetProcessHeap(), 0, auth_data);
536 537 538 539
}

static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg)
{
540
  RpcPacket *pkt = the_arg;
541 542
  RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg, pkt->auth_data,
                        pkt->auth_length);
543
  RPCRT4_ReleaseConnection(pkt->conn);
544
  HeapFree(GetProcessHeap(), 0, pkt);
545 546 547 548 549
  return 0;
}

static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg)
{
550
  RpcConnection* conn = the_arg;
551 552 553 554
  RpcPktHdr *hdr;
  RPC_MESSAGE *msg;
  RPC_STATUS status;
  RpcPacket *packet;
555 556
  unsigned char *auth_data;
  ULONG auth_length;
557 558

  TRACE("(%p)\n", conn);
559 560

  for (;;) {
561
    msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE));
562
    if (!msg) break;
563

564
    status = RPCRT4_ReceiveWithAuth(conn, &hdr, msg, &auth_data, &auth_length);
565
    if (status != RPC_S_OK) {
566
      WARN("receive failed with error %x\n", status);
567
      HeapFree(GetProcessHeap(), 0, msg);
568 569 570
      break;
    }

571 572 573 574 575 576
    switch (hdr->common.ptype) {
    case PKT_BIND:
      TRACE("got bind packet\n");

      status = process_bind_packet(conn, &hdr->bind, msg, auth_data,
                                   auth_length);
577
      break;
578 579 580 581 582 583 584 585 586 587 588 589

    case PKT_REQUEST:
      TRACE("got request packet\n");

      packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket));
      if (!packet) {
        I_RpcFree(msg->Buffer);
        RPCRT4_FreeHeader(hdr);
        HeapFree(GetProcessHeap(), 0, msg);
        HeapFree(GetProcessHeap(), 0, auth_data);
        goto exit;
      }
590
      packet->conn = RPCRT4_GrabConnection( conn );
591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
      packet->hdr = hdr;
      packet->msg = msg;
      packet->auth_data = auth_data;
      packet->auth_length = auth_length;
      if (!QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION)) {
        ERR("couldn't queue work item for worker thread, error was %d\n", GetLastError());
        HeapFree(GetProcessHeap(), 0, packet);
        status = RPC_S_OUT_OF_RESOURCES;
      } else {
        continue;
      }
      break;

    case PKT_AUTH3:
      TRACE("got auth3 packet\n");

      status = process_auth3_packet(conn, &hdr->common, msg, auth_data,
                                    auth_length);
      break;
    default:
      FIXME("unhandled packet type %u\n", hdr->common.ptype);
612
      break;
613 614
    }

615 616 617 618 619 620 621 622 623
    I_RpcFree(msg->Buffer);
    RPCRT4_FreeHeader(hdr);
    HeapFree(GetProcessHeap(), 0, msg);
    HeapFree(GetProcessHeap(), 0, auth_data);

    if (status != RPC_S_OK) {
      WARN("processing packet failed with error %u\n", status);
      break;
    }
624
  }
625
exit:
626
  RPCRT4_ReleaseConnection(conn);
627 628 629
  return 0;
}

630
void RPCRT4_new_client(RpcConnection* conn)
631
{
632 633
  HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL);
  if (!thread) {
634
    DWORD err = GetLastError();
635
    ERR("failed to create thread, error=%08x\n", err);
636
    RPCRT4_ReleaseConnection(conn);
637
  }
638 639 640 641 642 643
  /* we could set conn->thread, but then we'd have to make the io_thread wait
   * for that, otherwise the thread might finish, destroy the connection, and
   * free the memory we'd write to before we did, causing crashes and stuff -
   * so let's implement that later, when we really need conn->thread */

  CloseHandle( thread );
644 645
}

646 647 648 649 650 651 652 653 654 655 656 657 658
static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg)
{
  int res;
  unsigned int count;
  void *objs = NULL;
  RpcServerProtseq* cps = the_arg;
  RpcConnection* conn;
  BOOL set_ready_event = FALSE;

  TRACE("(the_arg == ^%p)\n", the_arg);

  for (;;) {
    objs = cps->ops->get_wait_array(cps, objs, &count);
659

660 661 662
    if (set_ready_event)
    {
        /* signal to function that changed state that we are now sync'ed */
663
        SetEvent(cps->server_ready_event);
664 665 666
        set_ready_event = FALSE;
    }

667
    /* start waiting */
668
    res = cps->ops->wait_for_new_connection(cps, count, objs);
669 670

    if (res == -1 || (res == 0 && !std_listen))
671
    {
672 673 674 675 676 677 678 679
      /* cleanup */
      cps->ops->free_wait_array(cps, objs);
      EnterCriticalSection(&cps->cs);
      for (conn = cps->conn; conn; conn = conn->Next)
        RPCRT4_CloseConnection(conn);
      LeaveCriticalSection(&cps->cs);

      if (res == 0 && !std_listen)
680
        SetEvent(cps->server_ready_event);
681
      break;
682
    }
683 684
    else if (res == 0)
      set_ready_event = TRUE;
685 686 687 688
  }
  return 0;
}

689 690
/* tells the server thread that the state has changed and waits for it to
 * make the changes */
691
static void RPCRT4_sync_with_server_thread(RpcServerProtseq *ps)
692 693 694 695
{
  /* make sure we are the only thread sync'ing the server state, otherwise
   * there is a race with the server thread setting an older state and setting
   * the server_ready_event when the new state hasn't yet been applied */
696
  WaitForSingleObject(ps->mgr_mutex, INFINITE);
697

698 699
  ps->ops->signal_state_changed(ps);

700
  /* wait for server thread to make the requested changes before returning */
701
  WaitForSingleObject(ps->server_ready_event, INFINITE);
702

703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727
  ReleaseMutex(ps->mgr_mutex);
}

static RPC_STATUS RPCRT4_start_listen_protseq(RpcServerProtseq *ps, BOOL auto_listen)
{
  RPC_STATUS status = RPC_S_OK;
  HANDLE server_thread;

  EnterCriticalSection(&listen_cs);
  if (ps->is_listening) goto done;

  if (!ps->mgr_mutex) ps->mgr_mutex = CreateMutexW(NULL, FALSE, NULL);
  if (!ps->server_ready_event) ps->server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
  server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL);
  if (!server_thread)
  {
    status = RPC_S_OUT_OF_RESOURCES;
    goto done;
  }
  ps->is_listening = TRUE;
  CloseHandle(server_thread);

done:
  LeaveCriticalSection(&listen_cs);
  return status;
728 729
}

730
static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen)
731
{
732
  RPC_STATUS status = RPC_S_ALREADY_LISTENING;
733
  RpcServerProtseq *cps;
734

735
  TRACE("\n");
736 737

  EnterCriticalSection(&listen_cs);
738 739
  if (auto_listen || (manual_listen_count++ == 0))
  {
740
    status = RPC_S_OK;
741
    if (++listen_count == 1)
742
      std_listen = TRUE;
743
  }
744
  LeaveCriticalSection(&listen_cs);
745

746 747
  if (std_listen)
  {
748
    EnterCriticalSection(&server_cs);
749
    LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
750 751
    {
      status = RPCRT4_start_listen_protseq(cps, TRUE);
752 753
      if (status != RPC_S_OK)
        break;
754 755
      
      /* make sure server is actually listening on the interface before
756 757
       * returning */
      RPCRT4_sync_with_server_thread(cps);
758
    }
759
    LeaveCriticalSection(&server_cs);
760 761
  }

762
  return status;
763 764
}

765
static void RPCRT4_stop_listen(BOOL auto_listen)
766
{
767
  EnterCriticalSection(&listen_cs);
768 769 770
  if (auto_listen || (--manual_listen_count == 0))
  {
    if (listen_count != 0 && --listen_count == 0) {
771 772
      RpcServerProtseq *cps;

773 774
      std_listen = FALSE;
      LeaveCriticalSection(&listen_cs);
775

776
      LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
777
        RPCRT4_sync_with_server_thread(cps);
778

779 780 781 782
      EnterCriticalSection(&listen_cs);
      if (listen_done_event) SetEvent( listen_done_event );
      listen_done_event = 0;
      LeaveCriticalSection(&listen_cs);
783 784 785 786 787
      return;
    }
    assert(listen_count >= 0);
  }
  LeaveCriticalSection(&listen_cs);
788 789
}

790
static BOOL RPCRT4_protseq_is_endpoint_registered(RpcServerProtseq *protseq, const char *endpoint)
791 792 793 794 795 796 797 798 799 800 801 802
{
  RpcConnection *conn;
  EnterCriticalSection(&protseq->cs);
  for (conn = protseq->conn; conn; conn = conn->Next)
  {
    if (!endpoint || !strcmp(endpoint, conn->Endpoint))
      break;
  }
  LeaveCriticalSection(&protseq->cs);
  return (conn != NULL);
}

803
static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps, const char *endpoint)
804
{
805 806
  RPC_STATUS status;

807 808 809 810 811 812 813 814 815
  EnterCriticalSection(&ps->cs);

  if (RPCRT4_protseq_is_endpoint_registered(ps, endpoint))
    status = RPC_S_OK;
  else
    status = ps->ops->open_endpoint(ps, endpoint);

  LeaveCriticalSection(&ps->cs);

816 817
  if (status != RPC_S_OK)
    return status;
818

819 820 821 822 823 824
  if (std_listen)
  {
    status = RPCRT4_start_listen_protseq(ps, FALSE);
    if (status == RPC_S_OK)
      RPCRT4_sync_with_server_thread(ps);
  }
825

826
  return status;
827 828 829 830 831 832 833 834 835 836
}

/***********************************************************************
 *             RpcServerInqBindings (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector )
{
  RPC_STATUS status;
  DWORD count;
  RpcServerProtseq* ps;
837
  RpcConnection* conn;
838

839 840 841
  if (BindingVector)
    TRACE("(*BindingVector == ^%p)\n", *BindingVector);
  else
842
    ERR("(BindingVector == NULL!!?)\n");
843

844
  EnterCriticalSection(&server_cs);
845
  /* count connections */
846
  count = 0;
847
  LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) {
848
    EnterCriticalSection(&ps->cs);
849
    for (conn = ps->conn; conn; conn = conn->Next)
850
      count++;
851
    LeaveCriticalSection(&ps->cs);
852 853 854 855 856 857 858 859
  }
  if (count) {
    /* export bindings */
    *BindingVector = HeapAlloc(GetProcessHeap(), 0,
                              sizeof(RPC_BINDING_VECTOR) +
                              sizeof(RPC_BINDING_HANDLE)*(count-1));
    (*BindingVector)->Count = count;
    count = 0;
860
    LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) {
861
      EnterCriticalSection(&ps->cs);
862
      for (conn = ps->conn; conn; conn = conn->Next) {
863 864
       RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count],
                          conn);
865 866
       count++;
      }
867
      LeaveCriticalSection(&ps->cs);
868 869 870 871 872 873 874 875 876 877 878 879 880
    }
    status = RPC_S_OK;
  } else {
    *BindingVector = NULL;
    status = RPC_S_NO_BINDINGS;
  }
  LeaveCriticalSection(&server_cs);
  return status;
}

/***********************************************************************
 *             RpcServerUseProtseqEpA (RPCRT4.@)
 */
881
RPC_STATUS WINAPI RpcServerUseProtseqEpA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor )
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
{
  RPC_POLICY policy;
  
  TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor );
  
  /* This should provide the default behaviour */
  policy.Length        = sizeof( policy );
  policy.EndpointFlags = 0;
  policy.NICFlags      = 0;
  
  return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
}

/***********************************************************************
 *             RpcServerUseProtseqEpW (RPCRT4.@)
 */
898
RPC_STATUS WINAPI RpcServerUseProtseqEpW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor )
899 900 901 902 903 904 905 906 907 908 909 910 911
{
  RPC_POLICY policy;
  
  TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor );
  
  /* This should provide the default behaviour */
  policy.Length        = sizeof( policy );
  policy.EndpointFlags = 0;
  policy.NICFlags      = 0;
  
  return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy );
}

912 913
/***********************************************************************
 *             alloc_serverprotoseq (internal)
914 915
 *
 * Must be called with server_cs held.
916
 */
917
static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, const char *Protseq, RpcServerProtseq **ps)
918
{
919 920 921
  const struct protseq_ops *ops = rpcrt4_get_protseq_ops(Protseq);

  if (!ops)
922 923 924 925 926 927 928 929 930
  {
    FIXME("protseq %s not supported\n", debugstr_a(Protseq));
    return RPC_S_PROTSEQ_NOT_SUPPORTED;
  }

  *ps = ops->alloc();
  if (!*ps)
    return RPC_S_OUT_OF_RESOURCES;
  (*ps)->MaxCalls = MaxCalls;
931
  (*ps)->Protseq = RPCRT4_strdupA(Protseq);
932 933 934 935
  (*ps)->ops = ops;
  (*ps)->MaxCalls = 0;
  (*ps)->conn = NULL;
  InitializeCriticalSection(&(*ps)->cs);
936
  (*ps)->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcServerProtseq.cs");
937 938 939 940
  (*ps)->is_listening = FALSE;
  (*ps)->mgr_mutex = NULL;
  (*ps)->server_ready_event = NULL;

941 942 943 944
  list_add_head(&protseqs, &(*ps)->entry);

  TRACE("new protseq %p created for %s\n", *ps, Protseq);

945
  return RPC_S_OK;
946 947
}

948 949 950 951
/* must be called with server_cs held */
static void destroy_serverprotoseq(RpcServerProtseq *ps)
{
    RPCRT4_strfree(ps->Protseq);
952
    ps->cs.DebugInfo->Spare[0] = 0;
953 954 955 956 957 958 959
    DeleteCriticalSection(&ps->cs);
    CloseHandle(ps->mgr_mutex);
    CloseHandle(ps->server_ready_event);
    list_remove(&ps->entry);
    HeapFree(GetProcessHeap(), 0, ps);
}

960
/* Finds a given protseq or creates a new one if one doesn't already exist */
961
static RPC_STATUS RPCRT4_get_or_create_serverprotseq(UINT MaxCalls, const char *Protseq, RpcServerProtseq **ps)
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
{
    RPC_STATUS status;
    RpcServerProtseq *cps;

    EnterCriticalSection(&server_cs);

    LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry)
        if (!strcmp(cps->Protseq, Protseq))
        {
            TRACE("found existing protseq object for %s\n", Protseq);
            *ps = cps;
            LeaveCriticalSection(&server_cs);
            return S_OK;
        }

    status = alloc_serverprotoseq(MaxCalls, Protseq, ps);

    LeaveCriticalSection(&server_cs);

    return status;
}

984 985 986
/***********************************************************************
 *             RpcServerUseProtseqEpExA (RPCRT4.@)
 */
987
RPC_STATUS WINAPI RpcServerUseProtseqEpExA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor,
988 989 990
                                            PRPC_POLICY lpPolicy )
{
  RpcServerProtseq* ps;
991
  RPC_STATUS status;
992

993 994
  TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_a((const char *)Protseq),
       MaxCalls, debugstr_a((const char *)Endpoint), SecurityDescriptor,
995 996
       lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );

997
  status = RPCRT4_get_or_create_serverprotseq(MaxCalls, (const char *)Protseq, &ps);
998 999
  if (status != RPC_S_OK)
    return status;
1000

1001
  return RPCRT4_use_protseq(ps, (const char *)Endpoint);
1002 1003 1004 1005 1006
}

/***********************************************************************
 *             RpcServerUseProtseqEpExW (RPCRT4.@)
 */
1007
RPC_STATUS WINAPI RpcServerUseProtseqEpExW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor,
1008 1009 1010
                                            PRPC_POLICY lpPolicy )
{
  RpcServerProtseq* ps;
1011
  RPC_STATUS status;
1012
  LPSTR ProtseqA;
1013
  LPSTR EndpointA;
1014

1015
  TRACE("(%s,%u,%s,%p,{%u,%u,%u})\n", debugstr_w( Protseq ), MaxCalls,
1016 1017 1018
       debugstr_w( Endpoint ), SecurityDescriptor,
       lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags );

1019 1020 1021
  ProtseqA = RPCRT4_strdupWtoA(Protseq);
  status = RPCRT4_get_or_create_serverprotseq(MaxCalls, ProtseqA, &ps);
  RPCRT4_strfree(ProtseqA);
1022 1023
  if (status != RPC_S_OK)
    return status;
1024

1025 1026 1027 1028
  EndpointA = RPCRT4_strdupWtoA(Endpoint);
  status = RPCRT4_use_protseq(ps, EndpointA);
  RPCRT4_strfree(EndpointA);
  return status;
1029 1030
}

1031 1032 1033
/***********************************************************************
 *             RpcServerUseProtseqA (RPCRT4.@)
 */
1034
RPC_STATUS WINAPI RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
1035
{
1036 1037 1038
  RPC_STATUS status;
  RpcServerProtseq* ps;

1039
  TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a((char*)Protseq), MaxCalls, SecurityDescriptor);
1040

1041
  status = RPCRT4_get_or_create_serverprotseq(MaxCalls, (const char *)Protseq, &ps);
1042 1043 1044 1045
  if (status != RPC_S_OK)
    return status;

  return RPCRT4_use_protseq(ps, NULL);
1046 1047 1048 1049 1050
}

/***********************************************************************
 *             RpcServerUseProtseqW (RPCRT4.@)
 */
1051
RPC_STATUS WINAPI RpcServerUseProtseqW(RPC_WSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor)
1052
{
1053 1054
  RPC_STATUS status;
  RpcServerProtseq* ps;
1055
  LPSTR ProtseqA;
1056

1057
  TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor);
1058

1059 1060 1061
  ProtseqA = RPCRT4_strdupWtoA(Protseq);
  status = RPCRT4_get_or_create_serverprotseq(MaxCalls, ProtseqA, &ps);
  RPCRT4_strfree(ProtseqA);
1062 1063 1064 1065
  if (status != RPC_S_OK)
    return status;

  return RPCRT4_use_protseq(ps, NULL);
1066 1067
}

1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082
void RPCRT4_destroy_all_protseqs(void)
{
    RpcServerProtseq *cps, *cursor2;

    if (listen_count != 0)
        std_listen = FALSE;

    EnterCriticalSection(&server_cs);
    LIST_FOR_EACH_ENTRY_SAFE(cps, cursor2, &protseqs, RpcServerProtseq, entry)
    {
        if (listen_count != 0)
            RPCRT4_sync_with_server_thread(cps);
        destroy_serverprotoseq(cps);
    }
    LeaveCriticalSection(&server_cs);
1083 1084
    DeleteCriticalSection(&server_cs);
    DeleteCriticalSection(&listen_cs);
1085 1086
}

1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
/***********************************************************************
 *             RpcServerRegisterIf (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv )
{
  TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv);
  return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL );
}

/***********************************************************************
 *             RpcServerRegisterIfEx (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
                       UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn )
{
  TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn);
  return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn );
}

/***********************************************************************
 *             RpcServerRegisterIf2 (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv,
                      UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn )
{
1112
  PRPC_SERVER_INTERFACE If = IfSpec;
1113
  RpcServerInterface* sif;
1114
  unsigned int i;
1115 1116 1117 1118 1119 1120

  TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls,
         MaxRpcSize, IfCallbackFn);
  TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID),
                                     If->InterfaceId.SyntaxVersion.MajorVersion,
                                     If->InterfaceId.SyntaxVersion.MinorVersion);
Greg Turner's avatar
Greg Turner committed
1121 1122 1123
  TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID),
                                        If->TransferSyntax.SyntaxVersion.MajorVersion,
                                        If->TransferSyntax.SyntaxVersion.MinorVersion);
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
  TRACE(" dispatch table: %p\n", If->DispatchTable);
  if (If->DispatchTable) {
    TRACE("  dispatch table count: %d\n", If->DispatchTable->DispatchTableCount);
    for (i=0; i<If->DispatchTable->DispatchTableCount; i++) {
      TRACE("   entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]);
    }
    TRACE("  reserved: %ld\n", If->DispatchTable->Reserved);
  }
  TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount);
  TRACE(" default manager epv: %p\n", If->DefaultManagerEpv);
  TRACE(" interpreter info: %p\n", If->InterpreterInfo);

  sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface));
  sif->If           = If;
1138
  if (MgrTypeUuid) {
1139
    sif->MgrTypeUuid = *MgrTypeUuid;
1140 1141
    sif->MgrEpv       = MgrEpv;
  } else {
1142
    memset(&sif->MgrTypeUuid, 0, sizeof(UUID));
1143 1144
    sif->MgrEpv       = If->DefaultManagerEpv;
  }
1145 1146 1147 1148 1149 1150
  sif->Flags        = Flags;
  sif->MaxCalls     = MaxCalls;
  sif->MaxRpcSize   = MaxRpcSize;
  sif->IfCallbackFn = IfCallbackFn;

  EnterCriticalSection(&server_cs);
1151
  list_add_head(&server_interfaces, &sif->entry);
1152 1153
  LeaveCriticalSection(&server_cs);

1154 1155
  if (sif->Flags & RPC_IF_AUTOLISTEN)
      RPCRT4_start_listen(TRUE);
1156 1157 1158 1159

  return RPC_S_OK;
}

1160 1161 1162 1163 1164
/***********************************************************************
 *             RpcServerUnregisterIf (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete )
{
1165
  PRPC_SERVER_INTERFACE If = IfSpec;
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176
  HANDLE event = NULL;
  BOOL found = FALSE;
  BOOL completed = TRUE;
  RpcServerInterface *cif;
  RPC_STATUS status;

  TRACE("(IfSpec == (RPC_IF_HANDLE)^%p (%s), MgrTypeUuid == %s, WaitForCallsToComplete == %u)\n",
    IfSpec, debugstr_guid(&If->InterfaceId.SyntaxGUID), debugstr_guid(MgrTypeUuid), WaitForCallsToComplete);

  EnterCriticalSection(&server_cs);
  LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) {
1177
    if ((!IfSpec || !memcmp(&If->InterfaceId, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER))) &&
1178 1179
        UuidEqual(MgrTypeUuid, &cif->MgrTypeUuid, &status)) {
      list_remove(&cif->entry);
1180
      TRACE("unregistering cif %p\n", cif);
1181 1182
      if (cif->CurrentCalls) {
        completed = FALSE;
1183
        cif->Delete = TRUE;
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
        if (WaitForCallsToComplete)
          cif->CallsCompletedEvent = event = CreateEventW(NULL, FALSE, FALSE, NULL);
      }
      found = TRUE;
      break;
    }
  }
  LeaveCriticalSection(&server_cs);

  if (!found) {
    ERR("not found for object %s\n", debugstr_guid(MgrTypeUuid));
    return RPC_S_UNKNOWN_IF;
  }

  if (completed)
    HeapFree(GetProcessHeap(), 0, cif);
  else if (event) {
    /* sif will be freed when the last call is completed, so be careful not to
     * touch that memory here as that could happen before we get here */
    WaitForSingleObject(event, INFINITE);
    CloseHandle(event);
  }
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220

  return RPC_S_OK;
}

/***********************************************************************
 *             RpcServerUnregisterIfEx (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles )
{
  FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n",
    IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles);

  return RPC_S_OK;
}

1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232
/***********************************************************************
 *             RpcObjectSetType (RPCRT4.@)
 *
 * PARAMS
 *   ObjUuid  [I] "Object" UUID
 *   TypeUuid [I] "Type" UUID
 *
 * RETURNS
 *   RPC_S_OK                 The call succeeded
 *   RPC_S_INVALID_OBJECT     The provided object (nil) is not valid
 *   RPC_S_ALREADY_REGISTERED The provided object is already registered
 *
1233
 * Maps "Object" UUIDs to "Type" UUIDs.  Passing the nil UUID as the type
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272
 * resets the mapping for the specified object UUID to nil (the default).
 * The nil object is always associated with the nil type and cannot be
 * reassigned.  Servers can support multiple implementations on the same
 * interface by registering different end-point vectors for the different
 * types.  There's no need to call this if a server only supports the nil
 * type, as is typical.
 */
RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid )
{
  RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL;
  RPC_STATUS dummy;

  TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid));
  if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) {
    /* nil uuid cannot be remapped */
    return RPC_S_INVALID_OBJECT;
  }

  /* find the mapping for this object if there is one ... */
  while (map) {
    if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break;
    prev = map;
    map = map->next;
  }
  if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) {
    /* ... and drop it from the list */
    if (map) {
      if (prev) 
        prev->next = map->next;
      else
        RpcObjTypeMaps = map->next;
      HeapFree(GetProcessHeap(), 0, map);
    }
  } else {
    /* ... , fail if we found it ... */
    if (map)
      return RPC_S_ALREADY_REGISTERED;
    /* ... otherwise create a new one and add it in. */
    map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap));
1273 1274
    map->Object = *ObjUuid;
    map->Type = *TypeUuid;
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284
    map->next = NULL;
    if (prev)
      prev->next = map; /* prev is the last map in the linklist */
    else
      RpcObjTypeMaps = map;
  }

  return RPC_S_OK;
}

1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327
struct rpc_server_registered_auth_info
{
    struct list entry;
    TimeStamp exp;
    CredHandle cred;
    ULONG max_token;
    USHORT auth_type;
};

RPC_STATUS RPCRT4_ServerGetRegisteredAuthInfo(
    USHORT auth_type, CredHandle *cred, TimeStamp *exp, ULONG *max_token)
{
    RPC_STATUS status = RPC_S_UNKNOWN_AUTHN_SERVICE;
    struct rpc_server_registered_auth_info *auth_info;

    EnterCriticalSection(&server_auth_info_cs);
    LIST_FOR_EACH_ENTRY(auth_info, &server_registered_auth_info, struct rpc_server_registered_auth_info, entry)
    {
        if (auth_info->auth_type == auth_type)
        {
            *cred = auth_info->cred;
            *exp = auth_info->exp;
            *max_token = auth_info->max_token;
            status = RPC_S_OK;
            break;
        }
    }
    LeaveCriticalSection(&server_auth_info_cs);

    return status;
}

void RPCRT4_ServerFreeAllRegisteredAuthInfo(void)
{
    struct rpc_server_registered_auth_info *auth_info, *cursor2;

    EnterCriticalSection(&server_auth_info_cs);
    LIST_FOR_EACH_ENTRY_SAFE(auth_info, cursor2, &server_registered_auth_info, struct rpc_server_registered_auth_info, entry)
    {
        FreeCredentialsHandle(&auth_info->cred);
        HeapFree(GetProcessHeap(), 0, auth_info);
    }
    LeaveCriticalSection(&server_auth_info_cs);
1328
    DeleteCriticalSection(&server_auth_info_cs);
1329 1330
}

1331 1332 1333
/***********************************************************************
 *             RpcServerRegisterAuthInfoA (RPCRT4.@)
 */
1334
RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( RPC_CSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
1335 1336
                            LPVOID Arg )
{
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
    SECURITY_STATUS sec_status;
    CredHandle cred;
    TimeStamp exp;
    ULONG package_count;
    ULONG i;
    PSecPkgInfoA packages;
    ULONG max_token;
    struct rpc_server_registered_auth_info *auth_info;

    TRACE("(%s,%u,%p,%p)\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg);

    sec_status = EnumerateSecurityPackagesA(&package_count, &packages);
    if (sec_status != SEC_E_OK)
    {
        ERR("EnumerateSecurityPackagesA failed with error 0x%08x\n",
            sec_status);
        return RPC_S_SEC_PKG_ERROR;
    }

    for (i = 0; i < package_count; i++)
        if (packages[i].wRPCID == AuthnSvc)
            break;

    if (i == package_count)
    {
        WARN("unsupported AuthnSvc %u\n", AuthnSvc);
        FreeContextBuffer(packages);
        return RPC_S_UNKNOWN_AUTHN_SERVICE;
    }
    TRACE("found package %s for service %u\n", packages[i].Name,
          AuthnSvc);
    sec_status = AcquireCredentialsHandleA((SEC_CHAR *)ServerPrincName,
                                           packages[i].Name,
                                           SECPKG_CRED_INBOUND, NULL, NULL,
                                           NULL, NULL, &cred, &exp);
    max_token = packages[i].cbMaxToken;
    FreeContextBuffer(packages);
    if (sec_status != SEC_E_OK)
        return RPC_S_SEC_PKG_ERROR;

    auth_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*auth_info));
    if (!auth_info)
    {
        FreeCredentialsHandle(&cred);
        return RPC_S_OUT_OF_RESOURCES;
    }

    auth_info->exp = exp;
    auth_info->cred = cred;
    auth_info->max_token = max_token;
    auth_info->auth_type = AuthnSvc;

    EnterCriticalSection(&server_auth_info_cs);
    list_add_tail(&server_registered_auth_info, &auth_info->entry);
    LeaveCriticalSection(&server_auth_info_cs);

    return RPC_S_OK;
1394 1395 1396 1397 1398
}

/***********************************************************************
 *             RpcServerRegisterAuthInfoW (RPCRT4.@)
 */
1399
RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( RPC_WSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn,
1400 1401
                            LPVOID Arg )
{
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
    SECURITY_STATUS sec_status;
    CredHandle cred;
    TimeStamp exp;
    ULONG package_count;
    ULONG i;
    PSecPkgInfoW packages;
    ULONG max_token;
    struct rpc_server_registered_auth_info *auth_info;

    TRACE("(%s,%u,%p,%p)\n", debugstr_w(ServerPrincName), AuthnSvc, GetKeyFn, Arg);

    sec_status = EnumerateSecurityPackagesW(&package_count, &packages);
    if (sec_status != SEC_E_OK)
    {
        ERR("EnumerateSecurityPackagesW failed with error 0x%08x\n",
            sec_status);
        return RPC_S_SEC_PKG_ERROR;
    }

    for (i = 0; i < package_count; i++)
        if (packages[i].wRPCID == AuthnSvc)
            break;

    if (i == package_count)
    {
        WARN("unsupported AuthnSvc %u\n", AuthnSvc);
        FreeContextBuffer(packages);
        return RPC_S_UNKNOWN_AUTHN_SERVICE;
    }
    TRACE("found package %s for service %u\n", debugstr_w(packages[i].Name),
          AuthnSvc);
    sec_status = AcquireCredentialsHandleW((SEC_WCHAR *)ServerPrincName,
                                           packages[i].Name,
                                           SECPKG_CRED_INBOUND, NULL, NULL,
                                           NULL, NULL, &cred, &exp);
    max_token = packages[i].cbMaxToken;
    FreeContextBuffer(packages);
    if (sec_status != SEC_E_OK)
        return RPC_S_SEC_PKG_ERROR;

    auth_info = HeapAlloc(GetProcessHeap(), 0, sizeof(*auth_info));
    if (!auth_info)
    {
        FreeCredentialsHandle(&cred);
        return RPC_S_OUT_OF_RESOURCES;
    }

    auth_info->exp = exp;
    auth_info->cred = cred;
    auth_info->max_token = max_token;
    auth_info->auth_type = AuthnSvc;

    EnterCriticalSection(&server_auth_info_cs);
    list_add_tail(&server_registered_auth_info, &auth_info->entry);
    LeaveCriticalSection(&server_auth_info_cs);

    return RPC_S_OK;
1459 1460
}

1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
/******************************************************************************
 * RpcServerInqDefaultPrincNameA   (rpcrt4.@)
 */
RPC_STATUS RPC_ENTRY RpcServerInqDefaultPrincNameA(ULONG AuthnSvc, RPC_CSTR *PrincName)
{
    RPC_STATUS ret;
    RPC_WSTR principalW;

    TRACE("%u, %p\n", AuthnSvc, PrincName);

    if ((ret = RpcServerInqDefaultPrincNameW( AuthnSvc, &principalW )) == RPC_S_OK)
    {
        if (!(*PrincName = (RPC_CSTR)RPCRT4_strdupWtoA( principalW ))) return RPC_S_OUT_OF_MEMORY;
        RpcStringFreeW( &principalW );
    }
    return ret;
}

/******************************************************************************
 * RpcServerInqDefaultPrincNameW   (rpcrt4.@)
 */
RPC_STATUS RPC_ENTRY RpcServerInqDefaultPrincNameW(ULONG AuthnSvc, RPC_WSTR *PrincName)
{
    ULONG len = 0;

    FIXME("%u, %p\n", AuthnSvc, PrincName);

    if (AuthnSvc != RPC_C_AUTHN_WINNT) return RPC_S_UNKNOWN_AUTHN_SERVICE;

    GetUserNameExW( NameSamCompatible, NULL, &len );
    if (GetLastError() != ERROR_MORE_DATA) return RPC_S_INTERNAL_ERROR;

    if (!(*PrincName = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
        return RPC_S_OUT_OF_MEMORY;

    GetUserNameExW( NameSamCompatible, *PrincName, &len );
    return RPC_S_OK;
}

1500 1501 1502 1503 1504
/***********************************************************************
 *             RpcServerListen (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait )
{
1505
  RPC_STATUS status = RPC_S_OK;
1506

1507 1508
  TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait);

1509
  if (list_empty(&protseqs))
1510 1511
    return RPC_S_NO_PROTSEQS_REGISTERED;

1512
  status = RPCRT4_start_listen(FALSE);
1513

1514
  if (DontWait || (status != RPC_S_OK)) return status;
1515

1516 1517 1518 1519 1520 1521 1522 1523
  return RpcMgmtWaitServerListen();
}

/***********************************************************************
 *             RpcMgmtServerWaitListen (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcMgmtWaitServerListen( void )
{
1524 1525
  HANDLE event;

1526
  TRACE("()\n");
1527 1528 1529

  EnterCriticalSection(&listen_cs);

1530 1531 1532 1533
  if (!std_listen) {
    LeaveCriticalSection(&listen_cs);
    return RPC_S_NOT_LISTENING;
  }
1534 1535 1536 1537 1538 1539 1540
  if (listen_done_event) {
    LeaveCriticalSection(&listen_cs);
    return RPC_S_ALREADY_LISTENING;
  }
  event = CreateEventW( NULL, TRUE, FALSE, NULL );
  listen_done_event = event;

1541 1542
  LeaveCriticalSection(&listen_cs);

1543 1544 1545
  TRACE( "waiting for server calls to finish\n" );
  WaitForSingleObject( event, INFINITE );
  TRACE( "done waiting\n" );
1546

1547
  CloseHandle( event );
1548
  return RPC_S_OK;
1549 1550
}

1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
/***********************************************************************
 *             RpcMgmtStopServerListening (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding )
{
  TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding);

  if (Binding) {
    FIXME("client-side invocation not implemented.\n");
    return RPC_S_WRONG_KIND_OF_BINDING;
  }
  
1563
  RPCRT4_stop_listen(FALSE);
1564 1565 1566 1567

  return RPC_S_OK;
}

1568 1569 1570 1571 1572 1573 1574 1575 1576
/***********************************************************************
 *             RpcMgmtEnableIdleCleanup (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcMgmtEnableIdleCleanup(void)
{
    FIXME("(): stub\n");
    return RPC_S_OK;
}

1577 1578 1579
/***********************************************************************
 *             I_RpcServerStartListening (RPCRT4.@)
 */
1580
RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd )
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
{
  FIXME( "(%p): stub\n", hWnd );

  return RPC_S_OK;
}

/***********************************************************************
 *             I_RpcServerStopListening (RPCRT4.@)
 */
RPC_STATUS WINAPI I_RpcServerStopListening( void )
{
  FIXME( "(): stub\n" );

  return RPC_S_OK;
}

/***********************************************************************
 *             I_RpcWindowProc (RPCRT4.@)
 */
1600
UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam )
1601
{
1602
  FIXME( "(%p,%08x,%08x,%08x): stub\n", hWnd, Message, wParam, lParam );
1603 1604 1605

  return 0;
}
1606

1607 1608 1609
/***********************************************************************
 *             RpcMgmtInqIfIds (RPCRT4.@)
 */
1610 1611 1612 1613 1614
RPC_STATUS WINAPI RpcMgmtInqIfIds(RPC_BINDING_HANDLE Binding, RPC_IF_ID_VECTOR **IfIdVector)
{
  FIXME("(%p,%p): stub\n", Binding, IfIdVector);
  return RPC_S_INVALID_BINDING;
}
1615

1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
/***********************************************************************
 *             RpcMgmtInqStats (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcMgmtInqStats(RPC_BINDING_HANDLE Binding, RPC_STATS_VECTOR **Statistics)
{
  RPC_STATS_VECTOR *stats;

  FIXME("(%p,%p)\n", Binding, Statistics);

  if ((stats = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_STATS_VECTOR))))
  {
    stats->Count = 1;
    stats->Stats[0] = 0;
    *Statistics = stats;
    return RPC_S_OK;
  }
  return RPC_S_OUT_OF_RESOURCES;
}

/***********************************************************************
 *             RpcMgmtStatsVectorFree (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcMgmtStatsVectorFree(RPC_STATS_VECTOR **StatsVector)
{
  FIXME("(%p)\n", StatsVector);

  if (StatsVector)
  {
    HeapFree(GetProcessHeap(), 0, *StatsVector);
    *StatsVector = NULL;
  }
  return RPC_S_OK;
}

1650 1651 1652
/***********************************************************************
 *             RpcMgmtEpEltInqBegin (RPCRT4.@)
 */
1653 1654
RPC_STATUS WINAPI RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE Binding, ULONG InquiryType,
    RPC_IF_ID *IfId, ULONG VersOption, UUID *ObjectUuid, RPC_EP_INQ_HANDLE* InquiryContext)
1655
{
1656
  FIXME("(%p,%u,%p,%u,%p,%p): stub\n",
1657 1658 1659
        Binding, InquiryType, IfId, VersOption, ObjectUuid, InquiryContext);
  return RPC_S_INVALID_BINDING;
}
1660 1661

/***********************************************************************
1662
 *             RpcMgmtIsServerListening (RPCRT4.@)
1663 1664 1665 1666 1667 1668
 */
RPC_STATUS WINAPI RpcMgmtIsServerListening(RPC_BINDING_HANDLE Binding)
{
  FIXME("(%p): stub\n", Binding);
  return RPC_S_INVALID_BINDING;
}
1669

1670 1671 1672 1673 1674 1675 1676 1677 1678
/***********************************************************************
 *             RpcMgmtSetAuthorizationFn (RPCRT4.@)
 */
RPC_STATUS WINAPI RpcMgmtSetAuthorizationFn(RPC_MGMT_AUTHORIZATION_FN fn)
{
  FIXME("(%p): stub\n", fn);
  return RPC_S_OK;
}

1679 1680 1681
/***********************************************************************
 *             RpcMgmtSetServerStackSize (RPCRT4.@)
 */
1682
RPC_STATUS WINAPI RpcMgmtSetServerStackSize(ULONG ThreadStackSize)
1683
{
1684
  FIXME("(0x%x): stub\n", ThreadStackSize);
1685 1686
  return RPC_S_OK;
}
1687 1688 1689 1690 1691 1692

/***********************************************************************
 *             I_RpcGetCurrentCallHandle (RPCRT4.@)
 */
RPC_BINDING_HANDLE WINAPI I_RpcGetCurrentCallHandle(void)
{
1693 1694
    TRACE("\n");
    return RPCRT4_GetThreadCurrentCallHandle();
1695
}