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