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