1 /* 2 * RPC transport layer 3 * 4 * Copyright 2001 Ove Kåven, TransGaming Technologies 5 * Copyright 2003 Mike Hearn 6 * Copyright 2004 Filip Navara 7 * Copyright 2006 Mike McCormack 8 * Copyright 2006 Damjan Jovanovic 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Lesser General Public 12 * License as published by the Free Software Foundation; either 13 * version 2.1 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Lesser General Public License for more details. 19 * 20 * You should have received a copy of the GNU Lesser General Public 21 * License along with this library; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 23 * 24 */ 25 26 #include "ntstatus.h" 27 #define WIN32_NO_STATUS 28 #ifdef __REACTOS__ 29 #define NONAMELESSUNION 30 #endif 31 #include "ws2tcpip.h" 32 33 #include <stdarg.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include <assert.h> 37 38 #include "windef.h" 39 #include "winbase.h" 40 #include "winnls.h" 41 #include "winerror.h" 42 #include "wininet.h" 43 #include "wine/winternl.h" 44 #include "winioctl.h" 45 46 #include "rpc.h" 47 #include "rpcndr.h" 48 49 #include "wine/debug.h" 50 51 #include "rpc_binding.h" 52 #include "rpc_assoc.h" 53 #include "rpc_message.h" 54 #include "rpc_server.h" 55 #include "epm_towers.h" 56 57 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000) 58 59 WINE_DEFAULT_DEBUG_CHANNEL(rpc); 60 61 #ifdef __REACTOS__ /* FIXME: Inspect */ 62 BOOL WINAPI CancelIoEx(HANDLE handle, LPOVERLAPPED lpOverlapped) 63 { 64 IO_STATUS_BLOCK io_status; 65 66 NtCancelIoFile(handle, &io_status); 67 if (io_status.u.Status) 68 { 69 SetLastError( RtlNtStatusToDosError( io_status.u.Status ) ); 70 return FALSE; 71 } 72 return TRUE; 73 } 74 #endif 75 76 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection); 77 78 /**** ncacn_np support ****/ 79 80 typedef struct _RpcConnection_np 81 { 82 RpcConnection common; 83 HANDLE pipe; 84 HANDLE listen_event; 85 char *listen_pipe; 86 IO_STATUS_BLOCK io_status; 87 HANDLE event_cache; 88 BOOL read_closed; 89 } RpcConnection_np; 90 91 static RpcConnection *rpcrt4_conn_np_alloc(void) 92 { 93 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_np)); 94 return &npc->common; 95 } 96 97 static HANDLE get_np_event(RpcConnection_np *connection) 98 { 99 HANDLE event = InterlockedExchangePointer(&connection->event_cache, NULL); 100 return event ? event : CreateEventW(NULL, TRUE, FALSE, NULL); 101 } 102 103 static void release_np_event(RpcConnection_np *connection, HANDLE event) 104 { 105 event = InterlockedExchangePointer(&connection->event_cache, event); 106 if (event) 107 CloseHandle(event); 108 } 109 110 #ifdef __REACTOS__ 111 /** 112 * @brief 113 * Creates a security descriptor for RPC4 pipe 114 * 115 * @param[out] SecDesc 116 * A pointer to an allocated security descriptor. 117 * 118 * @return 119 * ERROR_SUCCESS is returned if the function has 120 * successfully created the security descriptor, 121 * otherwise a Win32 error code is returned. 122 * 123 * @remarks 124 * Everyone (aka World SID) and anonynous users 125 * are given a subset of rights to access the pipe, 126 * whereas admins are given full power. 127 */ 128 static DWORD rpcrt4_create_pipe_security(PSECURITY_DESCRIPTOR *SecDesc) 129 { 130 DWORD ErrCode; 131 PACL Dacl; 132 ULONG DaclSize, RelSDSize = 0; 133 PSID EveryoneSid = NULL, AnonymousSid = NULL, AdminsSid = NULL; 134 PSECURITY_DESCRIPTOR AbsSD = NULL, RelSD = NULL; 135 static SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; 136 static SID_IDENTIFIER_AUTHORITY NtAuthority = {SECURITY_NT_AUTHORITY}; 137 138 if (!AllocateAndInitializeSid(&WorldAuthority, 139 1, 140 SECURITY_WORLD_RID, 141 0, 0, 0, 0, 0, 0, 0, 142 &EveryoneSid)) 143 { 144 ERR("rpcrt4_create_pipe_security(): Failed to allocate Everyone SID (error code %d)\n", GetLastError()); 145 return GetLastError(); 146 } 147 148 if (!AllocateAndInitializeSid(&NtAuthority, 149 1, 150 SECURITY_ANONYMOUS_LOGON_RID, 151 0, 0, 0, 0, 0, 0, 0, 152 &AnonymousSid)) 153 { 154 ERR("rpcrt4_create_pipe_security(): Failed to allocate Anonymous SID (error code %d)\n", GetLastError()); 155 ErrCode = GetLastError(); 156 goto Quit; 157 } 158 159 if (!AllocateAndInitializeSid(&NtAuthority, 160 2, 161 SECURITY_BUILTIN_DOMAIN_RID, 162 DOMAIN_ALIAS_RID_ADMINS, 163 0, 0, 0, 0, 0, 0, 164 &AdminsSid)) 165 { 166 ERR("rpcrt4_create_pipe_security(): Failed to allocate Admins SID (error code %d)\n", GetLastError()); 167 ErrCode = GetLastError(); 168 goto Quit; 169 } 170 171 AbsSD = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SECURITY_DESCRIPTOR)); 172 if (AbsSD == NULL) 173 { 174 ERR("rpcrt4_create_pipe_security(): Failed to allocate absolute SD!\n"); 175 ErrCode = ERROR_OUTOFMEMORY; 176 goto Quit; 177 } 178 179 if (!InitializeSecurityDescriptor(AbsSD, SECURITY_DESCRIPTOR_REVISION)) 180 { 181 ERR("rpcrt4_create_pipe_security(): Failed to create absolute SD (error code %d)\n", GetLastError()); 182 ErrCode = GetLastError(); 183 goto Quit; 184 } 185 186 DaclSize = sizeof(ACL) + 187 sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(EveryoneSid) + 188 sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(AnonymousSid) + 189 sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(AdminsSid); 190 191 192 Dacl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DaclSize); 193 if (Dacl == NULL) 194 { 195 ERR("rpcrt4_create_pipe_security(): Failed to allocate DACL!\n"); 196 ErrCode = ERROR_OUTOFMEMORY; 197 goto Quit; 198 } 199 200 if (!InitializeAcl(Dacl, DaclSize, ACL_REVISION)) 201 { 202 ERR("rpcrt4_create_pipe_security(): Failed to create DACL (error code %d)\n", GetLastError()); 203 ErrCode = GetLastError(); 204 goto Quit; 205 } 206 207 if (!AddAccessAllowedAce(Dacl, 208 ACL_REVISION, 209 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | READ_CONTROL, 210 EveryoneSid)) 211 { 212 ERR("rpcrt4_create_pipe_security(): Failed to set up ACE for Everyone SID (error code %d)\n", GetLastError()); 213 ErrCode = GetLastError(); 214 goto Quit; 215 } 216 217 if (!AddAccessAllowedAce(Dacl, 218 ACL_REVISION, 219 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE | READ_CONTROL, 220 AnonymousSid)) 221 { 222 ERR("rpcrt4_create_pipe_security(): Failed to set up ACE for Anonymous SID (error code %d)\n", GetLastError()); 223 ErrCode = GetLastError(); 224 goto Quit; 225 } 226 227 if (!AddAccessAllowedAce(Dacl, 228 ACL_REVISION, 229 GENERIC_ALL, 230 AdminsSid)) 231 { 232 ERR("rpcrt4_create_pipe_security(): Failed to set up ACE for Admins SID (error code %d)\n", GetLastError()); 233 ErrCode = GetLastError(); 234 goto Quit; 235 } 236 237 if (!SetSecurityDescriptorDacl(AbsSD, TRUE, Dacl, FALSE)) 238 { 239 ERR("rpcrt4_create_pipe_security(): Failed to set DACL to absolute SD (error code %d)\n", GetLastError()); 240 ErrCode = GetLastError(); 241 goto Quit; 242 } 243 244 if (!SetSecurityDescriptorOwner(AbsSD, AdminsSid, FALSE)) 245 { 246 ERR("rpcrt4_create_pipe_security(): Failed to set SD owner (error code %d)\n", GetLastError()); 247 ErrCode = GetLastError(); 248 goto Quit; 249 } 250 251 if (!SetSecurityDescriptorGroup(AbsSD, AdminsSid, FALSE)) 252 { 253 ERR("rpcrt4_create_pipe_security(): Failed to set SD group (error code %d)\n", GetLastError()); 254 ErrCode = GetLastError(); 255 goto Quit; 256 } 257 258 if (!MakeSelfRelativeSD(AbsSD, NULL, &RelSDSize) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) 259 { 260 ERR("rpcrt4_create_pipe_security(): Unexpected error code (error code %d -- must be ERROR_INSUFFICIENT_BUFFER)\n", GetLastError()); 261 ErrCode = GetLastError(); 262 goto Quit; 263 } 264 265 RelSD = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, RelSDSize); 266 if (RelSD == NULL) 267 { 268 ERR("rpcrt4_create_pipe_security(): Failed to allocate relative SD!\n"); 269 ErrCode = ERROR_OUTOFMEMORY; 270 goto Quit; 271 } 272 273 if (!MakeSelfRelativeSD(AbsSD, RelSD, &RelSDSize) && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 274 { 275 ERR("rpcrt4_create_pipe_security(): Failed to allocate relative SD, buffer too smal (expected size %lu)\n", RelSDSize); 276 ErrCode = ERROR_INSUFFICIENT_BUFFER; 277 goto Quit; 278 } 279 280 TRACE("rpcrt4_create_pipe_security(): Success!\n"); 281 *SecDesc = RelSD; 282 ErrCode = ERROR_SUCCESS; 283 284 Quit: 285 if (ErrCode != ERROR_SUCCESS) 286 { 287 if (RelSD != NULL) 288 { 289 HeapFree(GetProcessHeap(), 0, RelSD); 290 } 291 } 292 293 if (EveryoneSid != NULL) 294 { 295 FreeSid(EveryoneSid); 296 } 297 298 if (AnonymousSid != NULL) 299 { 300 FreeSid(AnonymousSid); 301 } 302 303 if (AdminsSid != NULL) 304 { 305 FreeSid(AdminsSid); 306 } 307 308 if (Dacl != NULL) 309 { 310 HeapFree(GetProcessHeap(), 0, Dacl); 311 } 312 313 if (AbsSD != NULL) 314 { 315 HeapFree(GetProcessHeap(), 0, AbsSD); 316 } 317 318 return ErrCode; 319 } 320 #endif 321 322 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *conn) 323 { 324 RpcConnection_np *connection = (RpcConnection_np *) conn; 325 #ifdef __REACTOS__ 326 DWORD ErrCode; 327 SECURITY_ATTRIBUTES SecurityAttributes; 328 PSECURITY_DESCRIPTOR PipeSecDesc; 329 #endif 330 331 TRACE("listening on %s\n", connection->listen_pipe); 332 333 #ifdef __REACTOS__ 334 ErrCode = rpcrt4_create_pipe_security(&PipeSecDesc); 335 if (ErrCode != ERROR_SUCCESS) 336 { 337 ERR("rpcrt4_conn_create_pipe(): Pipe security descriptor creation failed!\n"); 338 return RPC_S_CANT_CREATE_ENDPOINT; 339 } 340 341 SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); 342 SecurityAttributes.lpSecurityDescriptor = PipeSecDesc; 343 SecurityAttributes.bInheritHandle = FALSE; 344 345 connection->pipe = CreateNamedPipeA(connection->listen_pipe, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 346 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 347 PIPE_UNLIMITED_INSTANCES, 348 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, &SecurityAttributes); 349 HeapFree(GetProcessHeap(), 0, PipeSecDesc); 350 #else 351 connection->pipe = CreateNamedPipeA(connection->listen_pipe, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 352 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 353 PIPE_UNLIMITED_INSTANCES, 354 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); 355 #endif 356 if (connection->pipe == INVALID_HANDLE_VALUE) 357 { 358 WARN("CreateNamedPipe failed with error %d\n", GetLastError()); 359 if (GetLastError() == ERROR_FILE_EXISTS) 360 { 361 return RPC_S_DUPLICATE_ENDPOINT; 362 } 363 else 364 { 365 return RPC_S_CANT_CREATE_ENDPOINT; 366 } 367 } 368 369 return RPC_S_OK; 370 } 371 372 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait) 373 { 374 RpcConnection_np *npc = (RpcConnection_np *) Connection; 375 HANDLE pipe; 376 DWORD err, dwMode; 377 378 TRACE("connecting to %s\n", pname); 379 380 while (TRUE) { 381 DWORD dwFlags = 0; 382 if (Connection->QOS) 383 { 384 dwFlags = SECURITY_SQOS_PRESENT; 385 switch (Connection->QOS->qos->ImpersonationType) 386 { 387 case RPC_C_IMP_LEVEL_DEFAULT: 388 /* FIXME: what to do here? */ 389 break; 390 case RPC_C_IMP_LEVEL_ANONYMOUS: 391 dwFlags |= SECURITY_ANONYMOUS; 392 break; 393 case RPC_C_IMP_LEVEL_IDENTIFY: 394 dwFlags |= SECURITY_IDENTIFICATION; 395 break; 396 case RPC_C_IMP_LEVEL_IMPERSONATE: 397 dwFlags |= SECURITY_IMPERSONATION; 398 break; 399 case RPC_C_IMP_LEVEL_DELEGATE: 400 dwFlags |= SECURITY_DELEGATION; 401 break; 402 } 403 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC) 404 dwFlags |= SECURITY_CONTEXT_TRACKING; 405 } 406 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, 407 OPEN_EXISTING, dwFlags | FILE_FLAG_OVERLAPPED, 0); 408 if (pipe != INVALID_HANDLE_VALUE) break; 409 err = GetLastError(); 410 if (err == ERROR_PIPE_BUSY) { 411 if (WaitNamedPipeA(pname, NMPWAIT_USE_DEFAULT_WAIT)) { 412 TRACE("retrying busy server\n"); 413 continue; 414 } 415 TRACE("connection failed, error=%x\n", err); 416 return RPC_S_SERVER_TOO_BUSY; 417 #ifdef __REACTOS__ 418 } else if (err == ERROR_BAD_NETPATH) { 419 TRACE("connection failed, error=%x\n", err); 420 return RPC_S_SERVER_UNAVAILABLE; 421 #endif 422 } 423 if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) { 424 err = GetLastError(); 425 WARN("connection failed, error=%x\n", err); 426 return RPC_S_SERVER_UNAVAILABLE; 427 } 428 } 429 430 /* success */ 431 /* pipe is connected; change to message-read mode. */ 432 dwMode = PIPE_READMODE_MESSAGE; 433 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL); 434 npc->pipe = pipe; 435 436 return RPC_S_OK; 437 } 438 439 static char *ncalrpc_pipe_name(const char *endpoint) 440 { 441 static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; 442 char *pipe_name; 443 444 /* protseq=ncalrpc: supposed to use NT LPC ports, 445 * but we'll implement it with named pipes for now */ 446 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint)); 447 strcat(strcpy(pipe_name, prefix), endpoint); 448 return pipe_name; 449 } 450 451 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection) 452 { 453 RpcConnection_np *npc = (RpcConnection_np *) Connection; 454 RPC_STATUS r; 455 LPSTR pname; 456 457 /* already connected? */ 458 if (npc->pipe) 459 return RPC_S_OK; 460 461 pname = ncalrpc_pipe_name(Connection->Endpoint); 462 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE); 463 I_RpcFree(pname); 464 465 return r; 466 } 467 468 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint) 469 { 470 RPC_STATUS r; 471 RpcConnection *Connection; 472 char generated_endpoint[22]; 473 474 if (!endpoint) 475 { 476 static LONG lrpc_nameless_id; 477 DWORD process_id = GetCurrentProcessId(); 478 ULONG id = InterlockedIncrement(&lrpc_nameless_id); 479 snprintf(generated_endpoint, sizeof(generated_endpoint), 480 "LRPC%08x.%08x", process_id, id); 481 endpoint = generated_endpoint; 482 } 483 484 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, 485 endpoint, NULL, NULL, NULL, NULL); 486 if (r != RPC_S_OK) 487 return r; 488 489 ((RpcConnection_np*)Connection)->listen_pipe = ncalrpc_pipe_name(Connection->Endpoint); 490 r = rpcrt4_conn_create_pipe(Connection); 491 492 EnterCriticalSection(&protseq->cs); 493 list_add_head(&protseq->listeners, &Connection->protseq_entry); 494 Connection->protseq = protseq; 495 LeaveCriticalSection(&protseq->cs); 496 497 return r; 498 } 499 500 #ifdef __REACTOS__ 501 static char *ncacn_pipe_name(const char *server, const char *endpoint) 502 #else 503 static char *ncacn_pipe_name(const char *endpoint) 504 #endif 505 { 506 #ifdef __REACTOS__ 507 static const char prefix[] = "\\\\"; 508 static const char local[] = "."; 509 char ComputerName[MAX_COMPUTERNAME_LENGTH + 1]; 510 DWORD bufLen = ARRAY_SIZE(ComputerName); 511 #else 512 static const char prefix[] = "\\\\."; 513 #endif 514 char *pipe_name; 515 516 #ifdef __REACTOS__ 517 if (server != NULL && *server != 0) 518 { 519 /* Trim any leading UNC server prefix. */ 520 if (server[0] == '\\' && server[1] == '\\') 521 server += 2; 522 523 /* If the server represents the local computer, use instead 524 * the local prefix to avoid a round in UNC name resolution. */ 525 if (GetComputerNameA(ComputerName, &bufLen) && 526 (stricmp(ComputerName, server) == 0)) 527 { 528 server = local; 529 } 530 } 531 else 532 { 533 server = local; 534 } 535 #endif 536 537 /* protseq=ncacn_np: named pipes */ 538 #ifdef __REACTOS__ 539 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(server) + strlen(endpoint)); 540 strcpy(pipe_name, prefix); 541 strcat(pipe_name, server); 542 strcat(pipe_name, endpoint); 543 #else 544 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint)); 545 strcat(strcpy(pipe_name, prefix), endpoint); 546 #endif 547 return pipe_name; 548 } 549 550 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection) 551 { 552 RpcConnection_np *npc = (RpcConnection_np *) Connection; 553 RPC_STATUS r; 554 LPSTR pname; 555 556 /* already connected? */ 557 if (npc->pipe) 558 return RPC_S_OK; 559 560 #ifdef __REACTOS__ 561 pname = ncacn_pipe_name(Connection->NetworkAddr, Connection->Endpoint); 562 #else 563 pname = ncacn_pipe_name(Connection->Endpoint); 564 #endif 565 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE); 566 I_RpcFree(pname); 567 568 return r; 569 } 570 571 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint) 572 { 573 RPC_STATUS r; 574 RpcConnection *Connection; 575 char generated_endpoint[26]; 576 577 if (!endpoint) 578 { 579 static LONG np_nameless_id; 580 DWORD process_id = GetCurrentProcessId(); 581 ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 ); 582 snprintf(generated_endpoint, sizeof(generated_endpoint), 583 "\\\\pipe\\\\%08x.%03x", process_id, id); 584 endpoint = generated_endpoint; 585 } 586 587 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, 588 endpoint, NULL, NULL, NULL, NULL); 589 if (r != RPC_S_OK) 590 return r; 591 592 #ifdef __REACTOS__ 593 ((RpcConnection_np*)Connection)->listen_pipe = ncacn_pipe_name(NULL, Connection->Endpoint); 594 #else 595 ((RpcConnection_np*)Connection)->listen_pipe = ncacn_pipe_name(Connection->Endpoint); 596 #endif 597 r = rpcrt4_conn_create_pipe(Connection); 598 599 EnterCriticalSection(&protseq->cs); 600 list_add_head(&protseq->listeners, &Connection->protseq_entry); 601 Connection->protseq = protseq; 602 LeaveCriticalSection(&protseq->cs); 603 604 return r; 605 } 606 607 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc) 608 { 609 /* because of the way named pipes work, we'll transfer the connected pipe 610 * to the child, then reopen the server binding to continue listening */ 611 612 new_npc->pipe = old_npc->pipe; 613 old_npc->pipe = 0; 614 assert(!old_npc->listen_event); 615 } 616 617 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn) 618 { 619 DWORD len = MAX_COMPUTERNAME_LENGTH + 1; 620 RPC_STATUS status; 621 622 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); 623 status = rpcrt4_conn_create_pipe(old_conn); 624 625 /* Store the local computer name as the NetworkAddr for ncacn_np as long as 626 * we don't support named pipes over the network. */ 627 new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len); 628 if (!GetComputerNameA(new_conn->NetworkAddr, &len)) 629 { 630 ERR("Failed to retrieve the computer name, error %u\n", GetLastError()); 631 return RPC_S_OUT_OF_RESOURCES; 632 } 633 634 return status; 635 } 636 637 static RPC_STATUS is_pipe_listening(const char *pipe_name) 638 { 639 return WaitNamedPipeA(pipe_name, 1) ? RPC_S_OK : RPC_S_NOT_LISTENING; 640 } 641 642 static RPC_STATUS rpcrt4_ncacn_np_is_server_listening(const char *endpoint) 643 { 644 char *pipe_name; 645 RPC_STATUS status; 646 647 #ifdef __REACTOS__ 648 pipe_name = ncacn_pipe_name(NULL, endpoint); 649 #else 650 pipe_name = ncacn_pipe_name(endpoint); 651 #endif 652 status = is_pipe_listening(pipe_name); 653 I_RpcFree(pipe_name); 654 return status; 655 } 656 657 static RPC_STATUS rpcrt4_ncalrpc_np_is_server_listening(const char *endpoint) 658 { 659 char *pipe_name; 660 RPC_STATUS status; 661 662 pipe_name = ncalrpc_pipe_name(endpoint); 663 status = is_pipe_listening(pipe_name); 664 I_RpcFree(pipe_name); 665 return status; 666 } 667 668 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn) 669 { 670 DWORD len = MAX_COMPUTERNAME_LENGTH + 1; 671 RPC_STATUS status; 672 673 TRACE("%s\n", old_conn->Endpoint); 674 675 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); 676 status = rpcrt4_conn_create_pipe(old_conn); 677 678 /* Store the local computer name as the NetworkAddr for ncalrpc. */ 679 new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len); 680 if (!GetComputerNameA(new_conn->NetworkAddr, &len)) 681 { 682 ERR("Failed to retrieve the computer name, error %u\n", GetLastError()); 683 return RPC_S_OUT_OF_RESOURCES; 684 } 685 686 return status; 687 } 688 689 static int rpcrt4_conn_np_read(RpcConnection *conn, void *buffer, unsigned int count) 690 { 691 RpcConnection_np *connection = (RpcConnection_np *) conn; 692 HANDLE event; 693 NTSTATUS status; 694 695 event = get_np_event(connection); 696 if (!event) 697 return -1; 698 699 if (connection->read_closed) 700 status = STATUS_CANCELLED; 701 else 702 status = NtReadFile(connection->pipe, event, NULL, NULL, &connection->io_status, buffer, count, NULL, NULL); 703 if (status == STATUS_PENDING) 704 { 705 /* check read_closed again before waiting to avoid a race */ 706 if (connection->read_closed) 707 { 708 IO_STATUS_BLOCK io_status; 709 #ifdef __REACTOS__ /* FIXME: We should also cancel I/O for other threads */ 710 NtCancelIoFile(connection->pipe, &io_status); 711 #else 712 NtCancelIoFileEx(connection->pipe, &connection->io_status, &io_status); 713 #endif 714 } 715 WaitForSingleObject(event, INFINITE); 716 status = connection->io_status.u.Status; 717 } 718 release_np_event(connection, event); 719 return status && status != STATUS_BUFFER_OVERFLOW ? -1 : connection->io_status.Information; 720 } 721 722 static int rpcrt4_conn_np_write(RpcConnection *conn, const void *buffer, unsigned int count) 723 { 724 RpcConnection_np *connection = (RpcConnection_np *) conn; 725 IO_STATUS_BLOCK io_status; 726 HANDLE event; 727 NTSTATUS status; 728 729 event = get_np_event(connection); 730 if (!event) 731 return -1; 732 733 status = NtWriteFile(connection->pipe, event, NULL, NULL, &io_status, buffer, count, NULL, NULL); 734 if (status == STATUS_PENDING) 735 { 736 WaitForSingleObject(event, INFINITE); 737 status = io_status.u.Status; 738 } 739 release_np_event(connection, event); 740 if (status) 741 return -1; 742 743 assert(io_status.Information == count); 744 return count; 745 } 746 747 static int rpcrt4_conn_np_close(RpcConnection *conn) 748 { 749 RpcConnection_np *connection = (RpcConnection_np *) conn; 750 if (connection->pipe) 751 { 752 FlushFileBuffers(connection->pipe); 753 CloseHandle(connection->pipe); 754 connection->pipe = 0; 755 } 756 if (connection->listen_event) 757 { 758 CloseHandle(connection->listen_event); 759 connection->listen_event = 0; 760 } 761 if (connection->event_cache) 762 { 763 CloseHandle(connection->event_cache); 764 connection->event_cache = 0; 765 } 766 return 0; 767 } 768 769 static void rpcrt4_conn_np_close_read(RpcConnection *conn) 770 { 771 RpcConnection_np *connection = (RpcConnection_np*)conn; 772 IO_STATUS_BLOCK io_status; 773 774 connection->read_closed = TRUE; 775 #ifdef __REACTOS__ /* FIXME: We should also cancel I/O for other threads */ 776 NtCancelIoFile(connection->pipe, &io_status); 777 #else 778 NtCancelIoFileEx(connection->pipe, &connection->io_status, &io_status); 779 #endif 780 } 781 782 static void rpcrt4_conn_np_cancel_call(RpcConnection *conn) 783 { 784 RpcConnection_np *connection = (RpcConnection_np *)conn; 785 CancelIoEx(connection->pipe, NULL); 786 } 787 788 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *conn) 789 { 790 return rpcrt4_conn_np_read(conn, NULL, 0); 791 } 792 793 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data, 794 const char *networkaddr, 795 const char *endpoint) 796 { 797 twr_empty_floor_t *smb_floor; 798 twr_empty_floor_t *nb_floor; 799 size_t size; 800 size_t networkaddr_size; 801 size_t endpoint_size; 802 803 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); 804 805 networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1; 806 endpoint_size = endpoint ? strlen(endpoint) + 1 : 1; 807 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size; 808 809 if (!tower_data) 810 return size; 811 812 smb_floor = (twr_empty_floor_t *)tower_data; 813 814 tower_data += sizeof(*smb_floor); 815 816 smb_floor->count_lhs = sizeof(smb_floor->protid); 817 smb_floor->protid = EPM_PROTOCOL_SMB; 818 smb_floor->count_rhs = endpoint_size; 819 820 if (endpoint) 821 memcpy(tower_data, endpoint, endpoint_size); 822 else 823 tower_data[0] = 0; 824 tower_data += endpoint_size; 825 826 nb_floor = (twr_empty_floor_t *)tower_data; 827 828 tower_data += sizeof(*nb_floor); 829 830 nb_floor->count_lhs = sizeof(nb_floor->protid); 831 nb_floor->protid = EPM_PROTOCOL_NETBIOS; 832 nb_floor->count_rhs = networkaddr_size; 833 834 if (networkaddr) 835 memcpy(tower_data, networkaddr, networkaddr_size); 836 else 837 tower_data[0] = 0; 838 839 return size; 840 } 841 842 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data, 843 size_t tower_size, 844 char **networkaddr, 845 char **endpoint) 846 { 847 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data; 848 const twr_empty_floor_t *nb_floor; 849 850 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); 851 852 if (tower_size < sizeof(*smb_floor)) 853 return EPT_S_NOT_REGISTERED; 854 855 tower_data += sizeof(*smb_floor); 856 tower_size -= sizeof(*smb_floor); 857 858 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) || 859 (smb_floor->protid != EPM_PROTOCOL_SMB) || 860 (smb_floor->count_rhs > tower_size) || 861 (tower_data[smb_floor->count_rhs - 1] != '\0')) 862 return EPT_S_NOT_REGISTERED; 863 864 if (endpoint) 865 { 866 *endpoint = I_RpcAllocate(smb_floor->count_rhs); 867 if (!*endpoint) 868 return RPC_S_OUT_OF_RESOURCES; 869 memcpy(*endpoint, tower_data, smb_floor->count_rhs); 870 } 871 tower_data += smb_floor->count_rhs; 872 tower_size -= smb_floor->count_rhs; 873 874 if (tower_size < sizeof(*nb_floor)) 875 return EPT_S_NOT_REGISTERED; 876 877 nb_floor = (const twr_empty_floor_t *)tower_data; 878 879 tower_data += sizeof(*nb_floor); 880 tower_size -= sizeof(*nb_floor); 881 882 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) || 883 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) || 884 (nb_floor->count_rhs > tower_size) || 885 (tower_data[nb_floor->count_rhs - 1] != '\0')) 886 return EPT_S_NOT_REGISTERED; 887 888 if (networkaddr) 889 { 890 *networkaddr = I_RpcAllocate(nb_floor->count_rhs); 891 if (!*networkaddr) 892 { 893 if (endpoint) 894 { 895 I_RpcFree(*endpoint); 896 *endpoint = NULL; 897 } 898 return RPC_S_OUT_OF_RESOURCES; 899 } 900 memcpy(*networkaddr, tower_data, nb_floor->count_rhs); 901 } 902 903 return RPC_S_OK; 904 } 905 906 static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn) 907 { 908 RpcConnection_np *npc = (RpcConnection_np *)conn; 909 BOOL ret; 910 911 TRACE("(%p)\n", conn); 912 913 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx)) 914 return RPCRT4_default_impersonate_client(conn); 915 916 ret = ImpersonateNamedPipeClient(npc->pipe); 917 if (!ret) 918 { 919 DWORD error = GetLastError(); 920 WARN("ImpersonateNamedPipeClient failed with error %u\n", error); 921 switch (error) 922 { 923 case ERROR_CANNOT_IMPERSONATE: 924 return RPC_S_NO_CONTEXT_AVAILABLE; 925 } 926 } 927 return RPC_S_OK; 928 } 929 930 static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn) 931 { 932 BOOL ret; 933 934 TRACE("(%p)\n", conn); 935 936 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx)) 937 return RPCRT4_default_revert_to_self(conn); 938 939 ret = RevertToSelf(); 940 if (!ret) 941 { 942 WARN("RevertToSelf failed with error %u\n", GetLastError()); 943 return RPC_S_NO_CONTEXT_AVAILABLE; 944 } 945 return RPC_S_OK; 946 } 947 948 typedef struct _RpcServerProtseq_np 949 { 950 RpcServerProtseq common; 951 HANDLE mgr_event; 952 } RpcServerProtseq_np; 953 954 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void) 955 { 956 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps)); 957 if (ps) 958 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); 959 return &ps->common; 960 } 961 962 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq) 963 { 964 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common); 965 SetEvent(npps->mgr_event); 966 } 967 968 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) 969 { 970 HANDLE *objs = prev_array; 971 RpcConnection_np *conn; 972 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common); 973 974 EnterCriticalSection(&protseq->cs); 975 976 /* open and count connections */ 977 *count = 1; 978 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry) 979 { 980 if (!conn->pipe && rpcrt4_conn_create_pipe(&conn->common) != RPC_S_OK) 981 continue; 982 if (!conn->listen_event) 983 { 984 NTSTATUS status; 985 HANDLE event; 986 987 event = get_np_event(conn); 988 if (!event) 989 continue; 990 991 status = NtFsControlFile(conn->pipe, event, NULL, NULL, &conn->io_status, FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0); 992 switch (status) 993 { 994 case STATUS_SUCCESS: 995 case STATUS_PIPE_CONNECTED: 996 conn->io_status.u.Status = status; 997 SetEvent(event); 998 break; 999 case STATUS_PENDING: 1000 break; 1001 default: 1002 ERR("pipe listen error %x\n", status); 1003 continue; 1004 } 1005 1006 conn->listen_event = event; 1007 } 1008 (*count)++; 1009 } 1010 1011 /* make array of connections */ 1012 if (objs) 1013 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE)); 1014 else 1015 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE)); 1016 if (!objs) 1017 { 1018 ERR("couldn't allocate objs\n"); 1019 LeaveCriticalSection(&protseq->cs); 1020 return NULL; 1021 } 1022 1023 objs[0] = npps->mgr_event; 1024 *count = 1; 1025 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry) 1026 { 1027 if (conn->listen_event) 1028 objs[(*count)++] = conn->listen_event; 1029 } 1030 LeaveCriticalSection(&protseq->cs); 1031 return objs; 1032 } 1033 1034 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array) 1035 { 1036 HeapFree(GetProcessHeap(), 0, array); 1037 } 1038 1039 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array) 1040 { 1041 HANDLE b_handle; 1042 HANDLE *objs = wait_array; 1043 DWORD res; 1044 RpcConnection *cconn = NULL; 1045 RpcConnection_np *conn; 1046 1047 if (!objs) 1048 return -1; 1049 1050 do 1051 { 1052 /* an alertable wait isn't strictly necessary, but due to our 1053 * overlapped I/O implementation in Wine we need to free some memory 1054 * by the file user APC being called, even if no completion routine was 1055 * specified at the time of starting the async operation */ 1056 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE); 1057 } while (res == WAIT_IO_COMPLETION); 1058 1059 if (res == WAIT_OBJECT_0) 1060 return 0; 1061 else if (res == WAIT_FAILED) 1062 { 1063 ERR("wait failed with error %d\n", GetLastError()); 1064 return -1; 1065 } 1066 else 1067 { 1068 b_handle = objs[res - WAIT_OBJECT_0]; 1069 /* find which connection got a RPC */ 1070 EnterCriticalSection(&protseq->cs); 1071 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry) 1072 { 1073 if (b_handle == conn->listen_event) 1074 { 1075 release_np_event(conn, conn->listen_event); 1076 conn->listen_event = NULL; 1077 if (conn->io_status.u.Status == STATUS_SUCCESS || conn->io_status.u.Status == STATUS_PIPE_CONNECTED) 1078 cconn = rpcrt4_spawn_connection(&conn->common); 1079 else 1080 ERR("listen failed %x\n", conn->io_status.u.Status); 1081 break; 1082 } 1083 } 1084 LeaveCriticalSection(&protseq->cs); 1085 if (!cconn) 1086 { 1087 ERR("failed to locate connection for handle %p\n", b_handle); 1088 return -1; 1089 } 1090 RPCRT4_new_client(cconn); 1091 return 1; 1092 } 1093 } 1094 1095 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data, 1096 const char *networkaddr, 1097 const char *endpoint) 1098 { 1099 twr_empty_floor_t *pipe_floor; 1100 size_t size; 1101 size_t endpoint_size; 1102 1103 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); 1104 1105 endpoint_size = strlen(endpoint) + 1; 1106 size = sizeof(*pipe_floor) + endpoint_size; 1107 1108 if (!tower_data) 1109 return size; 1110 1111 pipe_floor = (twr_empty_floor_t *)tower_data; 1112 1113 tower_data += sizeof(*pipe_floor); 1114 1115 pipe_floor->count_lhs = sizeof(pipe_floor->protid); 1116 pipe_floor->protid = EPM_PROTOCOL_PIPE; 1117 pipe_floor->count_rhs = endpoint_size; 1118 1119 memcpy(tower_data, endpoint, endpoint_size); 1120 1121 return size; 1122 } 1123 1124 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data, 1125 size_t tower_size, 1126 char **networkaddr, 1127 char **endpoint) 1128 { 1129 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data; 1130 1131 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); 1132 1133 if (tower_size < sizeof(*pipe_floor)) 1134 return EPT_S_NOT_REGISTERED; 1135 1136 tower_data += sizeof(*pipe_floor); 1137 tower_size -= sizeof(*pipe_floor); 1138 1139 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) || 1140 (pipe_floor->protid != EPM_PROTOCOL_PIPE) || 1141 (pipe_floor->count_rhs > tower_size) || 1142 (tower_data[pipe_floor->count_rhs - 1] != '\0')) 1143 return EPT_S_NOT_REGISTERED; 1144 1145 if (networkaddr) 1146 *networkaddr = NULL; 1147 1148 if (endpoint) 1149 { 1150 *endpoint = I_RpcAllocate(pipe_floor->count_rhs); 1151 if (!*endpoint) 1152 return RPC_S_OUT_OF_RESOURCES; 1153 memcpy(*endpoint, tower_data, pipe_floor->count_rhs); 1154 } 1155 1156 return RPC_S_OK; 1157 } 1158 1159 static BOOL rpcrt4_ncalrpc_is_authorized(RpcConnection *conn) 1160 { 1161 return FALSE; 1162 } 1163 1164 static RPC_STATUS rpcrt4_ncalrpc_authorize(RpcConnection *conn, BOOL first_time, 1165 unsigned char *in_buffer, 1166 unsigned int in_size, 1167 unsigned char *out_buffer, 1168 unsigned int *out_size) 1169 { 1170 /* since this protocol is local to the machine there is no need to 1171 * authenticate the caller */ 1172 *out_size = 0; 1173 return RPC_S_OK; 1174 } 1175 1176 static RPC_STATUS rpcrt4_ncalrpc_secure_packet(RpcConnection *conn, 1177 enum secure_packet_direction dir, 1178 RpcPktHdr *hdr, unsigned int hdr_size, 1179 unsigned char *stub_data, unsigned int stub_data_size, 1180 RpcAuthVerifier *auth_hdr, 1181 unsigned char *auth_value, unsigned int auth_value_size) 1182 { 1183 /* since this protocol is local to the machine there is no need to secure 1184 * the packet */ 1185 return RPC_S_OK; 1186 } 1187 1188 static RPC_STATUS rpcrt4_ncalrpc_inquire_auth_client( 1189 RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name, 1190 ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags) 1191 { 1192 TRACE("(%p, %p, %p, %p, %p, %p, 0x%x)\n", conn, privs, 1193 server_princ_name, authn_level, authn_svc, authz_svc, flags); 1194 1195 if (privs) 1196 { 1197 FIXME("privs not implemented\n"); 1198 *privs = NULL; 1199 } 1200 if (server_princ_name) 1201 { 1202 FIXME("server_princ_name not implemented\n"); 1203 *server_princ_name = NULL; 1204 } 1205 if (authn_level) *authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY; 1206 if (authn_svc) *authn_svc = RPC_C_AUTHN_WINNT; 1207 if (authz_svc) 1208 { 1209 FIXME("authorization service not implemented\n"); 1210 *authz_svc = RPC_C_AUTHZ_NONE; 1211 } 1212 if (flags) 1213 FIXME("flags 0x%x not implemented\n", flags); 1214 1215 return RPC_S_OK; 1216 } 1217 1218 /**** ncacn_ip_tcp support ****/ 1219 1220 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data, 1221 const char *networkaddr, 1222 unsigned char tcp_protid, 1223 const char *endpoint) 1224 { 1225 twr_tcp_floor_t *tcp_floor; 1226 twr_ipv4_floor_t *ipv4_floor; 1227 struct addrinfo *ai; 1228 struct addrinfo hints; 1229 int ret; 1230 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor); 1231 1232 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); 1233 1234 if (!tower_data) 1235 return size; 1236 1237 tcp_floor = (twr_tcp_floor_t *)tower_data; 1238 tower_data += sizeof(*tcp_floor); 1239 1240 ipv4_floor = (twr_ipv4_floor_t *)tower_data; 1241 1242 tcp_floor->count_lhs = sizeof(tcp_floor->protid); 1243 tcp_floor->protid = tcp_protid; 1244 tcp_floor->count_rhs = sizeof(tcp_floor->port); 1245 1246 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid); 1247 ipv4_floor->protid = EPM_PROTOCOL_IP; 1248 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr); 1249 1250 hints.ai_flags = AI_NUMERICHOST; 1251 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */ 1252 hints.ai_family = PF_INET; 1253 hints.ai_socktype = SOCK_STREAM; 1254 hints.ai_protocol = IPPROTO_TCP; 1255 hints.ai_addrlen = 0; 1256 hints.ai_addr = NULL; 1257 hints.ai_canonname = NULL; 1258 hints.ai_next = NULL; 1259 1260 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai); 1261 if (ret) 1262 { 1263 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai); 1264 if (ret) 1265 { 1266 ERR("getaddrinfo failed: %s\n", gai_strerror(ret)); 1267 return 0; 1268 } 1269 } 1270 1271 if (ai->ai_family == PF_INET) 1272 { 1273 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr; 1274 tcp_floor->port = sin->sin_port; 1275 ipv4_floor->ipv4addr = sin->sin_addr.s_addr; 1276 } 1277 else 1278 { 1279 ERR("unexpected protocol family %d\n", ai->ai_family); 1280 freeaddrinfo(ai); 1281 return 0; 1282 } 1283 1284 freeaddrinfo(ai); 1285 1286 return size; 1287 } 1288 1289 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, 1290 size_t tower_size, 1291 char **networkaddr, 1292 unsigned char tcp_protid, 1293 char **endpoint) 1294 { 1295 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data; 1296 const twr_ipv4_floor_t *ipv4_floor; 1297 struct in_addr in_addr; 1298 1299 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); 1300 1301 if (tower_size < sizeof(*tcp_floor)) 1302 return EPT_S_NOT_REGISTERED; 1303 1304 tower_data += sizeof(*tcp_floor); 1305 tower_size -= sizeof(*tcp_floor); 1306 1307 if (tower_size < sizeof(*ipv4_floor)) 1308 return EPT_S_NOT_REGISTERED; 1309 1310 ipv4_floor = (const twr_ipv4_floor_t *)tower_data; 1311 1312 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) || 1313 (tcp_floor->protid != tcp_protid) || 1314 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) || 1315 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) || 1316 (ipv4_floor->protid != EPM_PROTOCOL_IP) || 1317 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr))) 1318 return EPT_S_NOT_REGISTERED; 1319 1320 if (endpoint) 1321 { 1322 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */); 1323 if (!*endpoint) 1324 return RPC_S_OUT_OF_RESOURCES; 1325 sprintf(*endpoint, "%u", ntohs(tcp_floor->port)); 1326 } 1327 1328 if (networkaddr) 1329 { 1330 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN); 1331 if (!*networkaddr) 1332 { 1333 if (endpoint) 1334 { 1335 I_RpcFree(*endpoint); 1336 *endpoint = NULL; 1337 } 1338 return RPC_S_OUT_OF_RESOURCES; 1339 } 1340 in_addr.s_addr = ipv4_floor->ipv4addr; 1341 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN)) 1342 { 1343 ERR("inet_ntop: %u\n", WSAGetLastError()); 1344 I_RpcFree(*networkaddr); 1345 *networkaddr = NULL; 1346 if (endpoint) 1347 { 1348 I_RpcFree(*endpoint); 1349 *endpoint = NULL; 1350 } 1351 return EPT_S_NOT_REGISTERED; 1352 } 1353 } 1354 1355 return RPC_S_OK; 1356 } 1357 1358 typedef struct _RpcConnection_tcp 1359 { 1360 RpcConnection common; 1361 int sock; 1362 HANDLE sock_event; 1363 HANDLE cancel_event; 1364 } RpcConnection_tcp; 1365 1366 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc) 1367 { 1368 static BOOL wsa_inited; 1369 if (!wsa_inited) 1370 { 1371 WSADATA wsadata; 1372 WSAStartup(MAKEWORD(2, 2), &wsadata); 1373 /* Note: WSAStartup can be called more than once so we don't bother with 1374 * making accesses to wsa_inited thread-safe */ 1375 wsa_inited = TRUE; 1376 } 1377 tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1378 tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1379 if (!tcpc->sock_event || !tcpc->cancel_event) 1380 { 1381 ERR("event creation failed\n"); 1382 if (tcpc->sock_event) CloseHandle(tcpc->sock_event); 1383 return FALSE; 1384 } 1385 return TRUE; 1386 } 1387 1388 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc) 1389 { 1390 HANDLE wait_handles[2]; 1391 DWORD res; 1392 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR) 1393 { 1394 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); 1395 return FALSE; 1396 } 1397 wait_handles[0] = tcpc->sock_event; 1398 wait_handles[1] = tcpc->cancel_event; 1399 res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE); 1400 switch (res) 1401 { 1402 case WAIT_OBJECT_0: 1403 return TRUE; 1404 case WAIT_OBJECT_0 + 1: 1405 return FALSE; 1406 default: 1407 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError()); 1408 return FALSE; 1409 } 1410 } 1411 1412 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc) 1413 { 1414 DWORD res; 1415 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR) 1416 { 1417 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); 1418 return FALSE; 1419 } 1420 res = WaitForSingleObject(tcpc->sock_event, INFINITE); 1421 switch (res) 1422 { 1423 case WAIT_OBJECT_0: 1424 return TRUE; 1425 default: 1426 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError()); 1427 return FALSE; 1428 } 1429 } 1430 1431 static RpcConnection *rpcrt4_conn_tcp_alloc(void) 1432 { 1433 RpcConnection_tcp *tcpc; 1434 tcpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp)); 1435 if (tcpc == NULL) 1436 return NULL; 1437 tcpc->sock = -1; 1438 if (!rpcrt4_sock_wait_init(tcpc)) 1439 { 1440 HeapFree(GetProcessHeap(), 0, tcpc); 1441 return NULL; 1442 } 1443 return &tcpc->common; 1444 } 1445 1446 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection) 1447 { 1448 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; 1449 int sock; 1450 int ret; 1451 struct addrinfo *ai; 1452 struct addrinfo *ai_cur; 1453 struct addrinfo hints; 1454 1455 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); 1456 1457 if (tcpc->sock != -1) 1458 return RPC_S_OK; 1459 1460 hints.ai_flags = 0; 1461 hints.ai_family = PF_UNSPEC; 1462 hints.ai_socktype = SOCK_STREAM; 1463 hints.ai_protocol = IPPROTO_TCP; 1464 hints.ai_addrlen = 0; 1465 hints.ai_addr = NULL; 1466 hints.ai_canonname = NULL; 1467 hints.ai_next = NULL; 1468 1469 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai); 1470 if (ret) 1471 { 1472 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr, 1473 Connection->Endpoint, gai_strerror(ret)); 1474 return RPC_S_SERVER_UNAVAILABLE; 1475 } 1476 1477 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) 1478 { 1479 int val; 1480 u_long nonblocking; 1481 1482 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6) 1483 { 1484 TRACE("skipping non-IP/IPv6 address family\n"); 1485 continue; 1486 } 1487 1488 if (TRACE_ON(rpc)) 1489 { 1490 char host[256]; 1491 char service[256]; 1492 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, 1493 host, sizeof(host), service, sizeof(service), 1494 NI_NUMERICHOST | NI_NUMERICSERV); 1495 TRACE("trying %s:%s\n", host, service); 1496 } 1497 1498 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); 1499 if (sock == -1) 1500 { 1501 WARN("socket() failed: %u\n", WSAGetLastError()); 1502 continue; 1503 } 1504 1505 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen)) 1506 { 1507 WARN("connect() failed: %u\n", WSAGetLastError()); 1508 closesocket(sock); 1509 continue; 1510 } 1511 1512 /* RPC depends on having minimal latency so disable the Nagle algorithm */ 1513 val = 1; 1514 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); 1515 nonblocking = 1; 1516 ioctlsocket(sock, FIONBIO, &nonblocking); 1517 1518 tcpc->sock = sock; 1519 1520 freeaddrinfo(ai); 1521 TRACE("connected\n"); 1522 return RPC_S_OK; 1523 } 1524 1525 freeaddrinfo(ai); 1526 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint); 1527 return RPC_S_SERVER_UNAVAILABLE; 1528 } 1529 1530 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint) 1531 { 1532 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT; 1533 int sock; 1534 int ret; 1535 struct addrinfo *ai; 1536 struct addrinfo *ai_cur; 1537 struct addrinfo hints; 1538 1539 TRACE("(%p, %s)\n", protseq, endpoint); 1540 1541 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */; 1542 hints.ai_family = PF_UNSPEC; 1543 hints.ai_socktype = SOCK_STREAM; 1544 hints.ai_protocol = IPPROTO_TCP; 1545 hints.ai_addrlen = 0; 1546 hints.ai_addr = NULL; 1547 hints.ai_canonname = NULL; 1548 hints.ai_next = NULL; 1549 1550 ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai); 1551 if (ret) 1552 { 1553 ERR("getaddrinfo for port %s failed: %s\n", endpoint, 1554 gai_strerror(ret)); 1555 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME)) 1556 return RPC_S_INVALID_ENDPOINT_FORMAT; 1557 return RPC_S_CANT_CREATE_ENDPOINT; 1558 } 1559 1560 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) 1561 { 1562 RpcConnection_tcp *tcpc; 1563 RPC_STATUS create_status; 1564 struct sockaddr_storage sa; 1565 socklen_t sa_len; 1566 char service[NI_MAXSERV]; 1567 u_long nonblocking; 1568 1569 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6) 1570 { 1571 TRACE("skipping non-IP/IPv6 address family\n"); 1572 continue; 1573 } 1574 1575 if (TRACE_ON(rpc)) 1576 { 1577 char host[256]; 1578 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, 1579 host, sizeof(host), service, sizeof(service), 1580 NI_NUMERICHOST | NI_NUMERICSERV); 1581 TRACE("trying %s:%s\n", host, service); 1582 } 1583 1584 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); 1585 if (sock == -1) 1586 { 1587 WARN("socket() failed: %u\n", WSAGetLastError()); 1588 status = RPC_S_CANT_CREATE_ENDPOINT; 1589 continue; 1590 } 1591 1592 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen); 1593 if (ret < 0) 1594 { 1595 WARN("bind failed: %u\n", WSAGetLastError()); 1596 closesocket(sock); 1597 if (WSAGetLastError() == WSAEADDRINUSE) 1598 status = RPC_S_DUPLICATE_ENDPOINT; 1599 else 1600 status = RPC_S_CANT_CREATE_ENDPOINT; 1601 continue; 1602 } 1603 1604 sa_len = sizeof(sa); 1605 if (getsockname(sock, (struct sockaddr *)&sa, &sa_len)) 1606 { 1607 WARN("getsockname() failed: %u\n", WSAGetLastError()); 1608 closesocket(sock); 1609 status = RPC_S_CANT_CREATE_ENDPOINT; 1610 continue; 1611 } 1612 1613 ret = getnameinfo((struct sockaddr *)&sa, sa_len, 1614 NULL, 0, service, sizeof(service), 1615 NI_NUMERICSERV); 1616 if (ret) 1617 { 1618 WARN("getnameinfo failed: %s\n", gai_strerror(ret)); 1619 closesocket(sock); 1620 status = RPC_S_CANT_CREATE_ENDPOINT; 1621 continue; 1622 } 1623 1624 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE, 1625 protseq->Protseq, NULL, 1626 service, NULL, NULL, NULL, NULL); 1627 if (create_status != RPC_S_OK) 1628 { 1629 closesocket(sock); 1630 status = create_status; 1631 continue; 1632 } 1633 1634 tcpc->sock = sock; 1635 ret = listen(sock, protseq->MaxCalls); 1636 if (ret < 0) 1637 { 1638 WARN("listen failed: %u\n", WSAGetLastError()); 1639 RPCRT4_ReleaseConnection(&tcpc->common); 1640 status = RPC_S_OUT_OF_RESOURCES; 1641 continue; 1642 } 1643 /* need a non-blocking socket, otherwise accept() has a potential 1644 * race-condition (poll() says it is readable, connection drops, 1645 * and accept() blocks until the next connection comes...) 1646 */ 1647 nonblocking = 1; 1648 ret = ioctlsocket(sock, FIONBIO, &nonblocking); 1649 if (ret < 0) 1650 { 1651 WARN("couldn't make socket non-blocking, error %d\n", ret); 1652 RPCRT4_ReleaseConnection(&tcpc->common); 1653 status = RPC_S_OUT_OF_RESOURCES; 1654 continue; 1655 } 1656 1657 EnterCriticalSection(&protseq->cs); 1658 list_add_tail(&protseq->listeners, &tcpc->common.protseq_entry); 1659 tcpc->common.protseq = protseq; 1660 LeaveCriticalSection(&protseq->cs); 1661 1662 freeaddrinfo(ai); 1663 1664 /* since IPv4 and IPv6 share the same port space, we only need one 1665 * successful bind to listen for both */ 1666 TRACE("listening on %s\n", endpoint); 1667 return RPC_S_OK; 1668 } 1669 1670 freeaddrinfo(ai); 1671 ERR("couldn't listen on port %s\n", endpoint); 1672 return status; 1673 } 1674 1675 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn) 1676 { 1677 int ret; 1678 struct sockaddr_in address; 1679 socklen_t addrsize; 1680 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn; 1681 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn; 1682 u_long nonblocking; 1683 1684 addrsize = sizeof(address); 1685 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize); 1686 if (ret < 0) 1687 { 1688 ERR("Failed to accept a TCP connection: error %d\n", ret); 1689 return RPC_S_OUT_OF_RESOURCES; 1690 } 1691 1692 nonblocking = 1; 1693 ioctlsocket(ret, FIONBIO, &nonblocking); 1694 client->sock = ret; 1695 1696 client->common.NetworkAddr = HeapAlloc(GetProcessHeap(), 0, INET6_ADDRSTRLEN); 1697 ret = getnameinfo((struct sockaddr*)&address, addrsize, client->common.NetworkAddr, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); 1698 if (ret != 0) 1699 { 1700 ERR("Failed to retrieve the IP address, error %d\n", ret); 1701 return RPC_S_OUT_OF_RESOURCES; 1702 } 1703 1704 TRACE("Accepted a new TCP connection from %s\n", client->common.NetworkAddr); 1705 return RPC_S_OK; 1706 } 1707 1708 static int rpcrt4_conn_tcp_read(RpcConnection *Connection, 1709 void *buffer, unsigned int count) 1710 { 1711 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; 1712 int bytes_read = 0; 1713 while (bytes_read != count) 1714 { 1715 int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0); 1716 if (!r) 1717 return -1; 1718 else if (r > 0) 1719 bytes_read += r; 1720 else if (WSAGetLastError() == WSAEINTR) 1721 continue; 1722 else if (WSAGetLastError() != WSAEWOULDBLOCK) 1723 { 1724 WARN("recv() failed: %u\n", WSAGetLastError()); 1725 return -1; 1726 } 1727 else 1728 { 1729 if (!rpcrt4_sock_wait_for_recv(tcpc)) 1730 return -1; 1731 } 1732 } 1733 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read); 1734 return bytes_read; 1735 } 1736 1737 static int rpcrt4_conn_tcp_write(RpcConnection *Connection, 1738 const void *buffer, unsigned int count) 1739 { 1740 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; 1741 int bytes_written = 0; 1742 while (bytes_written != count) 1743 { 1744 int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0); 1745 if (r >= 0) 1746 bytes_written += r; 1747 else if (WSAGetLastError() == WSAEINTR) 1748 continue; 1749 else if (WSAGetLastError() != WSAEWOULDBLOCK) 1750 return -1; 1751 else 1752 { 1753 if (!rpcrt4_sock_wait_for_send(tcpc)) 1754 return -1; 1755 } 1756 } 1757 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written); 1758 return bytes_written; 1759 } 1760 1761 static int rpcrt4_conn_tcp_close(RpcConnection *conn) 1762 { 1763 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn; 1764 1765 TRACE("%d\n", connection->sock); 1766 1767 if (connection->sock != -1) 1768 closesocket(connection->sock); 1769 connection->sock = -1; 1770 CloseHandle(connection->sock_event); 1771 CloseHandle(connection->cancel_event); 1772 return 0; 1773 } 1774 1775 static void rpcrt4_conn_tcp_close_read(RpcConnection *conn) 1776 { 1777 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn; 1778 shutdown(connection->sock, SD_RECEIVE); 1779 } 1780 1781 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *conn) 1782 { 1783 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn; 1784 1785 TRACE("%p\n", connection); 1786 1787 SetEvent(connection->cancel_event); 1788 } 1789 1790 static RPC_STATUS rpcrt4_conn_tcp_is_server_listening(const char *endpoint) 1791 { 1792 FIXME("\n"); 1793 return RPC_S_ACCESS_DENIED; 1794 } 1795 1796 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection) 1797 { 1798 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; 1799 1800 TRACE("%p\n", Connection); 1801 1802 if (!rpcrt4_sock_wait_for_recv(tcpc)) 1803 return -1; 1804 return 0; 1805 } 1806 1807 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, 1808 const char *networkaddr, 1809 const char *endpoint) 1810 { 1811 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr, 1812 EPM_PROTOCOL_TCP, endpoint); 1813 } 1814 1815 typedef struct _RpcServerProtseq_sock 1816 { 1817 RpcServerProtseq common; 1818 HANDLE mgr_event; 1819 } RpcServerProtseq_sock; 1820 1821 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void) 1822 { 1823 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps)); 1824 if (ps) 1825 { 1826 static BOOL wsa_inited; 1827 if (!wsa_inited) 1828 { 1829 WSADATA wsadata; 1830 WSAStartup(MAKEWORD(2, 2), &wsadata); 1831 /* Note: WSAStartup can be called more than once so we don't bother with 1832 * making accesses to wsa_inited thread-safe */ 1833 wsa_inited = TRUE; 1834 } 1835 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1836 } 1837 return &ps->common; 1838 } 1839 1840 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq) 1841 { 1842 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); 1843 SetEvent(sockps->mgr_event); 1844 } 1845 1846 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) 1847 { 1848 HANDLE *objs = prev_array; 1849 RpcConnection_tcp *conn; 1850 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); 1851 1852 EnterCriticalSection(&protseq->cs); 1853 1854 /* open and count connections */ 1855 *count = 1; 1856 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry) 1857 { 1858 if (conn->sock != -1) 1859 (*count)++; 1860 } 1861 1862 /* make array of connections */ 1863 if (objs) 1864 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE)); 1865 else 1866 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE)); 1867 if (!objs) 1868 { 1869 ERR("couldn't allocate objs\n"); 1870 LeaveCriticalSection(&protseq->cs); 1871 return NULL; 1872 } 1873 1874 objs[0] = sockps->mgr_event; 1875 *count = 1; 1876 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry) 1877 { 1878 if (conn->sock != -1) 1879 { 1880 int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT); 1881 if (res == SOCKET_ERROR) 1882 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); 1883 else 1884 { 1885 objs[*count] = conn->sock_event; 1886 (*count)++; 1887 } 1888 } 1889 } 1890 LeaveCriticalSection(&protseq->cs); 1891 return objs; 1892 } 1893 1894 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array) 1895 { 1896 HeapFree(GetProcessHeap(), 0, array); 1897 } 1898 1899 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array) 1900 { 1901 HANDLE b_handle; 1902 HANDLE *objs = wait_array; 1903 DWORD res; 1904 RpcConnection *cconn = NULL; 1905 RpcConnection_tcp *conn; 1906 1907 if (!objs) 1908 return -1; 1909 1910 do 1911 { 1912 /* an alertable wait isn't strictly necessary, but due to our 1913 * overlapped I/O implementation in Wine we need to free some memory 1914 * by the file user APC being called, even if no completion routine was 1915 * specified at the time of starting the async operation */ 1916 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE); 1917 } while (res == WAIT_IO_COMPLETION); 1918 1919 if (res == WAIT_OBJECT_0) 1920 return 0; 1921 if (res == WAIT_FAILED) 1922 { 1923 ERR("wait failed with error %d\n", GetLastError()); 1924 return -1; 1925 } 1926 1927 b_handle = objs[res - WAIT_OBJECT_0]; 1928 1929 /* find which connection got a RPC */ 1930 EnterCriticalSection(&protseq->cs); 1931 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry) 1932 { 1933 if (b_handle == conn->sock_event) 1934 { 1935 cconn = rpcrt4_spawn_connection(&conn->common); 1936 break; 1937 } 1938 } 1939 LeaveCriticalSection(&protseq->cs); 1940 if (!cconn) 1941 { 1942 ERR("failed to locate connection for handle %p\n", b_handle); 1943 return -1; 1944 } 1945 1946 RPCRT4_new_client(cconn); 1947 return 1; 1948 } 1949 1950 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, 1951 size_t tower_size, 1952 char **networkaddr, 1953 char **endpoint) 1954 { 1955 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size, 1956 networkaddr, EPM_PROTOCOL_TCP, 1957 endpoint); 1958 } 1959 1960 /**** ncacn_http support ****/ 1961 1962 /* 60 seconds is the period native uses */ 1963 #define HTTP_IDLE_TIME 60000 1964 1965 /* reference counted to avoid a race between a cancelled call's connection 1966 * being destroyed and the asynchronous InternetReadFileEx call being 1967 * completed */ 1968 typedef struct _RpcHttpAsyncData 1969 { 1970 LONG refs; 1971 HANDLE completion_event; 1972 WORD async_result; 1973 INTERNET_BUFFERSW inet_buffers; 1974 CRITICAL_SECTION cs; 1975 } RpcHttpAsyncData; 1976 1977 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data) 1978 { 1979 return InterlockedIncrement(&data->refs); 1980 } 1981 1982 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data) 1983 { 1984 ULONG refs = InterlockedDecrement(&data->refs); 1985 if (!refs) 1986 { 1987 TRACE("destroying async data %p\n", data); 1988 CloseHandle(data->completion_event); 1989 HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer); 1990 data->cs.DebugInfo->Spare[0] = 0; 1991 DeleteCriticalSection(&data->cs); 1992 HeapFree(GetProcessHeap(), 0, data); 1993 } 1994 return refs; 1995 } 1996 1997 static void prepare_async_request(RpcHttpAsyncData *async_data) 1998 { 1999 ResetEvent(async_data->completion_event); 2000 RpcHttpAsyncData_AddRef(async_data); 2001 } 2002 2003 static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret, HANDLE cancel_event) 2004 { 2005 HANDLE handles[2] = { async_data->completion_event, cancel_event }; 2006 DWORD res; 2007 2008 if(call_ret) { 2009 RpcHttpAsyncData_Release(async_data); 2010 return RPC_S_OK; 2011 } 2012 2013 if(GetLastError() != ERROR_IO_PENDING) { 2014 RpcHttpAsyncData_Release(async_data); 2015 ERR("Request failed with error %d\n", GetLastError()); 2016 return RPC_S_SERVER_UNAVAILABLE; 2017 } 2018 2019 res = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT); 2020 if(res != WAIT_OBJECT_0) { 2021 TRACE("Cancelled\n"); 2022 return RPC_S_CALL_CANCELLED; 2023 } 2024 2025 if(async_data->async_result) { 2026 ERR("Async request failed with error %d\n", async_data->async_result); 2027 return RPC_S_SERVER_UNAVAILABLE; 2028 } 2029 2030 return RPC_S_OK; 2031 } 2032 2033 struct authinfo 2034 { 2035 DWORD scheme; 2036 CredHandle cred; 2037 CtxtHandle ctx; 2038 TimeStamp exp; 2039 ULONG attr; 2040 ULONG max_token; 2041 char *data; 2042 unsigned int data_len; 2043 BOOL finished; /* finished authenticating */ 2044 }; 2045 2046 typedef struct _RpcConnection_http 2047 { 2048 RpcConnection common; 2049 HINTERNET app_info; 2050 HINTERNET session; 2051 HINTERNET in_request; 2052 HINTERNET out_request; 2053 WCHAR *servername; 2054 HANDLE timer_cancelled; 2055 HANDLE cancel_event; 2056 DWORD last_sent_time; 2057 ULONG bytes_received; 2058 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */ 2059 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */ 2060 UUID connection_uuid; 2061 UUID in_pipe_uuid; 2062 UUID out_pipe_uuid; 2063 RpcHttpAsyncData *async_data; 2064 } RpcConnection_http; 2065 2066 static RpcConnection *rpcrt4_ncacn_http_alloc(void) 2067 { 2068 RpcConnection_http *httpc; 2069 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc)); 2070 if (!httpc) return NULL; 2071 httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData)); 2072 if (!httpc->async_data) 2073 { 2074 HeapFree(GetProcessHeap(), 0, httpc); 2075 return NULL; 2076 } 2077 TRACE("async data = %p\n", httpc->async_data); 2078 httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL); 2079 httpc->async_data->refs = 1; 2080 httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSW); 2081 InitializeCriticalSection(&httpc->async_data->cs); 2082 httpc->async_data->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcHttpAsyncData.cs"); 2083 return &httpc->common; 2084 } 2085 2086 typedef struct _HttpTimerThreadData 2087 { 2088 PVOID timer_param; 2089 DWORD *last_sent_time; 2090 HANDLE timer_cancelled; 2091 } HttpTimerThreadData; 2092 2093 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy) 2094 { 2095 HINTERNET in_request = param; 2096 RpcPktHdr *idle_pkt; 2097 2098 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001, 2099 0, 0); 2100 if (idle_pkt) 2101 { 2102 DWORD bytes_written; 2103 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written); 2104 RPCRT4_FreeHeader(idle_pkt); 2105 } 2106 } 2107 2108 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time) 2109 { 2110 DWORD cur_time = GetTickCount(); 2111 DWORD cached_last_sent_time = *last_sent_time; 2112 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time); 2113 } 2114 2115 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param) 2116 { 2117 HttpTimerThreadData *data_in = param; 2118 HttpTimerThreadData data; 2119 DWORD timeout; 2120 2121 data = *data_in; 2122 HeapFree(GetProcessHeap(), 0, data_in); 2123 2124 for (timeout = HTTP_IDLE_TIME; 2125 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT; 2126 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time)) 2127 { 2128 /* are we too soon after last send? */ 2129 if (GetTickCount() - *data.last_sent_time < HTTP_IDLE_TIME) 2130 continue; 2131 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE); 2132 } 2133 2134 CloseHandle(data.timer_cancelled); 2135 return 0; 2136 } 2137 2138 static VOID WINAPI rpcrt4_http_internet_callback( 2139 HINTERNET hInternet, 2140 DWORD_PTR dwContext, 2141 DWORD dwInternetStatus, 2142 LPVOID lpvStatusInformation, 2143 DWORD dwStatusInformationLength) 2144 { 2145 RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext; 2146 2147 switch (dwInternetStatus) 2148 { 2149 case INTERNET_STATUS_REQUEST_COMPLETE: 2150 TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n"); 2151 if (async_data) 2152 { 2153 INTERNET_ASYNC_RESULT *async_result = lpvStatusInformation; 2154 2155 async_data->async_result = async_result->dwResult ? ERROR_SUCCESS : async_result->dwError; 2156 SetEvent(async_data->completion_event); 2157 RpcHttpAsyncData_Release(async_data); 2158 } 2159 break; 2160 } 2161 } 2162 2163 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor) 2164 { 2165 BOOL ret; 2166 DWORD status_code; 2167 DWORD size; 2168 DWORD index; 2169 WCHAR buf[32]; 2170 WCHAR *status_text = buf; 2171 TRACE("\n"); 2172 2173 index = 0; 2174 size = sizeof(status_code); 2175 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index); 2176 if (!ret) 2177 return GetLastError(); 2178 if (status_code == HTTP_STATUS_OK) 2179 return RPC_S_OK; 2180 index = 0; 2181 size = sizeof(buf); 2182 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index); 2183 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 2184 { 2185 status_text = HeapAlloc(GetProcessHeap(), 0, size); 2186 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index); 2187 } 2188 2189 ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>"); 2190 if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text); 2191 2192 if (status_code == HTTP_STATUS_DENIED) 2193 return ERROR_ACCESS_DENIED; 2194 return RPC_S_SERVER_UNAVAILABLE; 2195 } 2196 2197 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc) 2198 { 2199 static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0}; 2200 LPWSTR proxy = NULL; 2201 LPWSTR user = NULL; 2202 LPWSTR password = NULL; 2203 LPWSTR servername = NULL; 2204 const WCHAR *option; 2205 INTERNET_PORT port; 2206 2207 if (httpc->common.QOS && 2208 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)) 2209 { 2210 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials; 2211 if (http_cred->TransportCredentials) 2212 { 2213 WCHAR *p; 2214 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials; 2215 ULONG len = cred->DomainLength + 1 + cred->UserLength; 2216 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 2217 if (!user) 2218 return RPC_S_OUT_OF_RESOURCES; 2219 p = user; 2220 if (cred->DomainLength) 2221 { 2222 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR)); 2223 p += cred->DomainLength; 2224 *p = '\\'; 2225 p++; 2226 } 2227 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR)); 2228 p[cred->UserLength] = 0; 2229 2230 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength); 2231 } 2232 } 2233 2234 for (option = httpc->common.NetworkOptions; option; 2235 option = (wcschr(option, ',') ? wcschr(option, ',')+1 : NULL)) 2236 { 2237 static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0}; 2238 static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0}; 2239 2240 if (!_wcsnicmp(option, wszRpcProxy, ARRAY_SIZE(wszRpcProxy)-1)) 2241 { 2242 const WCHAR *value_start = option + ARRAY_SIZE(wszRpcProxy)-1; 2243 const WCHAR *value_end; 2244 const WCHAR *p; 2245 2246 value_end = wcschr(option, ','); 2247 if (!value_end) 2248 value_end = value_start + lstrlenW(value_start); 2249 for (p = value_start; p < value_end; p++) 2250 if (*p == ':') 2251 { 2252 port = wcstol(p+1, NULL, 10); 2253 value_end = p; 2254 break; 2255 } 2256 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start)); 2257 servername = RPCRT4_strndupW(value_start, value_end-value_start); 2258 } 2259 else if (!_wcsnicmp(option, wszHttpProxy, ARRAY_SIZE(wszHttpProxy)-1)) 2260 { 2261 const WCHAR *value_start = option + ARRAY_SIZE(wszHttpProxy)-1; 2262 const WCHAR *value_end; 2263 2264 value_end = wcschr(option, ','); 2265 if (!value_end) 2266 value_end = value_start + lstrlenW(value_start); 2267 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start)); 2268 proxy = RPCRT4_strndupW(value_start, value_end-value_start); 2269 } 2270 else 2271 FIXME("unhandled option %s\n", debugstr_w(option)); 2272 } 2273 2274 httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG, 2275 NULL, NULL, INTERNET_FLAG_ASYNC); 2276 if (!httpc->app_info) 2277 { 2278 HeapFree(GetProcessHeap(), 0, password); 2279 HeapFree(GetProcessHeap(), 0, user); 2280 HeapFree(GetProcessHeap(), 0, proxy); 2281 HeapFree(GetProcessHeap(), 0, servername); 2282 ERR("InternetOpenW failed with error %d\n", GetLastError()); 2283 return RPC_S_SERVER_UNAVAILABLE; 2284 } 2285 InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback); 2286 2287 /* if no RpcProxy option specified, set the HTTP server address to the 2288 * RPC server address */ 2289 if (!servername) 2290 { 2291 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR)); 2292 if (!servername) 2293 { 2294 HeapFree(GetProcessHeap(), 0, password); 2295 HeapFree(GetProcessHeap(), 0, user); 2296 HeapFree(GetProcessHeap(), 0, proxy); 2297 return RPC_S_OUT_OF_RESOURCES; 2298 } 2299 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1); 2300 } 2301 2302 port = (httpc->common.QOS && 2303 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) && 2304 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)) ? 2305 INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT; 2306 2307 httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password, 2308 INTERNET_SERVICE_HTTP, 0, 0); 2309 2310 HeapFree(GetProcessHeap(), 0, password); 2311 HeapFree(GetProcessHeap(), 0, user); 2312 HeapFree(GetProcessHeap(), 0, proxy); 2313 2314 if (!httpc->session) 2315 { 2316 ERR("InternetConnectW failed with error %d\n", GetLastError()); 2317 HeapFree(GetProcessHeap(), 0, servername); 2318 return RPC_S_SERVER_UNAVAILABLE; 2319 } 2320 httpc->servername = servername; 2321 return RPC_S_OK; 2322 } 2323 2324 static int rpcrt4_http_async_read(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event, 2325 void *buffer, unsigned int count) 2326 { 2327 char *buf = buffer; 2328 BOOL ret; 2329 unsigned int bytes_left = count; 2330 RPC_STATUS status = RPC_S_OK; 2331 2332 async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, count); 2333 2334 while (bytes_left) 2335 { 2336 async_data->inet_buffers.dwBufferLength = bytes_left; 2337 prepare_async_request(async_data); 2338 ret = InternetReadFileExW(req, &async_data->inet_buffers, IRF_ASYNC, 0); 2339 status = wait_async_request(async_data, ret, cancel_event); 2340 if (status != RPC_S_OK) 2341 { 2342 if (status == RPC_S_CALL_CANCELLED) 2343 TRACE("call cancelled\n"); 2344 break; 2345 } 2346 2347 if (!async_data->inet_buffers.dwBufferLength) 2348 break; 2349 memcpy(buf, async_data->inet_buffers.lpvBuffer, 2350 async_data->inet_buffers.dwBufferLength); 2351 2352 bytes_left -= async_data->inet_buffers.dwBufferLength; 2353 buf += async_data->inet_buffers.dwBufferLength; 2354 } 2355 2356 HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer); 2357 async_data->inet_buffers.lpvBuffer = NULL; 2358 2359 TRACE("%p %p %u -> %u\n", req, buffer, count, status); 2360 return status == RPC_S_OK ? count : -1; 2361 } 2362 2363 static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event) 2364 { 2365 BYTE buf[20]; 2366 BOOL ret; 2367 RPC_STATUS status; 2368 2369 TRACE("sending echo request to server\n"); 2370 2371 prepare_async_request(async_data); 2372 ret = HttpSendRequestW(req, NULL, 0, NULL, 0); 2373 status = wait_async_request(async_data, ret, cancel_event); 2374 if (status != RPC_S_OK) return status; 2375 2376 status = rpcrt4_http_check_response(req); 2377 if (status != RPC_S_OK) return status; 2378 2379 rpcrt4_http_async_read(req, async_data, cancel_event, buf, sizeof(buf)); 2380 /* FIXME: do something with retrieved data */ 2381 2382 return RPC_S_OK; 2383 } 2384 2385 static RPC_STATUS insert_content_length_header(HINTERNET request, DWORD len) 2386 { 2387 static const WCHAR fmtW[] = 2388 {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','u','\r','\n',0}; 2389 WCHAR header[ARRAY_SIZE(fmtW) + 10]; 2390 2391 swprintf(header, fmtW, len); 2392 if ((HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))) return RPC_S_OK; 2393 return RPC_S_SERVER_UNAVAILABLE; 2394 } 2395 2396 /* prepare the in pipe for use by RPC packets */ 2397 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data, HANDLE cancel_event, 2398 const UUID *connection_uuid, const UUID *in_pipe_uuid, 2399 const UUID *association_uuid, BOOL authorized) 2400 { 2401 BOOL ret; 2402 RPC_STATUS status; 2403 RpcPktHdr *hdr; 2404 INTERNET_BUFFERSW buffers_in; 2405 DWORD bytes_written; 2406 2407 if (!authorized) 2408 { 2409 /* ask wininet to authorize, if necessary */ 2410 status = send_echo_request(in_request, async_data, cancel_event); 2411 if (status != RPC_S_OK) return status; 2412 } 2413 memset(&buffers_in, 0, sizeof(buffers_in)); 2414 buffers_in.dwStructSize = sizeof(buffers_in); 2415 /* FIXME: get this from the registry */ 2416 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */ 2417 status = insert_content_length_header(in_request, buffers_in.dwBufferTotal); 2418 if (status != RPC_S_OK) return status; 2419 2420 prepare_async_request(async_data); 2421 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0); 2422 status = wait_async_request(async_data, ret, cancel_event); 2423 if (status != RPC_S_OK) return status; 2424 2425 TRACE("sending HTTP connect header to server\n"); 2426 hdr = RPCRT4_BuildHttpConnectHeader(FALSE, connection_uuid, in_pipe_uuid, association_uuid); 2427 if (!hdr) return RPC_S_OUT_OF_RESOURCES; 2428 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written); 2429 RPCRT4_FreeHeader(hdr); 2430 if (!ret) 2431 { 2432 ERR("InternetWriteFile failed with error %d\n", GetLastError()); 2433 return RPC_S_SERVER_UNAVAILABLE; 2434 } 2435 2436 return RPC_S_OK; 2437 } 2438 2439 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcHttpAsyncData *async_data, 2440 HANDLE cancel_event, RpcPktHdr *hdr, BYTE **data) 2441 { 2442 unsigned short data_len; 2443 unsigned int size; 2444 2445 if (rpcrt4_http_async_read(request, async_data, cancel_event, hdr, sizeof(hdr->common)) < 0) 2446 return RPC_S_SERVER_UNAVAILABLE; 2447 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http)) 2448 { 2449 ERR("wrong packet type received %d or wrong frag_len %d\n", 2450 hdr->common.ptype, hdr->common.frag_len); 2451 return RPC_S_PROTOCOL_ERROR; 2452 } 2453 2454 size = sizeof(hdr->http) - sizeof(hdr->common); 2455 if (rpcrt4_http_async_read(request, async_data, cancel_event, &hdr->common + 1, size) < 0) 2456 return RPC_S_SERVER_UNAVAILABLE; 2457 2458 data_len = hdr->common.frag_len - sizeof(hdr->http); 2459 if (data_len) 2460 { 2461 *data = HeapAlloc(GetProcessHeap(), 0, data_len); 2462 if (!*data) 2463 return RPC_S_OUT_OF_RESOURCES; 2464 if (rpcrt4_http_async_read(request, async_data, cancel_event, *data, data_len) < 0) 2465 { 2466 HeapFree(GetProcessHeap(), 0, *data); 2467 return RPC_S_SERVER_UNAVAILABLE; 2468 } 2469 } 2470 else 2471 *data = NULL; 2472 2473 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len)) 2474 { 2475 ERR("invalid http packet\n"); 2476 HeapFree(GetProcessHeap(), 0, *data); 2477 return RPC_S_PROTOCOL_ERROR; 2478 } 2479 2480 return RPC_S_OK; 2481 } 2482 2483 /* prepare the out pipe for use by RPC packets */ 2484 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, RpcHttpAsyncData *async_data, 2485 HANDLE cancel_event, const UUID *connection_uuid, 2486 const UUID *out_pipe_uuid, ULONG *flow_control_increment, 2487 BOOL authorized) 2488 { 2489 BOOL ret; 2490 RPC_STATUS status; 2491 RpcPktHdr *hdr; 2492 BYTE *data_from_server; 2493 RpcPktHdr pkt_from_server; 2494 ULONG field1, field3; 2495 BYTE buf[20]; 2496 2497 if (!authorized) 2498 { 2499 /* ask wininet to authorize, if necessary */ 2500 status = send_echo_request(out_request, async_data, cancel_event); 2501 if (status != RPC_S_OK) return status; 2502 } 2503 else 2504 rpcrt4_http_async_read(out_request, async_data, cancel_event, buf, sizeof(buf)); 2505 2506 hdr = RPCRT4_BuildHttpConnectHeader(TRUE, connection_uuid, out_pipe_uuid, NULL); 2507 if (!hdr) return RPC_S_OUT_OF_RESOURCES; 2508 2509 status = insert_content_length_header(out_request, hdr->common.frag_len); 2510 if (status != RPC_S_OK) 2511 { 2512 RPCRT4_FreeHeader(hdr); 2513 return status; 2514 } 2515 2516 TRACE("sending HTTP connect header to server\n"); 2517 prepare_async_request(async_data); 2518 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len); 2519 status = wait_async_request(async_data, ret, cancel_event); 2520 RPCRT4_FreeHeader(hdr); 2521 if (status != RPC_S_OK) return status; 2522 2523 status = rpcrt4_http_check_response(out_request); 2524 if (status != RPC_S_OK) return status; 2525 2526 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event, 2527 &pkt_from_server, &data_from_server); 2528 if (status != RPC_S_OK) return status; 2529 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server, 2530 &field1); 2531 HeapFree(GetProcessHeap(), 0, data_from_server); 2532 if (status != RPC_S_OK) return status; 2533 TRACE("received (%d) from first prepare header\n", field1); 2534 2535 for (;;) 2536 { 2537 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event, 2538 &pkt_from_server, &data_from_server); 2539 if (status != RPC_S_OK) return status; 2540 if (pkt_from_server.http.flags != 0x0001) break; 2541 2542 TRACE("http idle packet, waiting for real packet\n"); 2543 HeapFree(GetProcessHeap(), 0, data_from_server); 2544 if (pkt_from_server.http.num_data_items != 0) 2545 { 2546 ERR("HTTP idle packet should have no data items instead of %d\n", 2547 pkt_from_server.http.num_data_items); 2548 return RPC_S_PROTOCOL_ERROR; 2549 } 2550 } 2551 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server, 2552 &field1, flow_control_increment, 2553 &field3); 2554 HeapFree(GetProcessHeap(), 0, data_from_server); 2555 if (status != RPC_S_OK) return status; 2556 TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3); 2557 2558 return RPC_S_OK; 2559 } 2560 2561 static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64) 2562 { 2563 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 2564 UINT i = 0, x; 2565 2566 while (len > 0) 2567 { 2568 /* first 6 bits, all from bin[0] */ 2569 base64[i++] = enc[(bin[0] & 0xfc) >> 2]; 2570 x = (bin[0] & 3) << 4; 2571 2572 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */ 2573 if (len == 1) 2574 { 2575 base64[i++] = enc[x]; 2576 base64[i++] = '='; 2577 base64[i++] = '='; 2578 break; 2579 } 2580 base64[i++] = enc[x | ((bin[1] & 0xf0) >> 4)]; 2581 x = (bin[1] & 0x0f) << 2; 2582 2583 /* next 6 bits 4 from bin[1] and 2 from bin[2] */ 2584 if (len == 2) 2585 { 2586 base64[i++] = enc[x]; 2587 base64[i++] = '='; 2588 break; 2589 } 2590 base64[i++] = enc[x | ((bin[2] & 0xc0) >> 6)]; 2591 2592 /* last 6 bits, all from bin [2] */ 2593 base64[i++] = enc[bin[2] & 0x3f]; 2594 bin += 3; 2595 len -= 3; 2596 } 2597 base64[i] = 0; 2598 return i; 2599 } 2600 2601 static inline char decode_char( WCHAR c ) 2602 { 2603 if (c >= 'A' && c <= 'Z') return c - 'A'; 2604 if (c >= 'a' && c <= 'z') return c - 'a' + 26; 2605 if (c >= '0' && c <= '9') return c - '0' + 52; 2606 if (c == '+') return 62; 2607 if (c == '/') return 63; 2608 return 64; 2609 } 2610 2611 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf ) 2612 { 2613 unsigned int i = 0; 2614 char c0, c1, c2, c3; 2615 const WCHAR *p = base64; 2616 2617 while (len > 4) 2618 { 2619 if ((c0 = decode_char( p[0] )) > 63) return 0; 2620 if ((c1 = decode_char( p[1] )) > 63) return 0; 2621 if ((c2 = decode_char( p[2] )) > 63) return 0; 2622 if ((c3 = decode_char( p[3] )) > 63) return 0; 2623 2624 if (buf) 2625 { 2626 buf[i + 0] = (c0 << 2) | (c1 >> 4); 2627 buf[i + 1] = (c1 << 4) | (c2 >> 2); 2628 buf[i + 2] = (c2 << 6) | c3; 2629 } 2630 len -= 4; 2631 i += 3; 2632 p += 4; 2633 } 2634 if (p[2] == '=') 2635 { 2636 if ((c0 = decode_char( p[0] )) > 63) return 0; 2637 if ((c1 = decode_char( p[1] )) > 63) return 0; 2638 2639 if (buf) buf[i] = (c0 << 2) | (c1 >> 4); 2640 i++; 2641 } 2642 else if (p[3] == '=') 2643 { 2644 if ((c0 = decode_char( p[0] )) > 63) return 0; 2645 if ((c1 = decode_char( p[1] )) > 63) return 0; 2646 if ((c2 = decode_char( p[2] )) > 63) return 0; 2647 2648 if (buf) 2649 { 2650 buf[i + 0] = (c0 << 2) | (c1 >> 4); 2651 buf[i + 1] = (c1 << 4) | (c2 >> 2); 2652 } 2653 i += 2; 2654 } 2655 else 2656 { 2657 if ((c0 = decode_char( p[0] )) > 63) return 0; 2658 if ((c1 = decode_char( p[1] )) > 63) return 0; 2659 if ((c2 = decode_char( p[2] )) > 63) return 0; 2660 if ((c3 = decode_char( p[3] )) > 63) return 0; 2661 2662 if (buf) 2663 { 2664 buf[i + 0] = (c0 << 2) | (c1 >> 4); 2665 buf[i + 1] = (c1 << 4) | (c2 >> 2); 2666 buf[i + 2] = (c2 << 6) | c3; 2667 } 2668 i += 3; 2669 } 2670 return i; 2671 } 2672 2673 static struct authinfo *alloc_authinfo(void) 2674 { 2675 struct authinfo *ret; 2676 2677 if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret) ))) return NULL; 2678 2679 SecInvalidateHandle(&ret->cred); 2680 SecInvalidateHandle(&ret->ctx); 2681 memset(&ret->exp, 0, sizeof(ret->exp)); 2682 ret->scheme = 0; 2683 ret->attr = 0; 2684 ret->max_token = 0; 2685 ret->data = NULL; 2686 ret->data_len = 0; 2687 ret->finished = FALSE; 2688 return ret; 2689 } 2690 2691 static void destroy_authinfo(struct authinfo *info) 2692 { 2693 if (!info) return; 2694 2695 if (SecIsValidHandle(&info->ctx)) 2696 DeleteSecurityContext(&info->ctx); 2697 if (SecIsValidHandle(&info->cred)) 2698 FreeCredentialsHandle(&info->cred); 2699 2700 HeapFree(GetProcessHeap(), 0, info->data); 2701 HeapFree(GetProcessHeap(), 0, info); 2702 } 2703 2704 static const WCHAR basicW[] = {'B','a','s','i','c',0}; 2705 static const WCHAR ntlmW[] = {'N','T','L','M',0}; 2706 static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t',0}; 2707 static const WCHAR digestW[] = {'D','i','g','e','s','t',0}; 2708 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0}; 2709 2710 static const struct 2711 { 2712 const WCHAR *str; 2713 unsigned int len; 2714 DWORD scheme; 2715 } 2716 auth_schemes[] = 2717 { 2718 { basicW, ARRAY_SIZE(basicW) - 1, RPC_C_HTTP_AUTHN_SCHEME_BASIC }, 2719 { ntlmW, ARRAY_SIZE(ntlmW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NTLM }, 2720 { passportW, ARRAY_SIZE(passportW) - 1, RPC_C_HTTP_AUTHN_SCHEME_PASSPORT }, 2721 { digestW, ARRAY_SIZE(digestW) - 1, RPC_C_HTTP_AUTHN_SCHEME_DIGEST }, 2722 { negotiateW, ARRAY_SIZE(negotiateW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE } 2723 }; 2724 2725 static DWORD auth_scheme_from_header( const WCHAR *header ) 2726 { 2727 unsigned int i; 2728 for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) 2729 { 2730 if (!_wcsnicmp( header, auth_schemes[i].str, auth_schemes[i].len ) && 2731 (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme; 2732 } 2733 return 0; 2734 } 2735 2736 static BOOL get_authvalue(HINTERNET request, DWORD scheme, WCHAR *buffer, DWORD buflen) 2737 { 2738 DWORD len, index = 0; 2739 for (;;) 2740 { 2741 len = buflen; 2742 if (!HttpQueryInfoW(request, HTTP_QUERY_WWW_AUTHENTICATE, buffer, &len, &index)) return FALSE; 2743 if (auth_scheme_from_header(buffer) == scheme) break; 2744 } 2745 return TRUE; 2746 } 2747 2748 static RPC_STATUS do_authorization(HINTERNET request, SEC_WCHAR *servername, 2749 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds, struct authinfo **auth_ptr) 2750 { 2751 struct authinfo *info = *auth_ptr; 2752 SEC_WINNT_AUTH_IDENTITY_W *id = creds->TransportCredentials; 2753 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE; 2754 2755 if ((!info && !(info = alloc_authinfo()))) return RPC_S_SERVER_UNAVAILABLE; 2756 2757 switch (creds->AuthnSchemes[0]) 2758 { 2759 case RPC_C_HTTP_AUTHN_SCHEME_BASIC: 2760 { 2761 int userlen = WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, NULL, 0, NULL, NULL); 2762 int passlen = WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, NULL, 0, NULL, NULL); 2763 2764 info->data_len = userlen + passlen + 1; 2765 if (!(info->data = HeapAlloc(GetProcessHeap(), 0, info->data_len))) 2766 { 2767 status = RPC_S_OUT_OF_MEMORY; 2768 break; 2769 } 2770 WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, info->data, userlen, NULL, NULL); 2771 info->data[userlen] = ':'; 2772 WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, info->data + userlen + 1, passlen, NULL, NULL); 2773 2774 info->scheme = RPC_C_HTTP_AUTHN_SCHEME_BASIC; 2775 info->finished = TRUE; 2776 status = RPC_S_OK; 2777 break; 2778 } 2779 case RPC_C_HTTP_AUTHN_SCHEME_NTLM: 2780 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE: 2781 { 2782 2783 static SEC_WCHAR ntlmW[] = {'N','T','L','M',0}, negotiateW[] = {'N','e','g','o','t','i','a','t','e',0}; 2784 SECURITY_STATUS ret; 2785 SecBufferDesc out_desc, in_desc; 2786 SecBuffer out, in; 2787 ULONG flags = ISC_REQ_CONNECTION|ISC_REQ_USE_DCE_STYLE|ISC_REQ_MUTUAL_AUTH|ISC_REQ_DELEGATE; 2788 SEC_WCHAR *scheme; 2789 int scheme_len; 2790 const WCHAR *p; 2791 WCHAR auth_value[2048]; 2792 DWORD size = sizeof(auth_value); 2793 BOOL first = FALSE; 2794 2795 if (creds->AuthnSchemes[0] == RPC_C_HTTP_AUTHN_SCHEME_NTLM) scheme = ntlmW; 2796 else scheme = negotiateW; 2797 scheme_len = lstrlenW( scheme ); 2798 2799 if (!*auth_ptr) 2800 { 2801 TimeStamp exp; 2802 SecPkgInfoW *pkg_info; 2803 2804 ret = AcquireCredentialsHandleW(NULL, scheme, SECPKG_CRED_OUTBOUND, NULL, id, NULL, NULL, &info->cred, &exp); 2805 if (ret != SEC_E_OK) break; 2806 2807 ret = QuerySecurityPackageInfoW(scheme, &pkg_info); 2808 if (ret != SEC_E_OK) break; 2809 2810 info->max_token = pkg_info->cbMaxToken; 2811 FreeContextBuffer(pkg_info); 2812 first = TRUE; 2813 } 2814 else 2815 { 2816 if (info->finished || !get_authvalue(request, creds->AuthnSchemes[0], auth_value, size)) break; 2817 if (auth_scheme_from_header(auth_value) != info->scheme) 2818 { 2819 ERR("authentication scheme changed\n"); 2820 break; 2821 } 2822 } 2823 in.BufferType = SECBUFFER_TOKEN; 2824 in.cbBuffer = 0; 2825 in.pvBuffer = NULL; 2826 2827 in_desc.ulVersion = 0; 2828 in_desc.cBuffers = 1; 2829 in_desc.pBuffers = ∈ 2830 2831 p = auth_value + scheme_len; 2832 if (!first && *p == ' ') 2833 { 2834 int len = lstrlenW(++p); 2835 in.cbBuffer = decode_base64(p, len, NULL); 2836 if (!(in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer))) break; 2837 decode_base64(p, len, in.pvBuffer); 2838 } 2839 out.BufferType = SECBUFFER_TOKEN; 2840 out.cbBuffer = info->max_token; 2841 if (!(out.pvBuffer = HeapAlloc(GetProcessHeap(), 0, out.cbBuffer))) 2842 { 2843 HeapFree(GetProcessHeap(), 0, in.pvBuffer); 2844 break; 2845 } 2846 out_desc.ulVersion = 0; 2847 out_desc.cBuffers = 1; 2848 out_desc.pBuffers = &out; 2849 2850 ret = InitializeSecurityContextW(first ? &info->cred : NULL, first ? NULL : &info->ctx, 2851 first ? servername : NULL, flags, 0, SECURITY_NETWORK_DREP, 2852 in.pvBuffer ? &in_desc : NULL, 0, &info->ctx, &out_desc, 2853 &info->attr, &info->exp); 2854 HeapFree(GetProcessHeap(), 0, in.pvBuffer); 2855 if (ret == SEC_E_OK) 2856 { 2857 HeapFree(GetProcessHeap(), 0, info->data); 2858 info->data = out.pvBuffer; 2859 info->data_len = out.cbBuffer; 2860 info->finished = TRUE; 2861 TRACE("sending last auth packet\n"); 2862 status = RPC_S_OK; 2863 } 2864 else if (ret == SEC_I_CONTINUE_NEEDED) 2865 { 2866 HeapFree(GetProcessHeap(), 0, info->data); 2867 info->data = out.pvBuffer; 2868 info->data_len = out.cbBuffer; 2869 TRACE("sending next auth packet\n"); 2870 status = RPC_S_OK; 2871 } 2872 else 2873 { 2874 ERR("InitializeSecurityContextW failed with error 0x%08x\n", ret); 2875 HeapFree(GetProcessHeap(), 0, out.pvBuffer); 2876 break; 2877 } 2878 info->scheme = creds->AuthnSchemes[0]; 2879 break; 2880 } 2881 default: 2882 FIXME("scheme %u not supported\n", creds->AuthnSchemes[0]); 2883 break; 2884 } 2885 2886 if (status != RPC_S_OK) 2887 { 2888 destroy_authinfo(info); 2889 *auth_ptr = NULL; 2890 return status; 2891 } 2892 *auth_ptr = info; 2893 return RPC_S_OK; 2894 } 2895 2896 static RPC_STATUS insert_authorization_header(HINTERNET request, ULONG scheme, char *data, int data_len) 2897 { 2898 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '}; 2899 static const WCHAR basicW[] = {'B','a','s','i','c',' '}; 2900 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',' '}; 2901 static const WCHAR ntlmW[] = {'N','T','L','M',' '}; 2902 int scheme_len, auth_len = ARRAY_SIZE(authW), len = ((data_len + 2) * 4) / 3; 2903 const WCHAR *scheme_str; 2904 WCHAR *header, *ptr; 2905 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE; 2906 2907 switch (scheme) 2908 { 2909 case RPC_C_HTTP_AUTHN_SCHEME_BASIC: 2910 scheme_str = basicW; 2911 scheme_len = ARRAY_SIZE(basicW); 2912 break; 2913 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE: 2914 scheme_str = negotiateW; 2915 scheme_len = ARRAY_SIZE(negotiateW); 2916 break; 2917 case RPC_C_HTTP_AUTHN_SCHEME_NTLM: 2918 scheme_str = ntlmW; 2919 scheme_len = ARRAY_SIZE(ntlmW); 2920 break; 2921 default: 2922 ERR("unknown scheme %u\n", scheme); 2923 return RPC_S_SERVER_UNAVAILABLE; 2924 } 2925 if ((header = HeapAlloc(GetProcessHeap(), 0, (auth_len + scheme_len + len + 2) * sizeof(WCHAR)))) 2926 { 2927 memcpy(header, authW, auth_len * sizeof(WCHAR)); 2928 ptr = header + auth_len; 2929 memcpy(ptr, scheme_str, scheme_len * sizeof(WCHAR)); 2930 ptr += scheme_len; 2931 len = encode_base64(data, data_len, ptr); 2932 ptr[len++] = '\r'; 2933 ptr[len++] = '\n'; 2934 ptr[len] = 0; 2935 if (HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE)) 2936 status = RPC_S_OK; 2937 HeapFree(GetProcessHeap(), 0, header); 2938 } 2939 return status; 2940 } 2941 2942 static void drain_content(HINTERNET request, RpcHttpAsyncData *async_data, HANDLE cancel_event) 2943 { 2944 DWORD count, len = 0, size = sizeof(len); 2945 char buf[2048]; 2946 2947 HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &len, &size, NULL); 2948 if (!len) return; 2949 for (;;) 2950 { 2951 count = min(sizeof(buf), len); 2952 if (rpcrt4_http_async_read(request, async_data, cancel_event, buf, count) <= 0) return; 2953 len -= count; 2954 } 2955 } 2956 2957 static RPC_STATUS authorize_request(RpcConnection_http *httpc, HINTERNET request) 2958 { 2959 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':','\r','\n',0}; 2960 struct authinfo *info = NULL; 2961 RPC_STATUS status; 2962 BOOL ret; 2963 2964 for (;;) 2965 { 2966 status = do_authorization(request, httpc->servername, httpc->common.QOS->qos->u.HttpCredentials, &info); 2967 if (status != RPC_S_OK) break; 2968 2969 status = insert_authorization_header(request, info->scheme, info->data, info->data_len); 2970 if (status != RPC_S_OK) break; 2971 2972 prepare_async_request(httpc->async_data); 2973 ret = HttpSendRequestW(request, NULL, 0, NULL, 0); 2974 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event); 2975 if (status != RPC_S_OK || info->finished) break; 2976 2977 status = rpcrt4_http_check_response(request); 2978 if (status != RPC_S_OK && status != ERROR_ACCESS_DENIED) break; 2979 drain_content(request, httpc->async_data, httpc->cancel_event); 2980 } 2981 2982 if (info->scheme != RPC_C_HTTP_AUTHN_SCHEME_BASIC) 2983 HttpAddRequestHeadersW(request, authW, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD); 2984 2985 destroy_authinfo(info); 2986 return status; 2987 } 2988 2989 static BOOL has_credentials(RpcConnection_http *httpc) 2990 { 2991 RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds; 2992 SEC_WINNT_AUTH_IDENTITY_W *id; 2993 2994 if (!httpc->common.QOS || httpc->common.QOS->qos->AdditionalSecurityInfoType != RPC_C_AUTHN_INFO_TYPE_HTTP) 2995 return FALSE; 2996 2997 creds = httpc->common.QOS->qos->u.HttpCredentials; 2998 if (creds->AuthenticationTarget != RPC_C_HTTP_AUTHN_TARGET_SERVER || !creds->NumberOfAuthnSchemes) 2999 return FALSE; 3000 3001 id = creds->TransportCredentials; 3002 if (!id || !id->User || !id->Password) return FALSE; 3003 3004 return TRUE; 3005 } 3006 3007 static BOOL is_secure(RpcConnection_http *httpc) 3008 { 3009 return httpc->common.QOS && 3010 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) && 3011 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL); 3012 } 3013 3014 static RPC_STATUS set_auth_cookie(RpcConnection_http *httpc, const WCHAR *value) 3015 { 3016 static WCHAR httpW[] = {'h','t','t','p',0}; 3017 static WCHAR httpsW[] = {'h','t','t','p','s',0}; 3018 URL_COMPONENTSW uc; 3019 DWORD len; 3020 WCHAR *url; 3021 BOOL ret; 3022 3023 if (!value) return RPC_S_OK; 3024 3025 uc.dwStructSize = sizeof(uc); 3026 uc.lpszScheme = is_secure(httpc) ? httpsW : httpW; 3027 uc.dwSchemeLength = 0; 3028 uc.lpszHostName = httpc->servername; 3029 uc.dwHostNameLength = 0; 3030 uc.nPort = 0; 3031 uc.lpszUserName = NULL; 3032 uc.dwUserNameLength = 0; 3033 uc.lpszPassword = NULL; 3034 uc.dwPasswordLength = 0; 3035 uc.lpszUrlPath = NULL; 3036 uc.dwUrlPathLength = 0; 3037 uc.lpszExtraInfo = NULL; 3038 uc.dwExtraInfoLength = 0; 3039 3040 if (!InternetCreateUrlW(&uc, 0, NULL, &len) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) 3041 return RPC_S_SERVER_UNAVAILABLE; 3042 3043 if (!(url = HeapAlloc(GetProcessHeap(), 0, len))) return RPC_S_OUT_OF_MEMORY; 3044 3045 len = len / sizeof(WCHAR) - 1; 3046 if (!InternetCreateUrlW(&uc, 0, url, &len)) 3047 { 3048 HeapFree(GetProcessHeap(), 0, url); 3049 return RPC_S_SERVER_UNAVAILABLE; 3050 } 3051 3052 ret = InternetSetCookieW(url, NULL, value); 3053 HeapFree(GetProcessHeap(), 0, url); 3054 if (!ret) return RPC_S_SERVER_UNAVAILABLE; 3055 3056 return RPC_S_OK; 3057 } 3058 3059 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection) 3060 { 3061 RpcConnection_http *httpc = (RpcConnection_http *)Connection; 3062 static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0}; 3063 static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0}; 3064 static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0}; 3065 static const WCHAR wszColon[] = {':',0}; 3066 static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0}; 3067 LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL }; 3068 DWORD flags; 3069 WCHAR *url; 3070 RPC_STATUS status; 3071 BOOL secure, credentials; 3072 HttpTimerThreadData *timer_data; 3073 HANDLE thread; 3074 3075 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); 3076 3077 if (Connection->server) 3078 { 3079 ERR("ncacn_http servers not supported yet\n"); 3080 return RPC_S_SERVER_UNAVAILABLE; 3081 } 3082 3083 if (httpc->in_request) 3084 return RPC_S_OK; 3085 3086 httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL); 3087 3088 UuidCreate(&httpc->connection_uuid); 3089 UuidCreate(&httpc->in_pipe_uuid); 3090 UuidCreate(&httpc->out_pipe_uuid); 3091 3092 status = rpcrt4_http_internet_connect(httpc); 3093 if (status != RPC_S_OK) 3094 return status; 3095 3096 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR)); 3097 if (!url) 3098 return RPC_S_OUT_OF_MEMORY; 3099 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix)); 3100 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+ARRAY_SIZE(wszRpcProxyPrefix)-1, 3101 strlen(Connection->NetworkAddr)+1); 3102 lstrcatW(url, wszColon); 3103 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+lstrlenW(url), strlen(Connection->Endpoint)+1); 3104 3105 secure = is_secure(httpc); 3106 credentials = has_credentials(httpc); 3107 3108 flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE | 3109 INTERNET_FLAG_NO_AUTO_REDIRECT; 3110 if (secure) flags |= INTERNET_FLAG_SECURE; 3111 if (credentials) flags |= INTERNET_FLAG_NO_AUTH; 3112 3113 status = set_auth_cookie(httpc, Connection->CookieAuth); 3114 if (status != RPC_S_OK) 3115 { 3116 HeapFree(GetProcessHeap(), 0, url); 3117 return status; 3118 } 3119 httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL, wszAcceptTypes, 3120 flags, (DWORD_PTR)httpc->async_data); 3121 if (!httpc->in_request) 3122 { 3123 ERR("HttpOpenRequestW failed with error %d\n", GetLastError()); 3124 HeapFree(GetProcessHeap(), 0, url); 3125 return RPC_S_SERVER_UNAVAILABLE; 3126 } 3127 3128 if (credentials) 3129 { 3130 status = authorize_request(httpc, httpc->in_request); 3131 if (status != RPC_S_OK) 3132 { 3133 HeapFree(GetProcessHeap(), 0, url); 3134 return status; 3135 } 3136 status = rpcrt4_http_check_response(httpc->in_request); 3137 if (status != RPC_S_OK) 3138 { 3139 HeapFree(GetProcessHeap(), 0, url); 3140 return status; 3141 } 3142 drain_content(httpc->in_request, httpc->async_data, httpc->cancel_event); 3143 } 3144 3145 httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL, wszAcceptTypes, 3146 flags, (DWORD_PTR)httpc->async_data); 3147 HeapFree(GetProcessHeap(), 0, url); 3148 if (!httpc->out_request) 3149 { 3150 ERR("HttpOpenRequestW failed with error %d\n", GetLastError()); 3151 return RPC_S_SERVER_UNAVAILABLE; 3152 } 3153 3154 if (credentials) 3155 { 3156 status = authorize_request(httpc, httpc->out_request); 3157 if (status != RPC_S_OK) 3158 return status; 3159 } 3160 3161 status = rpcrt4_http_prepare_in_pipe(httpc->in_request, httpc->async_data, httpc->cancel_event, 3162 &httpc->connection_uuid, &httpc->in_pipe_uuid, 3163 &Connection->assoc->http_uuid, credentials); 3164 if (status != RPC_S_OK) 3165 return status; 3166 3167 status = rpcrt4_http_prepare_out_pipe(httpc->out_request, httpc->async_data, httpc->cancel_event, 3168 &httpc->connection_uuid, &httpc->out_pipe_uuid, 3169 &httpc->flow_control_increment, credentials); 3170 if (status != RPC_S_OK) 3171 return status; 3172 3173 httpc->flow_control_mark = httpc->flow_control_increment / 2; 3174 httpc->last_sent_time = GetTickCount(); 3175 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL); 3176 3177 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data)); 3178 if (!timer_data) 3179 return ERROR_OUTOFMEMORY; 3180 timer_data->timer_param = httpc->in_request; 3181 timer_data->last_sent_time = &httpc->last_sent_time; 3182 timer_data->timer_cancelled = httpc->timer_cancelled; 3183 /* FIXME: should use CreateTimerQueueTimer when implemented */ 3184 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL); 3185 if (!thread) 3186 { 3187 HeapFree(GetProcessHeap(), 0, timer_data); 3188 return GetLastError(); 3189 } 3190 CloseHandle(thread); 3191 3192 return RPC_S_OK; 3193 } 3194 3195 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn) 3196 { 3197 assert(0); 3198 return RPC_S_SERVER_UNAVAILABLE; 3199 } 3200 3201 static int rpcrt4_ncacn_http_read(RpcConnection *Connection, 3202 void *buffer, unsigned int count) 3203 { 3204 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3205 return rpcrt4_http_async_read(httpc->out_request, httpc->async_data, httpc->cancel_event, buffer, count); 3206 } 3207 3208 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload) 3209 { 3210 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3211 RPC_STATUS status; 3212 DWORD hdr_length; 3213 LONG dwRead; 3214 RpcPktCommonHdr common_hdr; 3215 3216 *Header = NULL; 3217 3218 TRACE("(%p, %p, %p)\n", Connection, Header, Payload); 3219 3220 again: 3221 /* read packet common header */ 3222 dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr)); 3223 if (dwRead != sizeof(common_hdr)) { 3224 WARN("Short read of header, %d bytes\n", dwRead); 3225 status = RPC_S_PROTOCOL_ERROR; 3226 goto fail; 3227 } 3228 if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) || 3229 !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0"))) 3230 { 3231 FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr)); 3232 status = RPC_S_PROTOCOL_ERROR; 3233 goto fail; 3234 } 3235 3236 status = RPCRT4_ValidateCommonHeader(&common_hdr); 3237 if (status != RPC_S_OK) goto fail; 3238 3239 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr); 3240 if (hdr_length == 0) { 3241 WARN("header length == 0\n"); 3242 status = RPC_S_PROTOCOL_ERROR; 3243 goto fail; 3244 } 3245 3246 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length); 3247 if (!*Header) 3248 { 3249 status = RPC_S_OUT_OF_RESOURCES; 3250 goto fail; 3251 } 3252 memcpy(*Header, &common_hdr, sizeof(common_hdr)); 3253 3254 /* read the rest of packet header */ 3255 dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr)); 3256 if (dwRead != hdr_length - sizeof(common_hdr)) { 3257 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length); 3258 status = RPC_S_PROTOCOL_ERROR; 3259 goto fail; 3260 } 3261 3262 if (common_hdr.frag_len - hdr_length) 3263 { 3264 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length); 3265 if (!*Payload) 3266 { 3267 status = RPC_S_OUT_OF_RESOURCES; 3268 goto fail; 3269 } 3270 3271 dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length); 3272 if (dwRead != common_hdr.frag_len - hdr_length) 3273 { 3274 WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length); 3275 status = RPC_S_PROTOCOL_ERROR; 3276 goto fail; 3277 } 3278 } 3279 else 3280 *Payload = NULL; 3281 3282 if ((*Header)->common.ptype == PKT_HTTP) 3283 { 3284 if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length)) 3285 { 3286 ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len); 3287 status = RPC_S_PROTOCOL_ERROR; 3288 goto fail; 3289 } 3290 if ((*Header)->http.flags == 0x0001) 3291 { 3292 TRACE("http idle packet, waiting for real packet\n"); 3293 if ((*Header)->http.num_data_items != 0) 3294 { 3295 ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items); 3296 status = RPC_S_PROTOCOL_ERROR; 3297 goto fail; 3298 } 3299 } 3300 else if ((*Header)->http.flags == 0x0002) 3301 { 3302 ULONG bytes_transmitted; 3303 ULONG flow_control_increment; 3304 UUID pipe_uuid; 3305 status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload, 3306 Connection->server, 3307 &bytes_transmitted, 3308 &flow_control_increment, 3309 &pipe_uuid); 3310 if (status != RPC_S_OK) 3311 goto fail; 3312 TRACE("received http flow control header (0x%x, 0x%x, %s)\n", 3313 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid)); 3314 /* FIXME: do something with parsed data */ 3315 } 3316 else 3317 { 3318 FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags); 3319 status = RPC_S_PROTOCOL_ERROR; 3320 goto fail; 3321 } 3322 RPCRT4_FreeHeader(*Header); 3323 *Header = NULL; 3324 HeapFree(GetProcessHeap(), 0, *Payload); 3325 *Payload = NULL; 3326 goto again; 3327 } 3328 3329 /* success */ 3330 status = RPC_S_OK; 3331 3332 httpc->bytes_received += common_hdr.frag_len; 3333 3334 TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received); 3335 3336 if (httpc->bytes_received > httpc->flow_control_mark) 3337 { 3338 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server, 3339 httpc->bytes_received, 3340 httpc->flow_control_increment, 3341 &httpc->out_pipe_uuid); 3342 if (hdr) 3343 { 3344 DWORD bytes_written; 3345 BOOL ret2; 3346 TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received); 3347 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written); 3348 RPCRT4_FreeHeader(hdr); 3349 if (ret2) 3350 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2; 3351 } 3352 } 3353 3354 fail: 3355 if (status != RPC_S_OK) { 3356 RPCRT4_FreeHeader(*Header); 3357 *Header = NULL; 3358 HeapFree(GetProcessHeap(), 0, *Payload); 3359 *Payload = NULL; 3360 } 3361 return status; 3362 } 3363 3364 static int rpcrt4_ncacn_http_write(RpcConnection *Connection, 3365 const void *buffer, unsigned int count) 3366 { 3367 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3368 DWORD bytes_written; 3369 BOOL ret; 3370 3371 httpc->last_sent_time = ~0U; /* disable idle packet sending */ 3372 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written); 3373 httpc->last_sent_time = GetTickCount(); 3374 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE"); 3375 return ret ? bytes_written : -1; 3376 } 3377 3378 static int rpcrt4_ncacn_http_close(RpcConnection *Connection) 3379 { 3380 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3381 3382 TRACE("\n"); 3383 3384 SetEvent(httpc->timer_cancelled); 3385 if (httpc->in_request) 3386 InternetCloseHandle(httpc->in_request); 3387 httpc->in_request = NULL; 3388 if (httpc->out_request) 3389 InternetCloseHandle(httpc->out_request); 3390 httpc->out_request = NULL; 3391 if (httpc->app_info) 3392 InternetCloseHandle(httpc->app_info); 3393 httpc->app_info = NULL; 3394 if (httpc->session) 3395 InternetCloseHandle(httpc->session); 3396 httpc->session = NULL; 3397 RpcHttpAsyncData_Release(httpc->async_data); 3398 if (httpc->cancel_event) 3399 CloseHandle(httpc->cancel_event); 3400 HeapFree(GetProcessHeap(), 0, httpc->servername); 3401 httpc->servername = NULL; 3402 3403 return 0; 3404 } 3405 3406 static void rpcrt4_ncacn_http_close_read(RpcConnection *conn) 3407 { 3408 rpcrt4_ncacn_http_close(conn); /* FIXME */ 3409 } 3410 3411 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection) 3412 { 3413 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3414 3415 SetEvent(httpc->cancel_event); 3416 } 3417 3418 static RPC_STATUS rpcrt4_ncacn_http_is_server_listening(const char *endpoint) 3419 { 3420 FIXME("\n"); 3421 return RPC_S_ACCESS_DENIED; 3422 } 3423 3424 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection) 3425 { 3426 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3427 BOOL ret; 3428 RPC_STATUS status; 3429 3430 prepare_async_request(httpc->async_data); 3431 ret = InternetQueryDataAvailable(httpc->out_request, 3432 &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0); 3433 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event); 3434 return status == RPC_S_OK ? 0 : -1; 3435 } 3436 3437 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data, 3438 const char *networkaddr, 3439 const char *endpoint) 3440 { 3441 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr, 3442 EPM_PROTOCOL_HTTP, endpoint); 3443 } 3444 3445 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data, 3446 size_t tower_size, 3447 char **networkaddr, 3448 char **endpoint) 3449 { 3450 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size, 3451 networkaddr, EPM_PROTOCOL_HTTP, 3452 endpoint); 3453 } 3454 3455 static const struct connection_ops conn_protseq_list[] = { 3456 { "ncacn_np", 3457 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB }, 3458 rpcrt4_conn_np_alloc, 3459 rpcrt4_ncacn_np_open, 3460 rpcrt4_ncacn_np_handoff, 3461 rpcrt4_conn_np_read, 3462 rpcrt4_conn_np_write, 3463 rpcrt4_conn_np_close, 3464 rpcrt4_conn_np_close_read, 3465 rpcrt4_conn_np_cancel_call, 3466 rpcrt4_ncacn_np_is_server_listening, 3467 rpcrt4_conn_np_wait_for_incoming_data, 3468 rpcrt4_ncacn_np_get_top_of_tower, 3469 rpcrt4_ncacn_np_parse_top_of_tower, 3470 NULL, 3471 RPCRT4_default_is_authorized, 3472 RPCRT4_default_authorize, 3473 RPCRT4_default_secure_packet, 3474 rpcrt4_conn_np_impersonate_client, 3475 rpcrt4_conn_np_revert_to_self, 3476 RPCRT4_default_inquire_auth_client, 3477 }, 3478 { "ncalrpc", 3479 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE }, 3480 rpcrt4_conn_np_alloc, 3481 rpcrt4_ncalrpc_open, 3482 rpcrt4_ncalrpc_handoff, 3483 rpcrt4_conn_np_read, 3484 rpcrt4_conn_np_write, 3485 rpcrt4_conn_np_close, 3486 rpcrt4_conn_np_close_read, 3487 rpcrt4_conn_np_cancel_call, 3488 rpcrt4_ncalrpc_np_is_server_listening, 3489 rpcrt4_conn_np_wait_for_incoming_data, 3490 rpcrt4_ncalrpc_get_top_of_tower, 3491 rpcrt4_ncalrpc_parse_top_of_tower, 3492 NULL, 3493 rpcrt4_ncalrpc_is_authorized, 3494 rpcrt4_ncalrpc_authorize, 3495 rpcrt4_ncalrpc_secure_packet, 3496 rpcrt4_conn_np_impersonate_client, 3497 rpcrt4_conn_np_revert_to_self, 3498 rpcrt4_ncalrpc_inquire_auth_client, 3499 }, 3500 { "ncacn_ip_tcp", 3501 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP }, 3502 rpcrt4_conn_tcp_alloc, 3503 rpcrt4_ncacn_ip_tcp_open, 3504 rpcrt4_conn_tcp_handoff, 3505 rpcrt4_conn_tcp_read, 3506 rpcrt4_conn_tcp_write, 3507 rpcrt4_conn_tcp_close, 3508 rpcrt4_conn_tcp_close_read, 3509 rpcrt4_conn_tcp_cancel_call, 3510 rpcrt4_conn_tcp_is_server_listening, 3511 rpcrt4_conn_tcp_wait_for_incoming_data, 3512 rpcrt4_ncacn_ip_tcp_get_top_of_tower, 3513 rpcrt4_ncacn_ip_tcp_parse_top_of_tower, 3514 NULL, 3515 RPCRT4_default_is_authorized, 3516 RPCRT4_default_authorize, 3517 RPCRT4_default_secure_packet, 3518 RPCRT4_default_impersonate_client, 3519 RPCRT4_default_revert_to_self, 3520 RPCRT4_default_inquire_auth_client, 3521 }, 3522 { "ncacn_http", 3523 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP }, 3524 rpcrt4_ncacn_http_alloc, 3525 rpcrt4_ncacn_http_open, 3526 rpcrt4_ncacn_http_handoff, 3527 rpcrt4_ncacn_http_read, 3528 rpcrt4_ncacn_http_write, 3529 rpcrt4_ncacn_http_close, 3530 rpcrt4_ncacn_http_close_read, 3531 rpcrt4_ncacn_http_cancel_call, 3532 rpcrt4_ncacn_http_is_server_listening, 3533 rpcrt4_ncacn_http_wait_for_incoming_data, 3534 rpcrt4_ncacn_http_get_top_of_tower, 3535 rpcrt4_ncacn_http_parse_top_of_tower, 3536 rpcrt4_ncacn_http_receive_fragment, 3537 RPCRT4_default_is_authorized, 3538 RPCRT4_default_authorize, 3539 RPCRT4_default_secure_packet, 3540 RPCRT4_default_impersonate_client, 3541 RPCRT4_default_revert_to_self, 3542 RPCRT4_default_inquire_auth_client, 3543 }, 3544 }; 3545 3546 3547 static const struct protseq_ops protseq_list[] = 3548 { 3549 { 3550 "ncacn_np", 3551 rpcrt4_protseq_np_alloc, 3552 rpcrt4_protseq_np_signal_state_changed, 3553 rpcrt4_protseq_np_get_wait_array, 3554 rpcrt4_protseq_np_free_wait_array, 3555 rpcrt4_protseq_np_wait_for_new_connection, 3556 rpcrt4_protseq_ncacn_np_open_endpoint, 3557 }, 3558 { 3559 "ncalrpc", 3560 rpcrt4_protseq_np_alloc, 3561 rpcrt4_protseq_np_signal_state_changed, 3562 rpcrt4_protseq_np_get_wait_array, 3563 rpcrt4_protseq_np_free_wait_array, 3564 rpcrt4_protseq_np_wait_for_new_connection, 3565 rpcrt4_protseq_ncalrpc_open_endpoint, 3566 }, 3567 { 3568 "ncacn_ip_tcp", 3569 rpcrt4_protseq_sock_alloc, 3570 rpcrt4_protseq_sock_signal_state_changed, 3571 rpcrt4_protseq_sock_get_wait_array, 3572 rpcrt4_protseq_sock_free_wait_array, 3573 rpcrt4_protseq_sock_wait_for_new_connection, 3574 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint, 3575 }, 3576 }; 3577 3578 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq) 3579 { 3580 unsigned int i; 3581 for(i = 0; i < ARRAY_SIZE(protseq_list); i++) 3582 if (!strcmp(protseq_list[i].name, protseq)) 3583 return &protseq_list[i]; 3584 return NULL; 3585 } 3586 3587 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq) 3588 { 3589 unsigned int i; 3590 for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++) 3591 if (!strcmp(conn_protseq_list[i].name, protseq)) 3592 return &conn_protseq_list[i]; 3593 return NULL; 3594 } 3595 3596 /**** interface to rest of code ****/ 3597 3598 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection) 3599 { 3600 TRACE("(Connection == ^%p)\n", Connection); 3601 3602 assert(!Connection->server); 3603 return Connection->ops->open_connection_client(Connection); 3604 } 3605 3606 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) 3607 { 3608 TRACE("(Connection == ^%p)\n", Connection); 3609 if (SecIsValidHandle(&Connection->ctx)) 3610 { 3611 DeleteSecurityContext(&Connection->ctx); 3612 SecInvalidateHandle(&Connection->ctx); 3613 } 3614 rpcrt4_conn_close(Connection); 3615 return RPC_S_OK; 3616 } 3617 3618 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, 3619 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, 3620 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth) 3621 { 3622 static LONG next_id; 3623 const struct connection_ops *ops; 3624 RpcConnection* NewConnection; 3625 3626 ops = rpcrt4_get_conn_protseq_ops(Protseq); 3627 if (!ops) 3628 { 3629 FIXME("not supported for protseq %s\n", Protseq); 3630 return RPC_S_PROTSEQ_NOT_SUPPORTED; 3631 } 3632 3633 NewConnection = ops->alloc(); 3634 NewConnection->ref = 1; 3635 NewConnection->server = server; 3636 NewConnection->ops = ops; 3637 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); 3638 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); 3639 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions); 3640 NewConnection->CookieAuth = RPCRT4_strdupW(CookieAuth); 3641 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; 3642 NewConnection->NextCallId = 1; 3643 3644 SecInvalidateHandle(&NewConnection->ctx); 3645 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo); 3646 NewConnection->AuthInfo = AuthInfo; 3647 NewConnection->auth_context_id = InterlockedIncrement( &next_id ); 3648 if (QOS) RpcQualityOfService_AddRef(QOS); 3649 NewConnection->QOS = QOS; 3650 3651 list_init(&NewConnection->conn_pool_entry); 3652 list_init(&NewConnection->protseq_entry); 3653 3654 TRACE("connection: %p\n", NewConnection); 3655 *Connection = NewConnection; 3656 3657 return RPC_S_OK; 3658 } 3659 3660 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection) 3661 { 3662 RpcConnection *connection; 3663 RPC_STATUS err; 3664 3665 err = RPCRT4_CreateConnection(&connection, old_connection->server, rpcrt4_conn_get_name(old_connection), 3666 old_connection->NetworkAddr, old_connection->Endpoint, NULL, 3667 old_connection->AuthInfo, old_connection->QOS, old_connection->CookieAuth); 3668 if (err != RPC_S_OK) 3669 return NULL; 3670 3671 rpcrt4_conn_handoff(old_connection, connection); 3672 if (old_connection->protseq) 3673 { 3674 EnterCriticalSection(&old_connection->protseq->cs); 3675 connection->protseq = old_connection->protseq; 3676 list_add_tail(&old_connection->protseq->connections, &connection->protseq_entry); 3677 LeaveCriticalSection(&old_connection->protseq->cs); 3678 } 3679 return connection; 3680 } 3681 3682 void rpcrt4_conn_release_and_wait(RpcConnection *connection) 3683 { 3684 HANDLE event = NULL; 3685 3686 if (connection->ref > 1) 3687 event = connection->wait_release = CreateEventW(NULL, TRUE, FALSE, NULL); 3688 3689 RPCRT4_ReleaseConnection(connection); 3690 3691 if(event) 3692 { 3693 WaitForSingleObject(event, INFINITE); 3694 CloseHandle(event); 3695 } 3696 } 3697 3698 RpcConnection *RPCRT4_GrabConnection(RpcConnection *connection) 3699 { 3700 LONG ref = InterlockedIncrement(&connection->ref); 3701 TRACE("%p ref=%u\n", connection, ref); 3702 return connection; 3703 } 3704 3705 void RPCRT4_ReleaseConnection(RpcConnection *connection) 3706 { 3707 LONG ref; 3708 3709 /* protseq stores a list of active connections, but does not own references to them. 3710 * It may need to grab a connection from the list, which could lead to a race if 3711 * connection is being released, but not yet removed from the list. We handle that 3712 * by synchronizing on CS here. */ 3713 if (connection->protseq) 3714 { 3715 EnterCriticalSection(&connection->protseq->cs); 3716 ref = InterlockedDecrement(&connection->ref); 3717 if (!ref) 3718 list_remove(&connection->protseq_entry); 3719 LeaveCriticalSection(&connection->protseq->cs); 3720 } 3721 else 3722 { 3723 ref = InterlockedDecrement(&connection->ref); 3724 } 3725 3726 TRACE("%p ref=%u\n", connection, ref); 3727 3728 if (!ref) 3729 { 3730 RPCRT4_CloseConnection(connection); 3731 RPCRT4_strfree(connection->Endpoint); 3732 RPCRT4_strfree(connection->NetworkAddr); 3733 HeapFree(GetProcessHeap(), 0, connection->NetworkOptions); 3734 HeapFree(GetProcessHeap(), 0, connection->CookieAuth); 3735 if (connection->AuthInfo) RpcAuthInfo_Release(connection->AuthInfo); 3736 if (connection->QOS) RpcQualityOfService_Release(connection->QOS); 3737 3738 /* server-only */ 3739 if (connection->server_binding) RPCRT4_ReleaseBinding(connection->server_binding); 3740 else if (connection->assoc) RpcAssoc_ConnectionReleased(connection->assoc); 3741 3742 if (connection->wait_release) SetEvent(connection->wait_release); 3743 3744 HeapFree(GetProcessHeap(), 0, connection); 3745 } 3746 } 3747 3748 RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint) 3749 { 3750 const struct connection_ops *ops; 3751 3752 ops = rpcrt4_get_conn_protseq_ops(protseq); 3753 if (!ops) 3754 { 3755 FIXME("not supported for protseq %s\n", protseq); 3756 return RPC_S_INVALID_BINDING; 3757 } 3758 3759 return ops->is_server_listening(endpoint); 3760 } 3761 3762 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, 3763 size_t *tower_size, 3764 const char *protseq, 3765 const char *networkaddr, 3766 const char *endpoint) 3767 { 3768 twr_empty_floor_t *protocol_floor; 3769 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq); 3770 3771 *tower_size = 0; 3772 3773 if (!protseq_ops) 3774 return RPC_S_INVALID_RPC_PROTSEQ; 3775 3776 if (!tower_data) 3777 { 3778 *tower_size = sizeof(*protocol_floor); 3779 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint); 3780 return RPC_S_OK; 3781 } 3782 3783 protocol_floor = (twr_empty_floor_t *)tower_data; 3784 protocol_floor->count_lhs = sizeof(protocol_floor->protid); 3785 protocol_floor->protid = protseq_ops->epm_protocols[0]; 3786 protocol_floor->count_rhs = 0; 3787 3788 tower_data += sizeof(*protocol_floor); 3789 3790 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint); 3791 if (!*tower_size) 3792 return EPT_S_NOT_REGISTERED; 3793 3794 *tower_size += sizeof(*protocol_floor); 3795 3796 return RPC_S_OK; 3797 } 3798 3799 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, 3800 size_t tower_size, 3801 char **protseq, 3802 char **networkaddr, 3803 char **endpoint) 3804 { 3805 const twr_empty_floor_t *protocol_floor; 3806 const twr_empty_floor_t *floor4; 3807 const struct connection_ops *protseq_ops = NULL; 3808 RPC_STATUS status; 3809 unsigned int i; 3810 3811 if (tower_size < sizeof(*protocol_floor)) 3812 return EPT_S_NOT_REGISTERED; 3813 3814 protocol_floor = (const twr_empty_floor_t *)tower_data; 3815 tower_data += sizeof(*protocol_floor); 3816 tower_size -= sizeof(*protocol_floor); 3817 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) || 3818 (protocol_floor->count_rhs > tower_size)) 3819 return EPT_S_NOT_REGISTERED; 3820 tower_data += protocol_floor->count_rhs; 3821 tower_size -= protocol_floor->count_rhs; 3822 3823 floor4 = (const twr_empty_floor_t *)tower_data; 3824 if ((tower_size < sizeof(*floor4)) || 3825 (floor4->count_lhs != sizeof(floor4->protid))) 3826 return EPT_S_NOT_REGISTERED; 3827 3828 for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++) 3829 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) && 3830 (floor4->protid == conn_protseq_list[i].epm_protocols[1])) 3831 { 3832 protseq_ops = &conn_protseq_list[i]; 3833 break; 3834 } 3835 3836 if (!protseq_ops) 3837 return EPT_S_NOT_REGISTERED; 3838 3839 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint); 3840 3841 if ((status == RPC_S_OK) && protseq) 3842 { 3843 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1); 3844 strcpy(*protseq, protseq_ops->name); 3845 } 3846 3847 return status; 3848 } 3849 3850 /*********************************************************************** 3851 * RpcNetworkIsProtseqValidW (RPCRT4.@) 3852 * 3853 * Checks if the given protocol sequence is known by the RPC system. 3854 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED. 3855 * 3856 */ 3857 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq) 3858 { 3859 char ps[0x10]; 3860 3861 WideCharToMultiByte(CP_ACP, 0, protseq, -1, 3862 ps, sizeof ps, NULL, NULL); 3863 if (rpcrt4_get_conn_protseq_ops(ps)) 3864 return RPC_S_OK; 3865 3866 FIXME("Unknown protseq %s\n", debugstr_w(protseq)); 3867 3868 return RPC_S_INVALID_RPC_PROTSEQ; 3869 } 3870 3871 /*********************************************************************** 3872 * RpcNetworkIsProtseqValidA (RPCRT4.@) 3873 */ 3874 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq) 3875 { 3876 UNICODE_STRING protseqW; 3877 3878 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq)) 3879 { 3880 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer); 3881 RtlFreeUnicodeString(&protseqW); 3882 return ret; 3883 } 3884 return RPC_S_OUT_OF_MEMORY; 3885 } 3886 3887 /*********************************************************************** 3888 * RpcProtseqVectorFreeA (RPCRT4.@) 3889 */ 3890 RPC_STATUS WINAPI RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA **protseqs) 3891 { 3892 TRACE("(%p)\n", protseqs); 3893 3894 if (*protseqs) 3895 { 3896 unsigned int i; 3897 for (i = 0; i < (*protseqs)->Count; i++) 3898 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]); 3899 HeapFree(GetProcessHeap(), 0, *protseqs); 3900 *protseqs = NULL; 3901 } 3902 return RPC_S_OK; 3903 } 3904 3905 /*********************************************************************** 3906 * RpcProtseqVectorFreeW (RPCRT4.@) 3907 */ 3908 RPC_STATUS WINAPI RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW **protseqs) 3909 { 3910 TRACE("(%p)\n", protseqs); 3911 3912 if (*protseqs) 3913 { 3914 unsigned int i; 3915 for (i = 0; i < (*protseqs)->Count; i++) 3916 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]); 3917 HeapFree(GetProcessHeap(), 0, *protseqs); 3918 *protseqs = NULL; 3919 } 3920 return RPC_S_OK; 3921 } 3922 3923 /*********************************************************************** 3924 * RpcNetworkInqProtseqsW (RPCRT4.@) 3925 */ 3926 RPC_STATUS WINAPI RpcNetworkInqProtseqsW( RPC_PROTSEQ_VECTORW** protseqs ) 3927 { 3928 RPC_PROTSEQ_VECTORW *pvector; 3929 unsigned int i; 3930 RPC_STATUS status = RPC_S_OUT_OF_MEMORY; 3931 3932 TRACE("(%p)\n", protseqs); 3933 3934 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned short*)*ARRAY_SIZE(protseq_list))); 3935 if (!*protseqs) 3936 goto end; 3937 pvector = *protseqs; 3938 pvector->Count = 0; 3939 for (i = 0; i < ARRAY_SIZE(protseq_list); i++) 3940 { 3941 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, (strlen(protseq_list[i].name)+1)*sizeof(unsigned short)); 3942 if (pvector->Protseq[i] == NULL) 3943 goto end; 3944 MultiByteToWideChar(CP_ACP, 0, (CHAR*)protseq_list[i].name, -1, 3945 (WCHAR*)pvector->Protseq[i], strlen(protseq_list[i].name) + 1); 3946 pvector->Count++; 3947 } 3948 status = RPC_S_OK; 3949 3950 end: 3951 if (status != RPC_S_OK) 3952 RpcProtseqVectorFreeW(protseqs); 3953 return status; 3954 } 3955 3956 /*********************************************************************** 3957 * RpcNetworkInqProtseqsA (RPCRT4.@) 3958 */ 3959 RPC_STATUS WINAPI RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** protseqs) 3960 { 3961 RPC_PROTSEQ_VECTORA *pvector; 3962 unsigned int i; 3963 RPC_STATUS status = RPC_S_OUT_OF_MEMORY; 3964 3965 TRACE("(%p)\n", protseqs); 3966 3967 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned char*)*ARRAY_SIZE(protseq_list))); 3968 if (!*protseqs) 3969 goto end; 3970 pvector = *protseqs; 3971 pvector->Count = 0; 3972 for (i = 0; i < ARRAY_SIZE(protseq_list); i++) 3973 { 3974 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_list[i].name)+1); 3975 if (pvector->Protseq[i] == NULL) 3976 goto end; 3977 strcpy((char*)pvector->Protseq[i], protseq_list[i].name); 3978 pvector->Count++; 3979 } 3980 status = RPC_S_OK; 3981 3982 end: 3983 if (status != RPC_S_OK) 3984 RpcProtseqVectorFreeA(protseqs); 3985 return status; 3986 } 3987