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