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