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 #ifdef __REACTOS__ 1261 static BOOL wsa_inited; 1262 if (!wsa_inited) 1263 { 1264 WSADATA wsadata; 1265 WSAStartup(MAKEWORD(2, 2), &wsadata); 1266 /* Note: WSAStartup can be called more than once so we don't bother with 1267 * making accesses to wsa_inited thread-safe */ 1268 wsa_inited = TRUE; 1269 } 1270 #endif 1271 1272 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai); 1273 if (ret) 1274 { 1275 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai); 1276 if (ret) 1277 { 1278 ERR("getaddrinfo failed: %s\n", gai_strerror(ret)); 1279 return 0; 1280 } 1281 } 1282 1283 if (ai->ai_family == PF_INET) 1284 { 1285 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr; 1286 tcp_floor->port = sin->sin_port; 1287 ipv4_floor->ipv4addr = sin->sin_addr.s_addr; 1288 } 1289 else 1290 { 1291 ERR("unexpected protocol family %d\n", ai->ai_family); 1292 freeaddrinfo(ai); 1293 return 0; 1294 } 1295 1296 freeaddrinfo(ai); 1297 1298 return size; 1299 } 1300 1301 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, 1302 size_t tower_size, 1303 char **networkaddr, 1304 unsigned char tcp_protid, 1305 char **endpoint) 1306 { 1307 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data; 1308 const twr_ipv4_floor_t *ipv4_floor; 1309 struct in_addr in_addr; 1310 1311 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); 1312 1313 if (tower_size < sizeof(*tcp_floor)) 1314 return EPT_S_NOT_REGISTERED; 1315 1316 tower_data += sizeof(*tcp_floor); 1317 tower_size -= sizeof(*tcp_floor); 1318 1319 if (tower_size < sizeof(*ipv4_floor)) 1320 return EPT_S_NOT_REGISTERED; 1321 1322 ipv4_floor = (const twr_ipv4_floor_t *)tower_data; 1323 1324 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) || 1325 (tcp_floor->protid != tcp_protid) || 1326 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) || 1327 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) || 1328 (ipv4_floor->protid != EPM_PROTOCOL_IP) || 1329 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr))) 1330 return EPT_S_NOT_REGISTERED; 1331 1332 if (endpoint) 1333 { 1334 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */); 1335 if (!*endpoint) 1336 return RPC_S_OUT_OF_RESOURCES; 1337 sprintf(*endpoint, "%u", ntohs(tcp_floor->port)); 1338 } 1339 1340 if (networkaddr) 1341 { 1342 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN); 1343 if (!*networkaddr) 1344 { 1345 if (endpoint) 1346 { 1347 I_RpcFree(*endpoint); 1348 *endpoint = NULL; 1349 } 1350 return RPC_S_OUT_OF_RESOURCES; 1351 } 1352 in_addr.s_addr = ipv4_floor->ipv4addr; 1353 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN)) 1354 { 1355 ERR("inet_ntop: %u\n", WSAGetLastError()); 1356 I_RpcFree(*networkaddr); 1357 *networkaddr = NULL; 1358 if (endpoint) 1359 { 1360 I_RpcFree(*endpoint); 1361 *endpoint = NULL; 1362 } 1363 return EPT_S_NOT_REGISTERED; 1364 } 1365 } 1366 1367 return RPC_S_OK; 1368 } 1369 1370 typedef struct _RpcConnection_tcp 1371 { 1372 RpcConnection common; 1373 int sock; 1374 HANDLE sock_event; 1375 HANDLE cancel_event; 1376 } RpcConnection_tcp; 1377 1378 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc) 1379 { 1380 static BOOL wsa_inited; 1381 if (!wsa_inited) 1382 { 1383 WSADATA wsadata; 1384 WSAStartup(MAKEWORD(2, 2), &wsadata); 1385 /* Note: WSAStartup can be called more than once so we don't bother with 1386 * making accesses to wsa_inited thread-safe */ 1387 wsa_inited = TRUE; 1388 } 1389 tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1390 tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1391 if (!tcpc->sock_event || !tcpc->cancel_event) 1392 { 1393 ERR("event creation failed\n"); 1394 if (tcpc->sock_event) CloseHandle(tcpc->sock_event); 1395 return FALSE; 1396 } 1397 return TRUE; 1398 } 1399 1400 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc) 1401 { 1402 HANDLE wait_handles[2]; 1403 DWORD res; 1404 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR) 1405 { 1406 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); 1407 return FALSE; 1408 } 1409 wait_handles[0] = tcpc->sock_event; 1410 wait_handles[1] = tcpc->cancel_event; 1411 res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE); 1412 switch (res) 1413 { 1414 case WAIT_OBJECT_0: 1415 return TRUE; 1416 case WAIT_OBJECT_0 + 1: 1417 return FALSE; 1418 default: 1419 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError()); 1420 return FALSE; 1421 } 1422 } 1423 1424 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc) 1425 { 1426 DWORD res; 1427 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR) 1428 { 1429 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); 1430 return FALSE; 1431 } 1432 res = WaitForSingleObject(tcpc->sock_event, INFINITE); 1433 switch (res) 1434 { 1435 case WAIT_OBJECT_0: 1436 return TRUE; 1437 default: 1438 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError()); 1439 return FALSE; 1440 } 1441 } 1442 1443 static RpcConnection *rpcrt4_conn_tcp_alloc(void) 1444 { 1445 RpcConnection_tcp *tcpc; 1446 tcpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp)); 1447 if (tcpc == NULL) 1448 return NULL; 1449 tcpc->sock = -1; 1450 if (!rpcrt4_sock_wait_init(tcpc)) 1451 { 1452 HeapFree(GetProcessHeap(), 0, tcpc); 1453 return NULL; 1454 } 1455 return &tcpc->common; 1456 } 1457 1458 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection) 1459 { 1460 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; 1461 int sock; 1462 int ret; 1463 struct addrinfo *ai; 1464 struct addrinfo *ai_cur; 1465 struct addrinfo hints; 1466 1467 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); 1468 1469 if (tcpc->sock != -1) 1470 return RPC_S_OK; 1471 1472 hints.ai_flags = 0; 1473 hints.ai_family = PF_UNSPEC; 1474 hints.ai_socktype = SOCK_STREAM; 1475 hints.ai_protocol = IPPROTO_TCP; 1476 hints.ai_addrlen = 0; 1477 hints.ai_addr = NULL; 1478 hints.ai_canonname = NULL; 1479 hints.ai_next = NULL; 1480 1481 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai); 1482 if (ret) 1483 { 1484 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr, 1485 Connection->Endpoint, gai_strerror(ret)); 1486 return RPC_S_SERVER_UNAVAILABLE; 1487 } 1488 1489 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) 1490 { 1491 int val; 1492 u_long nonblocking; 1493 1494 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6) 1495 { 1496 TRACE("skipping non-IP/IPv6 address family\n"); 1497 continue; 1498 } 1499 1500 if (TRACE_ON(rpc)) 1501 { 1502 char host[256]; 1503 char service[256]; 1504 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, 1505 host, sizeof(host), service, sizeof(service), 1506 NI_NUMERICHOST | NI_NUMERICSERV); 1507 TRACE("trying %s:%s\n", host, service); 1508 } 1509 1510 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); 1511 if (sock == -1) 1512 { 1513 WARN("socket() failed: %u\n", WSAGetLastError()); 1514 continue; 1515 } 1516 1517 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen)) 1518 { 1519 WARN("connect() failed: %u\n", WSAGetLastError()); 1520 closesocket(sock); 1521 continue; 1522 } 1523 1524 /* RPC depends on having minimal latency so disable the Nagle algorithm */ 1525 val = 1; 1526 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); 1527 nonblocking = 1; 1528 ioctlsocket(sock, FIONBIO, &nonblocking); 1529 1530 tcpc->sock = sock; 1531 1532 freeaddrinfo(ai); 1533 TRACE("connected\n"); 1534 return RPC_S_OK; 1535 } 1536 1537 freeaddrinfo(ai); 1538 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint); 1539 return RPC_S_SERVER_UNAVAILABLE; 1540 } 1541 1542 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint) 1543 { 1544 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT; 1545 int sock; 1546 int ret; 1547 struct addrinfo *ai; 1548 struct addrinfo *ai_cur; 1549 struct addrinfo hints; 1550 1551 TRACE("(%p, %s)\n", protseq, endpoint); 1552 1553 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */; 1554 hints.ai_family = PF_UNSPEC; 1555 hints.ai_socktype = SOCK_STREAM; 1556 hints.ai_protocol = IPPROTO_TCP; 1557 hints.ai_addrlen = 0; 1558 hints.ai_addr = NULL; 1559 hints.ai_canonname = NULL; 1560 hints.ai_next = NULL; 1561 1562 ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai); 1563 if (ret) 1564 { 1565 ERR("getaddrinfo for port %s failed: %s\n", endpoint, 1566 gai_strerror(ret)); 1567 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME)) 1568 return RPC_S_INVALID_ENDPOINT_FORMAT; 1569 return RPC_S_CANT_CREATE_ENDPOINT; 1570 } 1571 1572 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) 1573 { 1574 RpcConnection_tcp *tcpc; 1575 RPC_STATUS create_status; 1576 struct sockaddr_storage sa; 1577 socklen_t sa_len; 1578 char service[NI_MAXSERV]; 1579 u_long nonblocking; 1580 1581 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6) 1582 { 1583 TRACE("skipping non-IP/IPv6 address family\n"); 1584 continue; 1585 } 1586 1587 if (TRACE_ON(rpc)) 1588 { 1589 char host[256]; 1590 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, 1591 host, sizeof(host), service, sizeof(service), 1592 NI_NUMERICHOST | NI_NUMERICSERV); 1593 TRACE("trying %s:%s\n", host, service); 1594 } 1595 1596 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); 1597 if (sock == -1) 1598 { 1599 WARN("socket() failed: %u\n", WSAGetLastError()); 1600 status = RPC_S_CANT_CREATE_ENDPOINT; 1601 continue; 1602 } 1603 1604 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen); 1605 if (ret < 0) 1606 { 1607 WARN("bind failed: %u\n", WSAGetLastError()); 1608 closesocket(sock); 1609 if (WSAGetLastError() == WSAEADDRINUSE) 1610 status = RPC_S_DUPLICATE_ENDPOINT; 1611 else 1612 status = RPC_S_CANT_CREATE_ENDPOINT; 1613 continue; 1614 } 1615 1616 sa_len = sizeof(sa); 1617 if (getsockname(sock, (struct sockaddr *)&sa, &sa_len)) 1618 { 1619 WARN("getsockname() failed: %u\n", WSAGetLastError()); 1620 closesocket(sock); 1621 status = RPC_S_CANT_CREATE_ENDPOINT; 1622 continue; 1623 } 1624 1625 ret = getnameinfo((struct sockaddr *)&sa, sa_len, 1626 NULL, 0, service, sizeof(service), 1627 NI_NUMERICSERV); 1628 if (ret) 1629 { 1630 WARN("getnameinfo failed: %s\n", gai_strerror(ret)); 1631 closesocket(sock); 1632 status = RPC_S_CANT_CREATE_ENDPOINT; 1633 continue; 1634 } 1635 1636 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE, 1637 protseq->Protseq, NULL, 1638 service, NULL, NULL, NULL, NULL); 1639 if (create_status != RPC_S_OK) 1640 { 1641 closesocket(sock); 1642 status = create_status; 1643 continue; 1644 } 1645 1646 tcpc->sock = sock; 1647 ret = listen(sock, protseq->MaxCalls); 1648 if (ret < 0) 1649 { 1650 WARN("listen failed: %u\n", WSAGetLastError()); 1651 RPCRT4_ReleaseConnection(&tcpc->common); 1652 status = RPC_S_OUT_OF_RESOURCES; 1653 continue; 1654 } 1655 /* need a non-blocking socket, otherwise accept() has a potential 1656 * race-condition (poll() says it is readable, connection drops, 1657 * and accept() blocks until the next connection comes...) 1658 */ 1659 nonblocking = 1; 1660 ret = ioctlsocket(sock, FIONBIO, &nonblocking); 1661 if (ret < 0) 1662 { 1663 WARN("couldn't make socket non-blocking, error %d\n", ret); 1664 RPCRT4_ReleaseConnection(&tcpc->common); 1665 status = RPC_S_OUT_OF_RESOURCES; 1666 continue; 1667 } 1668 1669 EnterCriticalSection(&protseq->cs); 1670 list_add_tail(&protseq->listeners, &tcpc->common.protseq_entry); 1671 tcpc->common.protseq = protseq; 1672 LeaveCriticalSection(&protseq->cs); 1673 1674 freeaddrinfo(ai); 1675 1676 /* since IPv4 and IPv6 share the same port space, we only need one 1677 * successful bind to listen for both */ 1678 TRACE("listening on %s\n", endpoint); 1679 return RPC_S_OK; 1680 } 1681 1682 freeaddrinfo(ai); 1683 ERR("couldn't listen on port %s\n", endpoint); 1684 return status; 1685 } 1686 1687 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn) 1688 { 1689 int ret; 1690 struct sockaddr_in address; 1691 socklen_t addrsize; 1692 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn; 1693 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn; 1694 u_long nonblocking; 1695 1696 addrsize = sizeof(address); 1697 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize); 1698 if (ret < 0) 1699 { 1700 ERR("Failed to accept a TCP connection: error %d\n", ret); 1701 return RPC_S_OUT_OF_RESOURCES; 1702 } 1703 1704 nonblocking = 1; 1705 ioctlsocket(ret, FIONBIO, &nonblocking); 1706 client->sock = ret; 1707 1708 client->common.NetworkAddr = HeapAlloc(GetProcessHeap(), 0, INET6_ADDRSTRLEN); 1709 ret = getnameinfo((struct sockaddr*)&address, addrsize, client->common.NetworkAddr, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST); 1710 if (ret != 0) 1711 { 1712 ERR("Failed to retrieve the IP address, error %d\n", ret); 1713 return RPC_S_OUT_OF_RESOURCES; 1714 } 1715 1716 TRACE("Accepted a new TCP connection from %s\n", client->common.NetworkAddr); 1717 return RPC_S_OK; 1718 } 1719 1720 static int rpcrt4_conn_tcp_read(RpcConnection *Connection, 1721 void *buffer, unsigned int count) 1722 { 1723 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; 1724 int bytes_read = 0; 1725 while (bytes_read != count) 1726 { 1727 int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0); 1728 if (!r) 1729 return -1; 1730 else if (r > 0) 1731 bytes_read += r; 1732 else if (WSAGetLastError() == WSAEINTR) 1733 continue; 1734 else if (WSAGetLastError() != WSAEWOULDBLOCK) 1735 { 1736 WARN("recv() failed: %u\n", WSAGetLastError()); 1737 return -1; 1738 } 1739 else 1740 { 1741 if (!rpcrt4_sock_wait_for_recv(tcpc)) 1742 return -1; 1743 } 1744 } 1745 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read); 1746 return bytes_read; 1747 } 1748 1749 static int rpcrt4_conn_tcp_write(RpcConnection *Connection, 1750 const void *buffer, unsigned int count) 1751 { 1752 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; 1753 int bytes_written = 0; 1754 while (bytes_written != count) 1755 { 1756 int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0); 1757 if (r >= 0) 1758 bytes_written += r; 1759 else if (WSAGetLastError() == WSAEINTR) 1760 continue; 1761 else if (WSAGetLastError() != WSAEWOULDBLOCK) 1762 return -1; 1763 else 1764 { 1765 if (!rpcrt4_sock_wait_for_send(tcpc)) 1766 return -1; 1767 } 1768 } 1769 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written); 1770 return bytes_written; 1771 } 1772 1773 static int rpcrt4_conn_tcp_close(RpcConnection *conn) 1774 { 1775 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn; 1776 1777 TRACE("%d\n", connection->sock); 1778 1779 if (connection->sock != -1) 1780 closesocket(connection->sock); 1781 connection->sock = -1; 1782 CloseHandle(connection->sock_event); 1783 CloseHandle(connection->cancel_event); 1784 return 0; 1785 } 1786 1787 static void rpcrt4_conn_tcp_close_read(RpcConnection *conn) 1788 { 1789 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn; 1790 shutdown(connection->sock, SD_RECEIVE); 1791 } 1792 1793 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *conn) 1794 { 1795 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn; 1796 1797 TRACE("%p\n", connection); 1798 1799 SetEvent(connection->cancel_event); 1800 } 1801 1802 static RPC_STATUS rpcrt4_conn_tcp_is_server_listening(const char *endpoint) 1803 { 1804 FIXME("\n"); 1805 return RPC_S_ACCESS_DENIED; 1806 } 1807 1808 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection) 1809 { 1810 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; 1811 1812 TRACE("%p\n", Connection); 1813 1814 if (!rpcrt4_sock_wait_for_recv(tcpc)) 1815 return -1; 1816 return 0; 1817 } 1818 1819 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, 1820 const char *networkaddr, 1821 const char *endpoint) 1822 { 1823 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr, 1824 EPM_PROTOCOL_TCP, endpoint); 1825 } 1826 1827 typedef struct _RpcServerProtseq_sock 1828 { 1829 RpcServerProtseq common; 1830 HANDLE mgr_event; 1831 } RpcServerProtseq_sock; 1832 1833 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void) 1834 { 1835 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps)); 1836 if (ps) 1837 { 1838 static BOOL wsa_inited; 1839 if (!wsa_inited) 1840 { 1841 WSADATA wsadata; 1842 WSAStartup(MAKEWORD(2, 2), &wsadata); 1843 /* Note: WSAStartup can be called more than once so we don't bother with 1844 * making accesses to wsa_inited thread-safe */ 1845 wsa_inited = TRUE; 1846 } 1847 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); 1848 } 1849 return &ps->common; 1850 } 1851 1852 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq) 1853 { 1854 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); 1855 SetEvent(sockps->mgr_event); 1856 } 1857 1858 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) 1859 { 1860 HANDLE *objs = prev_array; 1861 RpcConnection_tcp *conn; 1862 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); 1863 1864 EnterCriticalSection(&protseq->cs); 1865 1866 /* open and count connections */ 1867 *count = 1; 1868 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry) 1869 { 1870 if (conn->sock != -1) 1871 (*count)++; 1872 } 1873 1874 /* make array of connections */ 1875 if (objs) 1876 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE)); 1877 else 1878 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE)); 1879 if (!objs) 1880 { 1881 ERR("couldn't allocate objs\n"); 1882 LeaveCriticalSection(&protseq->cs); 1883 return NULL; 1884 } 1885 1886 objs[0] = sockps->mgr_event; 1887 *count = 1; 1888 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry) 1889 { 1890 if (conn->sock != -1) 1891 { 1892 int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT); 1893 if (res == SOCKET_ERROR) 1894 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError()); 1895 else 1896 { 1897 objs[*count] = conn->sock_event; 1898 (*count)++; 1899 } 1900 } 1901 } 1902 LeaveCriticalSection(&protseq->cs); 1903 return objs; 1904 } 1905 1906 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array) 1907 { 1908 HeapFree(GetProcessHeap(), 0, array); 1909 } 1910 1911 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array) 1912 { 1913 HANDLE b_handle; 1914 HANDLE *objs = wait_array; 1915 DWORD res; 1916 RpcConnection *cconn = NULL; 1917 RpcConnection_tcp *conn; 1918 1919 if (!objs) 1920 return -1; 1921 1922 do 1923 { 1924 /* an alertable wait isn't strictly necessary, but due to our 1925 * overlapped I/O implementation in Wine we need to free some memory 1926 * by the file user APC being called, even if no completion routine was 1927 * specified at the time of starting the async operation */ 1928 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE); 1929 } while (res == WAIT_IO_COMPLETION); 1930 1931 if (res == WAIT_OBJECT_0) 1932 return 0; 1933 if (res == WAIT_FAILED) 1934 { 1935 ERR("wait failed with error %d\n", GetLastError()); 1936 return -1; 1937 } 1938 1939 b_handle = objs[res - WAIT_OBJECT_0]; 1940 1941 /* find which connection got a RPC */ 1942 EnterCriticalSection(&protseq->cs); 1943 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry) 1944 { 1945 if (b_handle == conn->sock_event) 1946 { 1947 cconn = rpcrt4_spawn_connection(&conn->common); 1948 break; 1949 } 1950 } 1951 LeaveCriticalSection(&protseq->cs); 1952 if (!cconn) 1953 { 1954 ERR("failed to locate connection for handle %p\n", b_handle); 1955 return -1; 1956 } 1957 1958 RPCRT4_new_client(cconn); 1959 return 1; 1960 } 1961 1962 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, 1963 size_t tower_size, 1964 char **networkaddr, 1965 char **endpoint) 1966 { 1967 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size, 1968 networkaddr, EPM_PROTOCOL_TCP, 1969 endpoint); 1970 } 1971 1972 /**** ncacn_http support ****/ 1973 1974 /* 60 seconds is the period native uses */ 1975 #define HTTP_IDLE_TIME 60000 1976 1977 /* reference counted to avoid a race between a cancelled call's connection 1978 * being destroyed and the asynchronous InternetReadFileEx call being 1979 * completed */ 1980 typedef struct _RpcHttpAsyncData 1981 { 1982 LONG refs; 1983 HANDLE completion_event; 1984 WORD async_result; 1985 INTERNET_BUFFERSW inet_buffers; 1986 CRITICAL_SECTION cs; 1987 } RpcHttpAsyncData; 1988 1989 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data) 1990 { 1991 return InterlockedIncrement(&data->refs); 1992 } 1993 1994 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data) 1995 { 1996 ULONG refs = InterlockedDecrement(&data->refs); 1997 if (!refs) 1998 { 1999 TRACE("destroying async data %p\n", data); 2000 CloseHandle(data->completion_event); 2001 HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer); 2002 data->cs.DebugInfo->Spare[0] = 0; 2003 DeleteCriticalSection(&data->cs); 2004 HeapFree(GetProcessHeap(), 0, data); 2005 } 2006 return refs; 2007 } 2008 2009 static void prepare_async_request(RpcHttpAsyncData *async_data) 2010 { 2011 ResetEvent(async_data->completion_event); 2012 RpcHttpAsyncData_AddRef(async_data); 2013 } 2014 2015 static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret, HANDLE cancel_event) 2016 { 2017 HANDLE handles[2] = { async_data->completion_event, cancel_event }; 2018 DWORD res; 2019 2020 if(call_ret) { 2021 RpcHttpAsyncData_Release(async_data); 2022 return RPC_S_OK; 2023 } 2024 2025 if(GetLastError() != ERROR_IO_PENDING) { 2026 RpcHttpAsyncData_Release(async_data); 2027 ERR("Request failed with error %d\n", GetLastError()); 2028 return RPC_S_SERVER_UNAVAILABLE; 2029 } 2030 2031 res = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT); 2032 if(res != WAIT_OBJECT_0) { 2033 TRACE("Cancelled\n"); 2034 return RPC_S_CALL_CANCELLED; 2035 } 2036 2037 if(async_data->async_result) { 2038 ERR("Async request failed with error %d\n", async_data->async_result); 2039 return RPC_S_SERVER_UNAVAILABLE; 2040 } 2041 2042 return RPC_S_OK; 2043 } 2044 2045 struct authinfo 2046 { 2047 DWORD scheme; 2048 CredHandle cred; 2049 CtxtHandle ctx; 2050 TimeStamp exp; 2051 ULONG attr; 2052 ULONG max_token; 2053 char *data; 2054 unsigned int data_len; 2055 BOOL finished; /* finished authenticating */ 2056 }; 2057 2058 typedef struct _RpcConnection_http 2059 { 2060 RpcConnection common; 2061 HINTERNET app_info; 2062 HINTERNET session; 2063 HINTERNET in_request; 2064 HINTERNET out_request; 2065 WCHAR *servername; 2066 HANDLE timer_cancelled; 2067 HANDLE cancel_event; 2068 DWORD last_sent_time; 2069 ULONG bytes_received; 2070 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */ 2071 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */ 2072 UUID connection_uuid; 2073 UUID in_pipe_uuid; 2074 UUID out_pipe_uuid; 2075 RpcHttpAsyncData *async_data; 2076 } RpcConnection_http; 2077 2078 static RpcConnection *rpcrt4_ncacn_http_alloc(void) 2079 { 2080 RpcConnection_http *httpc; 2081 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc)); 2082 if (!httpc) return NULL; 2083 httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData)); 2084 if (!httpc->async_data) 2085 { 2086 HeapFree(GetProcessHeap(), 0, httpc); 2087 return NULL; 2088 } 2089 TRACE("async data = %p\n", httpc->async_data); 2090 httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL); 2091 httpc->async_data->refs = 1; 2092 httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSW); 2093 InitializeCriticalSection(&httpc->async_data->cs); 2094 httpc->async_data->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcHttpAsyncData.cs"); 2095 return &httpc->common; 2096 } 2097 2098 typedef struct _HttpTimerThreadData 2099 { 2100 PVOID timer_param; 2101 DWORD *last_sent_time; 2102 HANDLE timer_cancelled; 2103 } HttpTimerThreadData; 2104 2105 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy) 2106 { 2107 HINTERNET in_request = param; 2108 RpcPktHdr *idle_pkt; 2109 2110 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001, 2111 0, 0); 2112 if (idle_pkt) 2113 { 2114 DWORD bytes_written; 2115 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written); 2116 RPCRT4_FreeHeader(idle_pkt); 2117 } 2118 } 2119 2120 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time) 2121 { 2122 DWORD cur_time = GetTickCount(); 2123 DWORD cached_last_sent_time = *last_sent_time; 2124 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time); 2125 } 2126 2127 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param) 2128 { 2129 HttpTimerThreadData *data_in = param; 2130 HttpTimerThreadData data; 2131 DWORD timeout; 2132 2133 data = *data_in; 2134 HeapFree(GetProcessHeap(), 0, data_in); 2135 2136 for (timeout = HTTP_IDLE_TIME; 2137 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT; 2138 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time)) 2139 { 2140 /* are we too soon after last send? */ 2141 if (GetTickCount() - *data.last_sent_time < HTTP_IDLE_TIME) 2142 continue; 2143 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE); 2144 } 2145 2146 CloseHandle(data.timer_cancelled); 2147 return 0; 2148 } 2149 2150 static VOID WINAPI rpcrt4_http_internet_callback( 2151 HINTERNET hInternet, 2152 DWORD_PTR dwContext, 2153 DWORD dwInternetStatus, 2154 LPVOID lpvStatusInformation, 2155 DWORD dwStatusInformationLength) 2156 { 2157 RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext; 2158 2159 switch (dwInternetStatus) 2160 { 2161 case INTERNET_STATUS_REQUEST_COMPLETE: 2162 TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n"); 2163 if (async_data) 2164 { 2165 INTERNET_ASYNC_RESULT *async_result = lpvStatusInformation; 2166 2167 async_data->async_result = async_result->dwResult ? ERROR_SUCCESS : async_result->dwError; 2168 SetEvent(async_data->completion_event); 2169 RpcHttpAsyncData_Release(async_data); 2170 } 2171 break; 2172 } 2173 } 2174 2175 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor) 2176 { 2177 BOOL ret; 2178 DWORD status_code; 2179 DWORD size; 2180 DWORD index; 2181 WCHAR buf[32]; 2182 WCHAR *status_text = buf; 2183 TRACE("\n"); 2184 2185 index = 0; 2186 size = sizeof(status_code); 2187 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index); 2188 if (!ret) 2189 return GetLastError(); 2190 if (status_code == HTTP_STATUS_OK) 2191 return RPC_S_OK; 2192 index = 0; 2193 size = sizeof(buf); 2194 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index); 2195 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 2196 { 2197 status_text = HeapAlloc(GetProcessHeap(), 0, size); 2198 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index); 2199 } 2200 2201 ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>"); 2202 if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text); 2203 2204 if (status_code == HTTP_STATUS_DENIED) 2205 return ERROR_ACCESS_DENIED; 2206 return RPC_S_SERVER_UNAVAILABLE; 2207 } 2208 2209 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc) 2210 { 2211 static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0}; 2212 LPWSTR proxy = NULL; 2213 LPWSTR user = NULL; 2214 LPWSTR password = NULL; 2215 LPWSTR servername = NULL; 2216 const WCHAR *option; 2217 INTERNET_PORT port; 2218 2219 if (httpc->common.QOS && 2220 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP)) 2221 { 2222 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials; 2223 if (http_cred->TransportCredentials) 2224 { 2225 WCHAR *p; 2226 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials; 2227 ULONG len = cred->DomainLength + 1 + cred->UserLength; 2228 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 2229 if (!user) 2230 return RPC_S_OUT_OF_RESOURCES; 2231 p = user; 2232 if (cred->DomainLength) 2233 { 2234 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR)); 2235 p += cred->DomainLength; 2236 *p = '\\'; 2237 p++; 2238 } 2239 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR)); 2240 p[cred->UserLength] = 0; 2241 2242 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength); 2243 } 2244 } 2245 2246 for (option = httpc->common.NetworkOptions; option; 2247 option = (wcschr(option, ',') ? wcschr(option, ',')+1 : NULL)) 2248 { 2249 static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0}; 2250 static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0}; 2251 2252 if (!_wcsnicmp(option, wszRpcProxy, ARRAY_SIZE(wszRpcProxy)-1)) 2253 { 2254 const WCHAR *value_start = option + ARRAY_SIZE(wszRpcProxy)-1; 2255 const WCHAR *value_end; 2256 const WCHAR *p; 2257 2258 value_end = wcschr(option, ','); 2259 if (!value_end) 2260 value_end = value_start + lstrlenW(value_start); 2261 for (p = value_start; p < value_end; p++) 2262 if (*p == ':') 2263 { 2264 port = wcstol(p+1, NULL, 10); 2265 value_end = p; 2266 break; 2267 } 2268 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start)); 2269 servername = RPCRT4_strndupW(value_start, value_end-value_start); 2270 } 2271 else if (!_wcsnicmp(option, wszHttpProxy, ARRAY_SIZE(wszHttpProxy)-1)) 2272 { 2273 const WCHAR *value_start = option + ARRAY_SIZE(wszHttpProxy)-1; 2274 const WCHAR *value_end; 2275 2276 value_end = wcschr(option, ','); 2277 if (!value_end) 2278 value_end = value_start + lstrlenW(value_start); 2279 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start)); 2280 proxy = RPCRT4_strndupW(value_start, value_end-value_start); 2281 } 2282 else 2283 FIXME("unhandled option %s\n", debugstr_w(option)); 2284 } 2285 2286 httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG, 2287 NULL, NULL, INTERNET_FLAG_ASYNC); 2288 if (!httpc->app_info) 2289 { 2290 HeapFree(GetProcessHeap(), 0, password); 2291 HeapFree(GetProcessHeap(), 0, user); 2292 HeapFree(GetProcessHeap(), 0, proxy); 2293 HeapFree(GetProcessHeap(), 0, servername); 2294 ERR("InternetOpenW failed with error %d\n", GetLastError()); 2295 return RPC_S_SERVER_UNAVAILABLE; 2296 } 2297 InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback); 2298 2299 /* if no RpcProxy option specified, set the HTTP server address to the 2300 * RPC server address */ 2301 if (!servername) 2302 { 2303 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR)); 2304 if (!servername) 2305 { 2306 HeapFree(GetProcessHeap(), 0, password); 2307 HeapFree(GetProcessHeap(), 0, user); 2308 HeapFree(GetProcessHeap(), 0, proxy); 2309 return RPC_S_OUT_OF_RESOURCES; 2310 } 2311 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1); 2312 } 2313 2314 port = (httpc->common.QOS && 2315 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) && 2316 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)) ? 2317 INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT; 2318 2319 httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password, 2320 INTERNET_SERVICE_HTTP, 0, 0); 2321 2322 HeapFree(GetProcessHeap(), 0, password); 2323 HeapFree(GetProcessHeap(), 0, user); 2324 HeapFree(GetProcessHeap(), 0, proxy); 2325 2326 if (!httpc->session) 2327 { 2328 ERR("InternetConnectW failed with error %d\n", GetLastError()); 2329 HeapFree(GetProcessHeap(), 0, servername); 2330 return RPC_S_SERVER_UNAVAILABLE; 2331 } 2332 httpc->servername = servername; 2333 return RPC_S_OK; 2334 } 2335 2336 static int rpcrt4_http_async_read(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event, 2337 void *buffer, unsigned int count) 2338 { 2339 char *buf = buffer; 2340 BOOL ret; 2341 unsigned int bytes_left = count; 2342 RPC_STATUS status = RPC_S_OK; 2343 2344 async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, count); 2345 2346 while (bytes_left) 2347 { 2348 async_data->inet_buffers.dwBufferLength = bytes_left; 2349 prepare_async_request(async_data); 2350 ret = InternetReadFileExW(req, &async_data->inet_buffers, IRF_ASYNC, 0); 2351 status = wait_async_request(async_data, ret, cancel_event); 2352 if (status != RPC_S_OK) 2353 { 2354 if (status == RPC_S_CALL_CANCELLED) 2355 TRACE("call cancelled\n"); 2356 break; 2357 } 2358 2359 if (!async_data->inet_buffers.dwBufferLength) 2360 break; 2361 memcpy(buf, async_data->inet_buffers.lpvBuffer, 2362 async_data->inet_buffers.dwBufferLength); 2363 2364 bytes_left -= async_data->inet_buffers.dwBufferLength; 2365 buf += async_data->inet_buffers.dwBufferLength; 2366 } 2367 2368 HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer); 2369 async_data->inet_buffers.lpvBuffer = NULL; 2370 2371 TRACE("%p %p %u -> %u\n", req, buffer, count, status); 2372 return status == RPC_S_OK ? count : -1; 2373 } 2374 2375 static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event) 2376 { 2377 BYTE buf[20]; 2378 BOOL ret; 2379 RPC_STATUS status; 2380 2381 TRACE("sending echo request to server\n"); 2382 2383 prepare_async_request(async_data); 2384 ret = HttpSendRequestW(req, NULL, 0, NULL, 0); 2385 status = wait_async_request(async_data, ret, cancel_event); 2386 if (status != RPC_S_OK) return status; 2387 2388 status = rpcrt4_http_check_response(req); 2389 if (status != RPC_S_OK) return status; 2390 2391 rpcrt4_http_async_read(req, async_data, cancel_event, buf, sizeof(buf)); 2392 /* FIXME: do something with retrieved data */ 2393 2394 return RPC_S_OK; 2395 } 2396 2397 static RPC_STATUS insert_content_length_header(HINTERNET request, DWORD len) 2398 { 2399 static const WCHAR fmtW[] = 2400 {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','u','\r','\n',0}; 2401 WCHAR header[ARRAY_SIZE(fmtW) + 10]; 2402 2403 swprintf(header, fmtW, len); 2404 if ((HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))) return RPC_S_OK; 2405 return RPC_S_SERVER_UNAVAILABLE; 2406 } 2407 2408 /* prepare the in pipe for use by RPC packets */ 2409 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data, HANDLE cancel_event, 2410 const UUID *connection_uuid, const UUID *in_pipe_uuid, 2411 const UUID *association_uuid, BOOL authorized) 2412 { 2413 BOOL ret; 2414 RPC_STATUS status; 2415 RpcPktHdr *hdr; 2416 INTERNET_BUFFERSW buffers_in; 2417 DWORD bytes_written; 2418 2419 if (!authorized) 2420 { 2421 /* ask wininet to authorize, if necessary */ 2422 status = send_echo_request(in_request, async_data, cancel_event); 2423 if (status != RPC_S_OK) return status; 2424 } 2425 memset(&buffers_in, 0, sizeof(buffers_in)); 2426 buffers_in.dwStructSize = sizeof(buffers_in); 2427 /* FIXME: get this from the registry */ 2428 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */ 2429 status = insert_content_length_header(in_request, buffers_in.dwBufferTotal); 2430 if (status != RPC_S_OK) return status; 2431 2432 prepare_async_request(async_data); 2433 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0); 2434 status = wait_async_request(async_data, ret, cancel_event); 2435 if (status != RPC_S_OK) return status; 2436 2437 TRACE("sending HTTP connect header to server\n"); 2438 hdr = RPCRT4_BuildHttpConnectHeader(FALSE, connection_uuid, in_pipe_uuid, association_uuid); 2439 if (!hdr) return RPC_S_OUT_OF_RESOURCES; 2440 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written); 2441 RPCRT4_FreeHeader(hdr); 2442 if (!ret) 2443 { 2444 ERR("InternetWriteFile failed with error %d\n", GetLastError()); 2445 return RPC_S_SERVER_UNAVAILABLE; 2446 } 2447 2448 return RPC_S_OK; 2449 } 2450 2451 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcHttpAsyncData *async_data, 2452 HANDLE cancel_event, RpcPktHdr *hdr, BYTE **data) 2453 { 2454 unsigned short data_len; 2455 unsigned int size; 2456 2457 if (rpcrt4_http_async_read(request, async_data, cancel_event, hdr, sizeof(hdr->common)) < 0) 2458 return RPC_S_SERVER_UNAVAILABLE; 2459 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http)) 2460 { 2461 ERR("wrong packet type received %d or wrong frag_len %d\n", 2462 hdr->common.ptype, hdr->common.frag_len); 2463 return RPC_S_PROTOCOL_ERROR; 2464 } 2465 2466 size = sizeof(hdr->http) - sizeof(hdr->common); 2467 if (rpcrt4_http_async_read(request, async_data, cancel_event, &hdr->common + 1, size) < 0) 2468 return RPC_S_SERVER_UNAVAILABLE; 2469 2470 data_len = hdr->common.frag_len - sizeof(hdr->http); 2471 if (data_len) 2472 { 2473 *data = HeapAlloc(GetProcessHeap(), 0, data_len); 2474 if (!*data) 2475 return RPC_S_OUT_OF_RESOURCES; 2476 if (rpcrt4_http_async_read(request, async_data, cancel_event, *data, data_len) < 0) 2477 { 2478 HeapFree(GetProcessHeap(), 0, *data); 2479 return RPC_S_SERVER_UNAVAILABLE; 2480 } 2481 } 2482 else 2483 *data = NULL; 2484 2485 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len)) 2486 { 2487 ERR("invalid http packet\n"); 2488 HeapFree(GetProcessHeap(), 0, *data); 2489 return RPC_S_PROTOCOL_ERROR; 2490 } 2491 2492 return RPC_S_OK; 2493 } 2494 2495 /* prepare the out pipe for use by RPC packets */ 2496 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, RpcHttpAsyncData *async_data, 2497 HANDLE cancel_event, const UUID *connection_uuid, 2498 const UUID *out_pipe_uuid, ULONG *flow_control_increment, 2499 BOOL authorized) 2500 { 2501 BOOL ret; 2502 RPC_STATUS status; 2503 RpcPktHdr *hdr; 2504 BYTE *data_from_server; 2505 RpcPktHdr pkt_from_server; 2506 ULONG field1, field3; 2507 BYTE buf[20]; 2508 2509 if (!authorized) 2510 { 2511 /* ask wininet to authorize, if necessary */ 2512 status = send_echo_request(out_request, async_data, cancel_event); 2513 if (status != RPC_S_OK) return status; 2514 } 2515 else 2516 rpcrt4_http_async_read(out_request, async_data, cancel_event, buf, sizeof(buf)); 2517 2518 hdr = RPCRT4_BuildHttpConnectHeader(TRUE, connection_uuid, out_pipe_uuid, NULL); 2519 if (!hdr) return RPC_S_OUT_OF_RESOURCES; 2520 2521 status = insert_content_length_header(out_request, hdr->common.frag_len); 2522 if (status != RPC_S_OK) 2523 { 2524 RPCRT4_FreeHeader(hdr); 2525 return status; 2526 } 2527 2528 TRACE("sending HTTP connect header to server\n"); 2529 prepare_async_request(async_data); 2530 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len); 2531 status = wait_async_request(async_data, ret, cancel_event); 2532 RPCRT4_FreeHeader(hdr); 2533 if (status != RPC_S_OK) return status; 2534 2535 status = rpcrt4_http_check_response(out_request); 2536 if (status != RPC_S_OK) return status; 2537 2538 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event, 2539 &pkt_from_server, &data_from_server); 2540 if (status != RPC_S_OK) return status; 2541 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server, 2542 &field1); 2543 HeapFree(GetProcessHeap(), 0, data_from_server); 2544 if (status != RPC_S_OK) return status; 2545 TRACE("received (%d) from first prepare header\n", field1); 2546 2547 for (;;) 2548 { 2549 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event, 2550 &pkt_from_server, &data_from_server); 2551 if (status != RPC_S_OK) return status; 2552 if (pkt_from_server.http.flags != 0x0001) break; 2553 2554 TRACE("http idle packet, waiting for real packet\n"); 2555 HeapFree(GetProcessHeap(), 0, data_from_server); 2556 if (pkt_from_server.http.num_data_items != 0) 2557 { 2558 ERR("HTTP idle packet should have no data items instead of %d\n", 2559 pkt_from_server.http.num_data_items); 2560 return RPC_S_PROTOCOL_ERROR; 2561 } 2562 } 2563 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server, 2564 &field1, flow_control_increment, 2565 &field3); 2566 HeapFree(GetProcessHeap(), 0, data_from_server); 2567 if (status != RPC_S_OK) return status; 2568 TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3); 2569 2570 return RPC_S_OK; 2571 } 2572 2573 static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64) 2574 { 2575 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 2576 UINT i = 0, x; 2577 2578 while (len > 0) 2579 { 2580 /* first 6 bits, all from bin[0] */ 2581 base64[i++] = enc[(bin[0] & 0xfc) >> 2]; 2582 x = (bin[0] & 3) << 4; 2583 2584 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */ 2585 if (len == 1) 2586 { 2587 base64[i++] = enc[x]; 2588 base64[i++] = '='; 2589 base64[i++] = '='; 2590 break; 2591 } 2592 base64[i++] = enc[x | ((bin[1] & 0xf0) >> 4)]; 2593 x = (bin[1] & 0x0f) << 2; 2594 2595 /* next 6 bits 4 from bin[1] and 2 from bin[2] */ 2596 if (len == 2) 2597 { 2598 base64[i++] = enc[x]; 2599 base64[i++] = '='; 2600 break; 2601 } 2602 base64[i++] = enc[x | ((bin[2] & 0xc0) >> 6)]; 2603 2604 /* last 6 bits, all from bin [2] */ 2605 base64[i++] = enc[bin[2] & 0x3f]; 2606 bin += 3; 2607 len -= 3; 2608 } 2609 base64[i] = 0; 2610 return i; 2611 } 2612 2613 static inline char decode_char( WCHAR c ) 2614 { 2615 if (c >= 'A' && c <= 'Z') return c - 'A'; 2616 if (c >= 'a' && c <= 'z') return c - 'a' + 26; 2617 if (c >= '0' && c <= '9') return c - '0' + 52; 2618 if (c == '+') return 62; 2619 if (c == '/') return 63; 2620 return 64; 2621 } 2622 2623 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf ) 2624 { 2625 unsigned int i = 0; 2626 char c0, c1, c2, c3; 2627 const WCHAR *p = base64; 2628 2629 while (len > 4) 2630 { 2631 if ((c0 = decode_char( p[0] )) > 63) return 0; 2632 if ((c1 = decode_char( p[1] )) > 63) return 0; 2633 if ((c2 = decode_char( p[2] )) > 63) return 0; 2634 if ((c3 = decode_char( p[3] )) > 63) return 0; 2635 2636 if (buf) 2637 { 2638 buf[i + 0] = (c0 << 2) | (c1 >> 4); 2639 buf[i + 1] = (c1 << 4) | (c2 >> 2); 2640 buf[i + 2] = (c2 << 6) | c3; 2641 } 2642 len -= 4; 2643 i += 3; 2644 p += 4; 2645 } 2646 if (p[2] == '=') 2647 { 2648 if ((c0 = decode_char( p[0] )) > 63) return 0; 2649 if ((c1 = decode_char( p[1] )) > 63) return 0; 2650 2651 if (buf) buf[i] = (c0 << 2) | (c1 >> 4); 2652 i++; 2653 } 2654 else if (p[3] == '=') 2655 { 2656 if ((c0 = decode_char( p[0] )) > 63) return 0; 2657 if ((c1 = decode_char( p[1] )) > 63) return 0; 2658 if ((c2 = decode_char( p[2] )) > 63) return 0; 2659 2660 if (buf) 2661 { 2662 buf[i + 0] = (c0 << 2) | (c1 >> 4); 2663 buf[i + 1] = (c1 << 4) | (c2 >> 2); 2664 } 2665 i += 2; 2666 } 2667 else 2668 { 2669 if ((c0 = decode_char( p[0] )) > 63) return 0; 2670 if ((c1 = decode_char( p[1] )) > 63) return 0; 2671 if ((c2 = decode_char( p[2] )) > 63) return 0; 2672 if ((c3 = decode_char( p[3] )) > 63) return 0; 2673 2674 if (buf) 2675 { 2676 buf[i + 0] = (c0 << 2) | (c1 >> 4); 2677 buf[i + 1] = (c1 << 4) | (c2 >> 2); 2678 buf[i + 2] = (c2 << 6) | c3; 2679 } 2680 i += 3; 2681 } 2682 return i; 2683 } 2684 2685 static struct authinfo *alloc_authinfo(void) 2686 { 2687 struct authinfo *ret; 2688 2689 if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret) ))) return NULL; 2690 2691 SecInvalidateHandle(&ret->cred); 2692 SecInvalidateHandle(&ret->ctx); 2693 memset(&ret->exp, 0, sizeof(ret->exp)); 2694 ret->scheme = 0; 2695 ret->attr = 0; 2696 ret->max_token = 0; 2697 ret->data = NULL; 2698 ret->data_len = 0; 2699 ret->finished = FALSE; 2700 return ret; 2701 } 2702 2703 static void destroy_authinfo(struct authinfo *info) 2704 { 2705 if (!info) return; 2706 2707 if (SecIsValidHandle(&info->ctx)) 2708 DeleteSecurityContext(&info->ctx); 2709 if (SecIsValidHandle(&info->cred)) 2710 FreeCredentialsHandle(&info->cred); 2711 2712 HeapFree(GetProcessHeap(), 0, info->data); 2713 HeapFree(GetProcessHeap(), 0, info); 2714 } 2715 2716 static const WCHAR basicW[] = {'B','a','s','i','c',0}; 2717 static const WCHAR ntlmW[] = {'N','T','L','M',0}; 2718 static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t',0}; 2719 static const WCHAR digestW[] = {'D','i','g','e','s','t',0}; 2720 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0}; 2721 2722 static const struct 2723 { 2724 const WCHAR *str; 2725 unsigned int len; 2726 DWORD scheme; 2727 } 2728 auth_schemes[] = 2729 { 2730 { basicW, ARRAY_SIZE(basicW) - 1, RPC_C_HTTP_AUTHN_SCHEME_BASIC }, 2731 { ntlmW, ARRAY_SIZE(ntlmW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NTLM }, 2732 { passportW, ARRAY_SIZE(passportW) - 1, RPC_C_HTTP_AUTHN_SCHEME_PASSPORT }, 2733 { digestW, ARRAY_SIZE(digestW) - 1, RPC_C_HTTP_AUTHN_SCHEME_DIGEST }, 2734 { negotiateW, ARRAY_SIZE(negotiateW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE } 2735 }; 2736 2737 static DWORD auth_scheme_from_header( const WCHAR *header ) 2738 { 2739 unsigned int i; 2740 for (i = 0; i < ARRAY_SIZE(auth_schemes); i++) 2741 { 2742 if (!_wcsnicmp( header, auth_schemes[i].str, auth_schemes[i].len ) && 2743 (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme; 2744 } 2745 return 0; 2746 } 2747 2748 static BOOL get_authvalue(HINTERNET request, DWORD scheme, WCHAR *buffer, DWORD buflen) 2749 { 2750 DWORD len, index = 0; 2751 for (;;) 2752 { 2753 len = buflen; 2754 if (!HttpQueryInfoW(request, HTTP_QUERY_WWW_AUTHENTICATE, buffer, &len, &index)) return FALSE; 2755 if (auth_scheme_from_header(buffer) == scheme) break; 2756 } 2757 return TRUE; 2758 } 2759 2760 static RPC_STATUS do_authorization(HINTERNET request, SEC_WCHAR *servername, 2761 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds, struct authinfo **auth_ptr) 2762 { 2763 struct authinfo *info = *auth_ptr; 2764 SEC_WINNT_AUTH_IDENTITY_W *id = creds->TransportCredentials; 2765 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE; 2766 2767 if ((!info && !(info = alloc_authinfo()))) return RPC_S_SERVER_UNAVAILABLE; 2768 2769 switch (creds->AuthnSchemes[0]) 2770 { 2771 case RPC_C_HTTP_AUTHN_SCHEME_BASIC: 2772 { 2773 int userlen = WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, NULL, 0, NULL, NULL); 2774 int passlen = WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, NULL, 0, NULL, NULL); 2775 2776 info->data_len = userlen + passlen + 1; 2777 if (!(info->data = HeapAlloc(GetProcessHeap(), 0, info->data_len))) 2778 { 2779 status = RPC_S_OUT_OF_MEMORY; 2780 break; 2781 } 2782 WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, info->data, userlen, NULL, NULL); 2783 info->data[userlen] = ':'; 2784 WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, info->data + userlen + 1, passlen, NULL, NULL); 2785 2786 info->scheme = RPC_C_HTTP_AUTHN_SCHEME_BASIC; 2787 info->finished = TRUE; 2788 status = RPC_S_OK; 2789 break; 2790 } 2791 case RPC_C_HTTP_AUTHN_SCHEME_NTLM: 2792 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE: 2793 { 2794 2795 static SEC_WCHAR ntlmW[] = {'N','T','L','M',0}, negotiateW[] = {'N','e','g','o','t','i','a','t','e',0}; 2796 SECURITY_STATUS ret; 2797 SecBufferDesc out_desc, in_desc; 2798 SecBuffer out, in; 2799 ULONG flags = ISC_REQ_CONNECTION|ISC_REQ_USE_DCE_STYLE|ISC_REQ_MUTUAL_AUTH|ISC_REQ_DELEGATE; 2800 SEC_WCHAR *scheme; 2801 int scheme_len; 2802 const WCHAR *p; 2803 WCHAR auth_value[2048]; 2804 DWORD size = sizeof(auth_value); 2805 BOOL first = FALSE; 2806 2807 if (creds->AuthnSchemes[0] == RPC_C_HTTP_AUTHN_SCHEME_NTLM) scheme = ntlmW; 2808 else scheme = negotiateW; 2809 scheme_len = lstrlenW( scheme ); 2810 2811 if (!*auth_ptr) 2812 { 2813 TimeStamp exp; 2814 SecPkgInfoW *pkg_info; 2815 2816 ret = AcquireCredentialsHandleW(NULL, scheme, SECPKG_CRED_OUTBOUND, NULL, id, NULL, NULL, &info->cred, &exp); 2817 if (ret != SEC_E_OK) break; 2818 2819 ret = QuerySecurityPackageInfoW(scheme, &pkg_info); 2820 if (ret != SEC_E_OK) break; 2821 2822 info->max_token = pkg_info->cbMaxToken; 2823 FreeContextBuffer(pkg_info); 2824 first = TRUE; 2825 } 2826 else 2827 { 2828 if (info->finished || !get_authvalue(request, creds->AuthnSchemes[0], auth_value, size)) break; 2829 if (auth_scheme_from_header(auth_value) != info->scheme) 2830 { 2831 ERR("authentication scheme changed\n"); 2832 break; 2833 } 2834 } 2835 in.BufferType = SECBUFFER_TOKEN; 2836 in.cbBuffer = 0; 2837 in.pvBuffer = NULL; 2838 2839 in_desc.ulVersion = 0; 2840 in_desc.cBuffers = 1; 2841 in_desc.pBuffers = ∈ 2842 2843 p = auth_value + scheme_len; 2844 if (!first && *p == ' ') 2845 { 2846 int len = lstrlenW(++p); 2847 in.cbBuffer = decode_base64(p, len, NULL); 2848 if (!(in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer))) break; 2849 decode_base64(p, len, in.pvBuffer); 2850 } 2851 out.BufferType = SECBUFFER_TOKEN; 2852 out.cbBuffer = info->max_token; 2853 if (!(out.pvBuffer = HeapAlloc(GetProcessHeap(), 0, out.cbBuffer))) 2854 { 2855 HeapFree(GetProcessHeap(), 0, in.pvBuffer); 2856 break; 2857 } 2858 out_desc.ulVersion = 0; 2859 out_desc.cBuffers = 1; 2860 out_desc.pBuffers = &out; 2861 2862 ret = InitializeSecurityContextW(first ? &info->cred : NULL, first ? NULL : &info->ctx, 2863 first ? servername : NULL, flags, 0, SECURITY_NETWORK_DREP, 2864 in.pvBuffer ? &in_desc : NULL, 0, &info->ctx, &out_desc, 2865 &info->attr, &info->exp); 2866 HeapFree(GetProcessHeap(), 0, in.pvBuffer); 2867 if (ret == SEC_E_OK) 2868 { 2869 HeapFree(GetProcessHeap(), 0, info->data); 2870 info->data = out.pvBuffer; 2871 info->data_len = out.cbBuffer; 2872 info->finished = TRUE; 2873 TRACE("sending last auth packet\n"); 2874 status = RPC_S_OK; 2875 } 2876 else if (ret == SEC_I_CONTINUE_NEEDED) 2877 { 2878 HeapFree(GetProcessHeap(), 0, info->data); 2879 info->data = out.pvBuffer; 2880 info->data_len = out.cbBuffer; 2881 TRACE("sending next auth packet\n"); 2882 status = RPC_S_OK; 2883 } 2884 else 2885 { 2886 ERR("InitializeSecurityContextW failed with error 0x%08x\n", ret); 2887 HeapFree(GetProcessHeap(), 0, out.pvBuffer); 2888 break; 2889 } 2890 info->scheme = creds->AuthnSchemes[0]; 2891 break; 2892 } 2893 default: 2894 FIXME("scheme %u not supported\n", creds->AuthnSchemes[0]); 2895 break; 2896 } 2897 2898 if (status != RPC_S_OK) 2899 { 2900 destroy_authinfo(info); 2901 *auth_ptr = NULL; 2902 return status; 2903 } 2904 *auth_ptr = info; 2905 return RPC_S_OK; 2906 } 2907 2908 static RPC_STATUS insert_authorization_header(HINTERNET request, ULONG scheme, char *data, int data_len) 2909 { 2910 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '}; 2911 static const WCHAR basicW[] = {'B','a','s','i','c',' '}; 2912 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',' '}; 2913 static const WCHAR ntlmW[] = {'N','T','L','M',' '}; 2914 int scheme_len, auth_len = ARRAY_SIZE(authW), len = ((data_len + 2) * 4) / 3; 2915 const WCHAR *scheme_str; 2916 WCHAR *header, *ptr; 2917 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE; 2918 2919 switch (scheme) 2920 { 2921 case RPC_C_HTTP_AUTHN_SCHEME_BASIC: 2922 scheme_str = basicW; 2923 scheme_len = ARRAY_SIZE(basicW); 2924 break; 2925 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE: 2926 scheme_str = negotiateW; 2927 scheme_len = ARRAY_SIZE(negotiateW); 2928 break; 2929 case RPC_C_HTTP_AUTHN_SCHEME_NTLM: 2930 scheme_str = ntlmW; 2931 scheme_len = ARRAY_SIZE(ntlmW); 2932 break; 2933 default: 2934 ERR("unknown scheme %u\n", scheme); 2935 return RPC_S_SERVER_UNAVAILABLE; 2936 } 2937 if ((header = HeapAlloc(GetProcessHeap(), 0, (auth_len + scheme_len + len + 2) * sizeof(WCHAR)))) 2938 { 2939 memcpy(header, authW, auth_len * sizeof(WCHAR)); 2940 ptr = header + auth_len; 2941 memcpy(ptr, scheme_str, scheme_len * sizeof(WCHAR)); 2942 ptr += scheme_len; 2943 len = encode_base64(data, data_len, ptr); 2944 ptr[len++] = '\r'; 2945 ptr[len++] = '\n'; 2946 ptr[len] = 0; 2947 if (HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE)) 2948 status = RPC_S_OK; 2949 HeapFree(GetProcessHeap(), 0, header); 2950 } 2951 return status; 2952 } 2953 2954 static void drain_content(HINTERNET request, RpcHttpAsyncData *async_data, HANDLE cancel_event) 2955 { 2956 DWORD count, len = 0, size = sizeof(len); 2957 char buf[2048]; 2958 2959 HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &len, &size, NULL); 2960 if (!len) return; 2961 for (;;) 2962 { 2963 count = min(sizeof(buf), len); 2964 if (rpcrt4_http_async_read(request, async_data, cancel_event, buf, count) <= 0) return; 2965 len -= count; 2966 } 2967 } 2968 2969 static RPC_STATUS authorize_request(RpcConnection_http *httpc, HINTERNET request) 2970 { 2971 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':','\r','\n',0}; 2972 struct authinfo *info = NULL; 2973 RPC_STATUS status; 2974 BOOL ret; 2975 2976 for (;;) 2977 { 2978 status = do_authorization(request, httpc->servername, httpc->common.QOS->qos->u.HttpCredentials, &info); 2979 if (status != RPC_S_OK) break; 2980 2981 status = insert_authorization_header(request, info->scheme, info->data, info->data_len); 2982 if (status != RPC_S_OK) break; 2983 2984 prepare_async_request(httpc->async_data); 2985 ret = HttpSendRequestW(request, NULL, 0, NULL, 0); 2986 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event); 2987 if (status != RPC_S_OK || info->finished) break; 2988 2989 status = rpcrt4_http_check_response(request); 2990 if (status != RPC_S_OK && status != ERROR_ACCESS_DENIED) break; 2991 drain_content(request, httpc->async_data, httpc->cancel_event); 2992 } 2993 2994 if (info->scheme != RPC_C_HTTP_AUTHN_SCHEME_BASIC) 2995 HttpAddRequestHeadersW(request, authW, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD); 2996 2997 destroy_authinfo(info); 2998 return status; 2999 } 3000 3001 static BOOL has_credentials(RpcConnection_http *httpc) 3002 { 3003 RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds; 3004 SEC_WINNT_AUTH_IDENTITY_W *id; 3005 3006 if (!httpc->common.QOS || httpc->common.QOS->qos->AdditionalSecurityInfoType != RPC_C_AUTHN_INFO_TYPE_HTTP) 3007 return FALSE; 3008 3009 creds = httpc->common.QOS->qos->u.HttpCredentials; 3010 if (creds->AuthenticationTarget != RPC_C_HTTP_AUTHN_TARGET_SERVER || !creds->NumberOfAuthnSchemes) 3011 return FALSE; 3012 3013 id = creds->TransportCredentials; 3014 if (!id || !id->User || !id->Password) return FALSE; 3015 3016 return TRUE; 3017 } 3018 3019 static BOOL is_secure(RpcConnection_http *httpc) 3020 { 3021 return httpc->common.QOS && 3022 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) && 3023 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL); 3024 } 3025 3026 static RPC_STATUS set_auth_cookie(RpcConnection_http *httpc, const WCHAR *value) 3027 { 3028 static WCHAR httpW[] = {'h','t','t','p',0}; 3029 static WCHAR httpsW[] = {'h','t','t','p','s',0}; 3030 URL_COMPONENTSW uc; 3031 DWORD len; 3032 WCHAR *url; 3033 BOOL ret; 3034 3035 if (!value) return RPC_S_OK; 3036 3037 uc.dwStructSize = sizeof(uc); 3038 uc.lpszScheme = is_secure(httpc) ? httpsW : httpW; 3039 uc.dwSchemeLength = 0; 3040 uc.lpszHostName = httpc->servername; 3041 uc.dwHostNameLength = 0; 3042 uc.nPort = 0; 3043 uc.lpszUserName = NULL; 3044 uc.dwUserNameLength = 0; 3045 uc.lpszPassword = NULL; 3046 uc.dwPasswordLength = 0; 3047 uc.lpszUrlPath = NULL; 3048 uc.dwUrlPathLength = 0; 3049 uc.lpszExtraInfo = NULL; 3050 uc.dwExtraInfoLength = 0; 3051 3052 if (!InternetCreateUrlW(&uc, 0, NULL, &len) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) 3053 return RPC_S_SERVER_UNAVAILABLE; 3054 3055 if (!(url = HeapAlloc(GetProcessHeap(), 0, len))) return RPC_S_OUT_OF_MEMORY; 3056 3057 len = len / sizeof(WCHAR) - 1; 3058 if (!InternetCreateUrlW(&uc, 0, url, &len)) 3059 { 3060 HeapFree(GetProcessHeap(), 0, url); 3061 return RPC_S_SERVER_UNAVAILABLE; 3062 } 3063 3064 ret = InternetSetCookieW(url, NULL, value); 3065 HeapFree(GetProcessHeap(), 0, url); 3066 if (!ret) return RPC_S_SERVER_UNAVAILABLE; 3067 3068 return RPC_S_OK; 3069 } 3070 3071 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection) 3072 { 3073 RpcConnection_http *httpc = (RpcConnection_http *)Connection; 3074 static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0}; 3075 static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0}; 3076 static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0}; 3077 static const WCHAR wszColon[] = {':',0}; 3078 static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0}; 3079 LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL }; 3080 DWORD flags; 3081 WCHAR *url; 3082 RPC_STATUS status; 3083 BOOL secure, credentials; 3084 HttpTimerThreadData *timer_data; 3085 HANDLE thread; 3086 3087 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); 3088 3089 if (Connection->server) 3090 { 3091 ERR("ncacn_http servers not supported yet\n"); 3092 return RPC_S_SERVER_UNAVAILABLE; 3093 } 3094 3095 if (httpc->in_request) 3096 return RPC_S_OK; 3097 3098 httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL); 3099 3100 UuidCreate(&httpc->connection_uuid); 3101 UuidCreate(&httpc->in_pipe_uuid); 3102 UuidCreate(&httpc->out_pipe_uuid); 3103 3104 status = rpcrt4_http_internet_connect(httpc); 3105 if (status != RPC_S_OK) 3106 return status; 3107 3108 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR)); 3109 if (!url) 3110 return RPC_S_OUT_OF_MEMORY; 3111 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix)); 3112 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+ARRAY_SIZE(wszRpcProxyPrefix)-1, 3113 strlen(Connection->NetworkAddr)+1); 3114 lstrcatW(url, wszColon); 3115 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+lstrlenW(url), strlen(Connection->Endpoint)+1); 3116 3117 secure = is_secure(httpc); 3118 credentials = has_credentials(httpc); 3119 3120 flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE | 3121 INTERNET_FLAG_NO_AUTO_REDIRECT; 3122 if (secure) flags |= INTERNET_FLAG_SECURE; 3123 if (credentials) flags |= INTERNET_FLAG_NO_AUTH; 3124 3125 status = set_auth_cookie(httpc, Connection->CookieAuth); 3126 if (status != RPC_S_OK) 3127 { 3128 HeapFree(GetProcessHeap(), 0, url); 3129 return status; 3130 } 3131 httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL, wszAcceptTypes, 3132 flags, (DWORD_PTR)httpc->async_data); 3133 if (!httpc->in_request) 3134 { 3135 ERR("HttpOpenRequestW failed with error %d\n", GetLastError()); 3136 HeapFree(GetProcessHeap(), 0, url); 3137 return RPC_S_SERVER_UNAVAILABLE; 3138 } 3139 3140 if (credentials) 3141 { 3142 status = authorize_request(httpc, httpc->in_request); 3143 if (status != RPC_S_OK) 3144 { 3145 HeapFree(GetProcessHeap(), 0, url); 3146 return status; 3147 } 3148 status = rpcrt4_http_check_response(httpc->in_request); 3149 if (status != RPC_S_OK) 3150 { 3151 HeapFree(GetProcessHeap(), 0, url); 3152 return status; 3153 } 3154 drain_content(httpc->in_request, httpc->async_data, httpc->cancel_event); 3155 } 3156 3157 httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL, wszAcceptTypes, 3158 flags, (DWORD_PTR)httpc->async_data); 3159 HeapFree(GetProcessHeap(), 0, url); 3160 if (!httpc->out_request) 3161 { 3162 ERR("HttpOpenRequestW failed with error %d\n", GetLastError()); 3163 return RPC_S_SERVER_UNAVAILABLE; 3164 } 3165 3166 if (credentials) 3167 { 3168 status = authorize_request(httpc, httpc->out_request); 3169 if (status != RPC_S_OK) 3170 return status; 3171 } 3172 3173 status = rpcrt4_http_prepare_in_pipe(httpc->in_request, httpc->async_data, httpc->cancel_event, 3174 &httpc->connection_uuid, &httpc->in_pipe_uuid, 3175 &Connection->assoc->http_uuid, credentials); 3176 if (status != RPC_S_OK) 3177 return status; 3178 3179 status = rpcrt4_http_prepare_out_pipe(httpc->out_request, httpc->async_data, httpc->cancel_event, 3180 &httpc->connection_uuid, &httpc->out_pipe_uuid, 3181 &httpc->flow_control_increment, credentials); 3182 if (status != RPC_S_OK) 3183 return status; 3184 3185 httpc->flow_control_mark = httpc->flow_control_increment / 2; 3186 httpc->last_sent_time = GetTickCount(); 3187 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL); 3188 3189 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data)); 3190 if (!timer_data) 3191 return ERROR_OUTOFMEMORY; 3192 timer_data->timer_param = httpc->in_request; 3193 timer_data->last_sent_time = &httpc->last_sent_time; 3194 timer_data->timer_cancelled = httpc->timer_cancelled; 3195 /* FIXME: should use CreateTimerQueueTimer when implemented */ 3196 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL); 3197 if (!thread) 3198 { 3199 HeapFree(GetProcessHeap(), 0, timer_data); 3200 return GetLastError(); 3201 } 3202 CloseHandle(thread); 3203 3204 return RPC_S_OK; 3205 } 3206 3207 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn) 3208 { 3209 assert(0); 3210 return RPC_S_SERVER_UNAVAILABLE; 3211 } 3212 3213 static int rpcrt4_ncacn_http_read(RpcConnection *Connection, 3214 void *buffer, unsigned int count) 3215 { 3216 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3217 return rpcrt4_http_async_read(httpc->out_request, httpc->async_data, httpc->cancel_event, buffer, count); 3218 } 3219 3220 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload) 3221 { 3222 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3223 RPC_STATUS status; 3224 DWORD hdr_length; 3225 LONG dwRead; 3226 RpcPktCommonHdr common_hdr; 3227 3228 *Header = NULL; 3229 3230 TRACE("(%p, %p, %p)\n", Connection, Header, Payload); 3231 3232 again: 3233 /* read packet common header */ 3234 dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr)); 3235 if (dwRead != sizeof(common_hdr)) { 3236 WARN("Short read of header, %d bytes\n", dwRead); 3237 status = RPC_S_PROTOCOL_ERROR; 3238 goto fail; 3239 } 3240 if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) || 3241 !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0"))) 3242 { 3243 FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr)); 3244 status = RPC_S_PROTOCOL_ERROR; 3245 goto fail; 3246 } 3247 3248 status = RPCRT4_ValidateCommonHeader(&common_hdr); 3249 if (status != RPC_S_OK) goto fail; 3250 3251 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr); 3252 if (hdr_length == 0) { 3253 WARN("header length == 0\n"); 3254 status = RPC_S_PROTOCOL_ERROR; 3255 goto fail; 3256 } 3257 3258 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length); 3259 if (!*Header) 3260 { 3261 status = RPC_S_OUT_OF_RESOURCES; 3262 goto fail; 3263 } 3264 memcpy(*Header, &common_hdr, sizeof(common_hdr)); 3265 3266 /* read the rest of packet header */ 3267 dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr)); 3268 if (dwRead != hdr_length - sizeof(common_hdr)) { 3269 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length); 3270 status = RPC_S_PROTOCOL_ERROR; 3271 goto fail; 3272 } 3273 3274 if (common_hdr.frag_len - hdr_length) 3275 { 3276 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length); 3277 if (!*Payload) 3278 { 3279 status = RPC_S_OUT_OF_RESOURCES; 3280 goto fail; 3281 } 3282 3283 dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length); 3284 if (dwRead != common_hdr.frag_len - hdr_length) 3285 { 3286 WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length); 3287 status = RPC_S_PROTOCOL_ERROR; 3288 goto fail; 3289 } 3290 } 3291 else 3292 *Payload = NULL; 3293 3294 if ((*Header)->common.ptype == PKT_HTTP) 3295 { 3296 if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length)) 3297 { 3298 ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len); 3299 status = RPC_S_PROTOCOL_ERROR; 3300 goto fail; 3301 } 3302 if ((*Header)->http.flags == 0x0001) 3303 { 3304 TRACE("http idle packet, waiting for real packet\n"); 3305 if ((*Header)->http.num_data_items != 0) 3306 { 3307 ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items); 3308 status = RPC_S_PROTOCOL_ERROR; 3309 goto fail; 3310 } 3311 } 3312 else if ((*Header)->http.flags == 0x0002) 3313 { 3314 ULONG bytes_transmitted; 3315 ULONG flow_control_increment; 3316 UUID pipe_uuid; 3317 status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload, 3318 Connection->server, 3319 &bytes_transmitted, 3320 &flow_control_increment, 3321 &pipe_uuid); 3322 if (status != RPC_S_OK) 3323 goto fail; 3324 TRACE("received http flow control header (0x%x, 0x%x, %s)\n", 3325 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid)); 3326 /* FIXME: do something with parsed data */ 3327 } 3328 else 3329 { 3330 FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags); 3331 status = RPC_S_PROTOCOL_ERROR; 3332 goto fail; 3333 } 3334 RPCRT4_FreeHeader(*Header); 3335 *Header = NULL; 3336 HeapFree(GetProcessHeap(), 0, *Payload); 3337 *Payload = NULL; 3338 goto again; 3339 } 3340 3341 /* success */ 3342 status = RPC_S_OK; 3343 3344 httpc->bytes_received += common_hdr.frag_len; 3345 3346 TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received); 3347 3348 if (httpc->bytes_received > httpc->flow_control_mark) 3349 { 3350 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server, 3351 httpc->bytes_received, 3352 httpc->flow_control_increment, 3353 &httpc->out_pipe_uuid); 3354 if (hdr) 3355 { 3356 DWORD bytes_written; 3357 BOOL ret2; 3358 TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received); 3359 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written); 3360 RPCRT4_FreeHeader(hdr); 3361 if (ret2) 3362 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2; 3363 } 3364 } 3365 3366 fail: 3367 if (status != RPC_S_OK) { 3368 RPCRT4_FreeHeader(*Header); 3369 *Header = NULL; 3370 HeapFree(GetProcessHeap(), 0, *Payload); 3371 *Payload = NULL; 3372 } 3373 return status; 3374 } 3375 3376 static int rpcrt4_ncacn_http_write(RpcConnection *Connection, 3377 const void *buffer, unsigned int count) 3378 { 3379 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3380 DWORD bytes_written; 3381 BOOL ret; 3382 3383 httpc->last_sent_time = ~0U; /* disable idle packet sending */ 3384 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written); 3385 httpc->last_sent_time = GetTickCount(); 3386 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE"); 3387 return ret ? bytes_written : -1; 3388 } 3389 3390 static int rpcrt4_ncacn_http_close(RpcConnection *Connection) 3391 { 3392 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3393 3394 TRACE("\n"); 3395 3396 SetEvent(httpc->timer_cancelled); 3397 if (httpc->in_request) 3398 InternetCloseHandle(httpc->in_request); 3399 httpc->in_request = NULL; 3400 if (httpc->out_request) 3401 InternetCloseHandle(httpc->out_request); 3402 httpc->out_request = NULL; 3403 if (httpc->app_info) 3404 InternetCloseHandle(httpc->app_info); 3405 httpc->app_info = NULL; 3406 if (httpc->session) 3407 InternetCloseHandle(httpc->session); 3408 httpc->session = NULL; 3409 RpcHttpAsyncData_Release(httpc->async_data); 3410 if (httpc->cancel_event) 3411 CloseHandle(httpc->cancel_event); 3412 HeapFree(GetProcessHeap(), 0, httpc->servername); 3413 httpc->servername = NULL; 3414 3415 return 0; 3416 } 3417 3418 static void rpcrt4_ncacn_http_close_read(RpcConnection *conn) 3419 { 3420 rpcrt4_ncacn_http_close(conn); /* FIXME */ 3421 } 3422 3423 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection) 3424 { 3425 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3426 3427 SetEvent(httpc->cancel_event); 3428 } 3429 3430 static RPC_STATUS rpcrt4_ncacn_http_is_server_listening(const char *endpoint) 3431 { 3432 FIXME("\n"); 3433 return RPC_S_ACCESS_DENIED; 3434 } 3435 3436 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection) 3437 { 3438 RpcConnection_http *httpc = (RpcConnection_http *) Connection; 3439 BOOL ret; 3440 RPC_STATUS status; 3441 3442 prepare_async_request(httpc->async_data); 3443 ret = InternetQueryDataAvailable(httpc->out_request, 3444 &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0); 3445 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event); 3446 return status == RPC_S_OK ? 0 : -1; 3447 } 3448 3449 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data, 3450 const char *networkaddr, 3451 const char *endpoint) 3452 { 3453 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr, 3454 EPM_PROTOCOL_HTTP, endpoint); 3455 } 3456 3457 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data, 3458 size_t tower_size, 3459 char **networkaddr, 3460 char **endpoint) 3461 { 3462 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size, 3463 networkaddr, EPM_PROTOCOL_HTTP, 3464 endpoint); 3465 } 3466 3467 static const struct connection_ops conn_protseq_list[] = { 3468 { "ncacn_np", 3469 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB }, 3470 rpcrt4_conn_np_alloc, 3471 rpcrt4_ncacn_np_open, 3472 rpcrt4_ncacn_np_handoff, 3473 rpcrt4_conn_np_read, 3474 rpcrt4_conn_np_write, 3475 rpcrt4_conn_np_close, 3476 rpcrt4_conn_np_close_read, 3477 rpcrt4_conn_np_cancel_call, 3478 rpcrt4_ncacn_np_is_server_listening, 3479 rpcrt4_conn_np_wait_for_incoming_data, 3480 rpcrt4_ncacn_np_get_top_of_tower, 3481 rpcrt4_ncacn_np_parse_top_of_tower, 3482 NULL, 3483 RPCRT4_default_is_authorized, 3484 RPCRT4_default_authorize, 3485 RPCRT4_default_secure_packet, 3486 rpcrt4_conn_np_impersonate_client, 3487 rpcrt4_conn_np_revert_to_self, 3488 RPCRT4_default_inquire_auth_client, 3489 }, 3490 { "ncalrpc", 3491 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE }, 3492 rpcrt4_conn_np_alloc, 3493 rpcrt4_ncalrpc_open, 3494 rpcrt4_ncalrpc_handoff, 3495 rpcrt4_conn_np_read, 3496 rpcrt4_conn_np_write, 3497 rpcrt4_conn_np_close, 3498 rpcrt4_conn_np_close_read, 3499 rpcrt4_conn_np_cancel_call, 3500 rpcrt4_ncalrpc_np_is_server_listening, 3501 rpcrt4_conn_np_wait_for_incoming_data, 3502 rpcrt4_ncalrpc_get_top_of_tower, 3503 rpcrt4_ncalrpc_parse_top_of_tower, 3504 NULL, 3505 rpcrt4_ncalrpc_is_authorized, 3506 rpcrt4_ncalrpc_authorize, 3507 rpcrt4_ncalrpc_secure_packet, 3508 rpcrt4_conn_np_impersonate_client, 3509 rpcrt4_conn_np_revert_to_self, 3510 rpcrt4_ncalrpc_inquire_auth_client, 3511 }, 3512 { "ncacn_ip_tcp", 3513 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP }, 3514 rpcrt4_conn_tcp_alloc, 3515 rpcrt4_ncacn_ip_tcp_open, 3516 rpcrt4_conn_tcp_handoff, 3517 rpcrt4_conn_tcp_read, 3518 rpcrt4_conn_tcp_write, 3519 rpcrt4_conn_tcp_close, 3520 rpcrt4_conn_tcp_close_read, 3521 rpcrt4_conn_tcp_cancel_call, 3522 rpcrt4_conn_tcp_is_server_listening, 3523 rpcrt4_conn_tcp_wait_for_incoming_data, 3524 rpcrt4_ncacn_ip_tcp_get_top_of_tower, 3525 rpcrt4_ncacn_ip_tcp_parse_top_of_tower, 3526 NULL, 3527 RPCRT4_default_is_authorized, 3528 RPCRT4_default_authorize, 3529 RPCRT4_default_secure_packet, 3530 RPCRT4_default_impersonate_client, 3531 RPCRT4_default_revert_to_self, 3532 RPCRT4_default_inquire_auth_client, 3533 }, 3534 { "ncacn_http", 3535 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP }, 3536 rpcrt4_ncacn_http_alloc, 3537 rpcrt4_ncacn_http_open, 3538 rpcrt4_ncacn_http_handoff, 3539 rpcrt4_ncacn_http_read, 3540 rpcrt4_ncacn_http_write, 3541 rpcrt4_ncacn_http_close, 3542 rpcrt4_ncacn_http_close_read, 3543 rpcrt4_ncacn_http_cancel_call, 3544 rpcrt4_ncacn_http_is_server_listening, 3545 rpcrt4_ncacn_http_wait_for_incoming_data, 3546 rpcrt4_ncacn_http_get_top_of_tower, 3547 rpcrt4_ncacn_http_parse_top_of_tower, 3548 rpcrt4_ncacn_http_receive_fragment, 3549 RPCRT4_default_is_authorized, 3550 RPCRT4_default_authorize, 3551 RPCRT4_default_secure_packet, 3552 RPCRT4_default_impersonate_client, 3553 RPCRT4_default_revert_to_self, 3554 RPCRT4_default_inquire_auth_client, 3555 }, 3556 }; 3557 3558 3559 static const struct protseq_ops protseq_list[] = 3560 { 3561 { 3562 "ncacn_np", 3563 rpcrt4_protseq_np_alloc, 3564 rpcrt4_protseq_np_signal_state_changed, 3565 rpcrt4_protseq_np_get_wait_array, 3566 rpcrt4_protseq_np_free_wait_array, 3567 rpcrt4_protseq_np_wait_for_new_connection, 3568 rpcrt4_protseq_ncacn_np_open_endpoint, 3569 }, 3570 { 3571 "ncalrpc", 3572 rpcrt4_protseq_np_alloc, 3573 rpcrt4_protseq_np_signal_state_changed, 3574 rpcrt4_protseq_np_get_wait_array, 3575 rpcrt4_protseq_np_free_wait_array, 3576 rpcrt4_protseq_np_wait_for_new_connection, 3577 rpcrt4_protseq_ncalrpc_open_endpoint, 3578 }, 3579 { 3580 "ncacn_ip_tcp", 3581 rpcrt4_protseq_sock_alloc, 3582 rpcrt4_protseq_sock_signal_state_changed, 3583 rpcrt4_protseq_sock_get_wait_array, 3584 rpcrt4_protseq_sock_free_wait_array, 3585 rpcrt4_protseq_sock_wait_for_new_connection, 3586 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint, 3587 }, 3588 }; 3589 3590 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq) 3591 { 3592 unsigned int i; 3593 for(i = 0; i < ARRAY_SIZE(protseq_list); i++) 3594 if (!strcmp(protseq_list[i].name, protseq)) 3595 return &protseq_list[i]; 3596 return NULL; 3597 } 3598 3599 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq) 3600 { 3601 unsigned int i; 3602 for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++) 3603 if (!strcmp(conn_protseq_list[i].name, protseq)) 3604 return &conn_protseq_list[i]; 3605 return NULL; 3606 } 3607 3608 /**** interface to rest of code ****/ 3609 3610 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection) 3611 { 3612 TRACE("(Connection == ^%p)\n", Connection); 3613 3614 assert(!Connection->server); 3615 return Connection->ops->open_connection_client(Connection); 3616 } 3617 3618 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) 3619 { 3620 TRACE("(Connection == ^%p)\n", Connection); 3621 if (SecIsValidHandle(&Connection->ctx)) 3622 { 3623 DeleteSecurityContext(&Connection->ctx); 3624 SecInvalidateHandle(&Connection->ctx); 3625 } 3626 rpcrt4_conn_close(Connection); 3627 return RPC_S_OK; 3628 } 3629 3630 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, 3631 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, 3632 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth) 3633 { 3634 static LONG next_id; 3635 const struct connection_ops *ops; 3636 RpcConnection* NewConnection; 3637 3638 ops = rpcrt4_get_conn_protseq_ops(Protseq); 3639 if (!ops) 3640 { 3641 FIXME("not supported for protseq %s\n", Protseq); 3642 return RPC_S_PROTSEQ_NOT_SUPPORTED; 3643 } 3644 3645 NewConnection = ops->alloc(); 3646 NewConnection->ref = 1; 3647 NewConnection->server = server; 3648 NewConnection->ops = ops; 3649 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); 3650 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); 3651 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions); 3652 NewConnection->CookieAuth = RPCRT4_strdupW(CookieAuth); 3653 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; 3654 NewConnection->NextCallId = 1; 3655 3656 SecInvalidateHandle(&NewConnection->ctx); 3657 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo); 3658 NewConnection->AuthInfo = AuthInfo; 3659 NewConnection->auth_context_id = InterlockedIncrement( &next_id ); 3660 if (QOS) RpcQualityOfService_AddRef(QOS); 3661 NewConnection->QOS = QOS; 3662 3663 list_init(&NewConnection->conn_pool_entry); 3664 list_init(&NewConnection->protseq_entry); 3665 3666 TRACE("connection: %p\n", NewConnection); 3667 *Connection = NewConnection; 3668 3669 return RPC_S_OK; 3670 } 3671 3672 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection) 3673 { 3674 RpcConnection *connection; 3675 RPC_STATUS err; 3676 3677 err = RPCRT4_CreateConnection(&connection, old_connection->server, rpcrt4_conn_get_name(old_connection), 3678 old_connection->NetworkAddr, old_connection->Endpoint, NULL, 3679 old_connection->AuthInfo, old_connection->QOS, old_connection->CookieAuth); 3680 if (err != RPC_S_OK) 3681 return NULL; 3682 3683 rpcrt4_conn_handoff(old_connection, connection); 3684 if (old_connection->protseq) 3685 { 3686 EnterCriticalSection(&old_connection->protseq->cs); 3687 connection->protseq = old_connection->protseq; 3688 list_add_tail(&old_connection->protseq->connections, &connection->protseq_entry); 3689 LeaveCriticalSection(&old_connection->protseq->cs); 3690 } 3691 return connection; 3692 } 3693 3694 void rpcrt4_conn_release_and_wait(RpcConnection *connection) 3695 { 3696 HANDLE event = NULL; 3697 3698 if (connection->ref > 1) 3699 event = connection->wait_release = CreateEventW(NULL, TRUE, FALSE, NULL); 3700 3701 RPCRT4_ReleaseConnection(connection); 3702 3703 if(event) 3704 { 3705 WaitForSingleObject(event, INFINITE); 3706 CloseHandle(event); 3707 } 3708 } 3709 3710 RpcConnection *RPCRT4_GrabConnection(RpcConnection *connection) 3711 { 3712 LONG ref = InterlockedIncrement(&connection->ref); 3713 TRACE("%p ref=%u\n", connection, ref); 3714 return connection; 3715 } 3716 3717 void RPCRT4_ReleaseConnection(RpcConnection *connection) 3718 { 3719 LONG ref; 3720 3721 /* protseq stores a list of active connections, but does not own references to them. 3722 * It may need to grab a connection from the list, which could lead to a race if 3723 * connection is being released, but not yet removed from the list. We handle that 3724 * by synchronizing on CS here. */ 3725 if (connection->protseq) 3726 { 3727 EnterCriticalSection(&connection->protseq->cs); 3728 ref = InterlockedDecrement(&connection->ref); 3729 if (!ref) 3730 list_remove(&connection->protseq_entry); 3731 LeaveCriticalSection(&connection->protseq->cs); 3732 } 3733 else 3734 { 3735 ref = InterlockedDecrement(&connection->ref); 3736 } 3737 3738 TRACE("%p ref=%u\n", connection, ref); 3739 3740 if (!ref) 3741 { 3742 RPCRT4_CloseConnection(connection); 3743 RPCRT4_strfree(connection->Endpoint); 3744 RPCRT4_strfree(connection->NetworkAddr); 3745 HeapFree(GetProcessHeap(), 0, connection->NetworkOptions); 3746 HeapFree(GetProcessHeap(), 0, connection->CookieAuth); 3747 if (connection->AuthInfo) RpcAuthInfo_Release(connection->AuthInfo); 3748 if (connection->QOS) RpcQualityOfService_Release(connection->QOS); 3749 3750 /* server-only */ 3751 if (connection->server_binding) RPCRT4_ReleaseBinding(connection->server_binding); 3752 else if (connection->assoc) RpcAssoc_ConnectionReleased(connection->assoc); 3753 3754 if (connection->wait_release) SetEvent(connection->wait_release); 3755 3756 HeapFree(GetProcessHeap(), 0, connection); 3757 } 3758 } 3759 3760 RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint) 3761 { 3762 const struct connection_ops *ops; 3763 3764 ops = rpcrt4_get_conn_protseq_ops(protseq); 3765 if (!ops) 3766 { 3767 FIXME("not supported for protseq %s\n", protseq); 3768 return RPC_S_INVALID_BINDING; 3769 } 3770 3771 return ops->is_server_listening(endpoint); 3772 } 3773 3774 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, 3775 size_t *tower_size, 3776 const char *protseq, 3777 const char *networkaddr, 3778 const char *endpoint) 3779 { 3780 twr_empty_floor_t *protocol_floor; 3781 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq); 3782 3783 *tower_size = 0; 3784 3785 if (!protseq_ops) 3786 return RPC_S_INVALID_RPC_PROTSEQ; 3787 3788 if (!tower_data) 3789 { 3790 *tower_size = sizeof(*protocol_floor); 3791 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint); 3792 return RPC_S_OK; 3793 } 3794 3795 protocol_floor = (twr_empty_floor_t *)tower_data; 3796 protocol_floor->count_lhs = sizeof(protocol_floor->protid); 3797 protocol_floor->protid = protseq_ops->epm_protocols[0]; 3798 protocol_floor->count_rhs = 0; 3799 3800 tower_data += sizeof(*protocol_floor); 3801 3802 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint); 3803 if (!*tower_size) 3804 return EPT_S_NOT_REGISTERED; 3805 3806 *tower_size += sizeof(*protocol_floor); 3807 3808 return RPC_S_OK; 3809 } 3810 3811 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, 3812 size_t tower_size, 3813 char **protseq, 3814 char **networkaddr, 3815 char **endpoint) 3816 { 3817 const twr_empty_floor_t *protocol_floor; 3818 const twr_empty_floor_t *floor4; 3819 const struct connection_ops *protseq_ops = NULL; 3820 RPC_STATUS status; 3821 unsigned int i; 3822 3823 if (tower_size < sizeof(*protocol_floor)) 3824 return EPT_S_NOT_REGISTERED; 3825 3826 protocol_floor = (const twr_empty_floor_t *)tower_data; 3827 tower_data += sizeof(*protocol_floor); 3828 tower_size -= sizeof(*protocol_floor); 3829 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) || 3830 (protocol_floor->count_rhs > tower_size)) 3831 return EPT_S_NOT_REGISTERED; 3832 tower_data += protocol_floor->count_rhs; 3833 tower_size -= protocol_floor->count_rhs; 3834 3835 floor4 = (const twr_empty_floor_t *)tower_data; 3836 if ((tower_size < sizeof(*floor4)) || 3837 (floor4->count_lhs != sizeof(floor4->protid))) 3838 return EPT_S_NOT_REGISTERED; 3839 3840 for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++) 3841 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) && 3842 (floor4->protid == conn_protseq_list[i].epm_protocols[1])) 3843 { 3844 protseq_ops = &conn_protseq_list[i]; 3845 break; 3846 } 3847 3848 if (!protseq_ops) 3849 return EPT_S_NOT_REGISTERED; 3850 3851 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint); 3852 3853 if ((status == RPC_S_OK) && protseq) 3854 { 3855 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1); 3856 strcpy(*protseq, protseq_ops->name); 3857 } 3858 3859 return status; 3860 } 3861 3862 /*********************************************************************** 3863 * RpcNetworkIsProtseqValidW (RPCRT4.@) 3864 * 3865 * Checks if the given protocol sequence is known by the RPC system. 3866 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED. 3867 * 3868 */ 3869 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq) 3870 { 3871 char ps[0x10]; 3872 3873 WideCharToMultiByte(CP_ACP, 0, protseq, -1, 3874 ps, sizeof ps, NULL, NULL); 3875 if (rpcrt4_get_conn_protseq_ops(ps)) 3876 return RPC_S_OK; 3877 3878 FIXME("Unknown protseq %s\n", debugstr_w(protseq)); 3879 3880 return RPC_S_INVALID_RPC_PROTSEQ; 3881 } 3882 3883 /*********************************************************************** 3884 * RpcNetworkIsProtseqValidA (RPCRT4.@) 3885 */ 3886 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq) 3887 { 3888 UNICODE_STRING protseqW; 3889 3890 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq)) 3891 { 3892 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer); 3893 RtlFreeUnicodeString(&protseqW); 3894 return ret; 3895 } 3896 return RPC_S_OUT_OF_MEMORY; 3897 } 3898 3899 /*********************************************************************** 3900 * RpcProtseqVectorFreeA (RPCRT4.@) 3901 */ 3902 RPC_STATUS WINAPI RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA **protseqs) 3903 { 3904 TRACE("(%p)\n", protseqs); 3905 3906 if (*protseqs) 3907 { 3908 unsigned int i; 3909 for (i = 0; i < (*protseqs)->Count; i++) 3910 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]); 3911 HeapFree(GetProcessHeap(), 0, *protseqs); 3912 *protseqs = NULL; 3913 } 3914 return RPC_S_OK; 3915 } 3916 3917 /*********************************************************************** 3918 * RpcProtseqVectorFreeW (RPCRT4.@) 3919 */ 3920 RPC_STATUS WINAPI RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW **protseqs) 3921 { 3922 TRACE("(%p)\n", protseqs); 3923 3924 if (*protseqs) 3925 { 3926 unsigned int i; 3927 for (i = 0; i < (*protseqs)->Count; i++) 3928 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]); 3929 HeapFree(GetProcessHeap(), 0, *protseqs); 3930 *protseqs = NULL; 3931 } 3932 return RPC_S_OK; 3933 } 3934 3935 /*********************************************************************** 3936 * RpcNetworkInqProtseqsW (RPCRT4.@) 3937 */ 3938 RPC_STATUS WINAPI RpcNetworkInqProtseqsW( RPC_PROTSEQ_VECTORW** protseqs ) 3939 { 3940 RPC_PROTSEQ_VECTORW *pvector; 3941 unsigned int i; 3942 RPC_STATUS status = RPC_S_OUT_OF_MEMORY; 3943 3944 TRACE("(%p)\n", protseqs); 3945 3946 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned short*)*ARRAY_SIZE(protseq_list))); 3947 if (!*protseqs) 3948 goto end; 3949 pvector = *protseqs; 3950 pvector->Count = 0; 3951 for (i = 0; i < ARRAY_SIZE(protseq_list); i++) 3952 { 3953 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, (strlen(protseq_list[i].name)+1)*sizeof(unsigned short)); 3954 if (pvector->Protseq[i] == NULL) 3955 goto end; 3956 MultiByteToWideChar(CP_ACP, 0, (CHAR*)protseq_list[i].name, -1, 3957 (WCHAR*)pvector->Protseq[i], strlen(protseq_list[i].name) + 1); 3958 pvector->Count++; 3959 } 3960 status = RPC_S_OK; 3961 3962 end: 3963 if (status != RPC_S_OK) 3964 RpcProtseqVectorFreeW(protseqs); 3965 return status; 3966 } 3967 3968 /*********************************************************************** 3969 * RpcNetworkInqProtseqsA (RPCRT4.@) 3970 */ 3971 RPC_STATUS WINAPI RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** protseqs) 3972 { 3973 RPC_PROTSEQ_VECTORA *pvector; 3974 unsigned int i; 3975 RPC_STATUS status = RPC_S_OUT_OF_MEMORY; 3976 3977 TRACE("(%p)\n", protseqs); 3978 3979 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned char*)*ARRAY_SIZE(protseq_list))); 3980 if (!*protseqs) 3981 goto end; 3982 pvector = *protseqs; 3983 pvector->Count = 0; 3984 for (i = 0; i < ARRAY_SIZE(protseq_list); i++) 3985 { 3986 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_list[i].name)+1); 3987 if (pvector->Protseq[i] == NULL) 3988 goto end; 3989 strcpy((char*)pvector->Protseq[i], protseq_list[i].name); 3990 pvector->Count++; 3991 } 3992 status = RPC_S_OK; 3993 3994 end: 3995 if (status != RPC_S_OK) 3996 RpcProtseqVectorFreeA(protseqs); 3997 return status; 3998 } 3999