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