user32/listbox: Resize the entire item array at once in SetCount.
[wine.git] / dlls / rpcrt4 / rpc_transport.c
blobb98bf9e0ae15f8a33f9dce55bf83a450a710964d
1 /*
2 * RPC transport layer
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
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.
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.
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
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "ws2tcpip.h"
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <assert.h>
35 #include "windef.h"
36 #include "winbase.h"
37 #include "winnls.h"
38 #include "winerror.h"
39 #include "wininet.h"
40 #include "winternl.h"
41 #include "winioctl.h"
42 #include "wine/unicode.h"
44 #include "rpc.h"
45 #include "rpcndr.h"
47 #include "wine/debug.h"
49 #include "rpc_binding.h"
50 #include "rpc_assoc.h"
51 #include "rpc_message.h"
52 #include "rpc_server.h"
53 #include "epm_towers.h"
55 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
57 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
59 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection);
61 /**** ncacn_np support ****/
63 typedef struct _RpcConnection_np
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;
74 static RpcConnection *rpcrt4_conn_np_alloc(void)
76 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_np));
77 return &npc->common;
80 static HANDLE get_np_event(RpcConnection_np *connection)
82 HANDLE event = InterlockedExchangePointer(&connection->event_cache, NULL);
83 return event ? event : CreateEventW(NULL, TRUE, FALSE, NULL);
86 static void release_np_event(RpcConnection_np *connection, HANDLE event)
88 event = InterlockedExchangePointer(&connection->event_cache, event);
89 if (event)
90 CloseHandle(event);
93 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *conn)
95 RpcConnection_np *connection = (RpcConnection_np *) conn;
97 TRACE("listening on %s\n", connection->listen_pipe);
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)
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;
112 return RPC_S_OK;
115 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
117 RpcConnection_np *npc = (RpcConnection_np *) Connection;
118 HANDLE pipe;
119 DWORD err, dwMode;
121 TRACE("connecting to %s\n", pname);
123 while (TRUE) {
124 DWORD dwFlags = 0;
125 if (Connection->QOS)
127 dwFlags = SECURITY_SQOS_PRESENT;
128 switch (Connection->QOS->qos->ImpersonationType)
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;
146 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
147 dwFlags |= SECURITY_CONTEXT_TRACKING;
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;
158 TRACE("connection failed, error=%x\n", err);
159 return RPC_S_SERVER_TOO_BUSY;
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;
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;
174 return RPC_S_OK;
177 static char *ncalrpc_pipe_name(const char *endpoint)
179 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
180 char *pipe_name;
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;
189 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
191 RpcConnection_np *npc = (RpcConnection_np *) Connection;
192 RPC_STATUS r;
193 LPSTR pname;
195 /* already connected? */
196 if (npc->pipe)
197 return RPC_S_OK;
199 pname = ncalrpc_pipe_name(Connection->Endpoint);
200 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
201 I_RpcFree(pname);
203 return r;
206 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
208 RPC_STATUS r;
209 RpcConnection *Connection;
210 char generated_endpoint[22];
212 if (!endpoint)
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;
222 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
223 endpoint, NULL, NULL, NULL, NULL);
224 if (r != RPC_S_OK)
225 return r;
227 ((RpcConnection_np*)Connection)->listen_pipe = ncalrpc_pipe_name(Connection->Endpoint);
228 r = rpcrt4_conn_create_pipe(Connection);
230 EnterCriticalSection(&protseq->cs);
231 list_add_head(&protseq->listeners, &Connection->protseq_entry);
232 Connection->protseq = protseq;
233 LeaveCriticalSection(&protseq->cs);
235 return r;
238 static char *ncacn_pipe_name(const char *endpoint)
240 static const char prefix[] = "\\\\.";
241 char *pipe_name;
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;
249 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
251 RpcConnection_np *npc = (RpcConnection_np *) Connection;
252 RPC_STATUS r;
253 LPSTR pname;
255 /* already connected? */
256 if (npc->pipe)
257 return RPC_S_OK;
259 pname = ncacn_pipe_name(Connection->Endpoint);
260 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
261 I_RpcFree(pname);
263 return r;
266 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
268 RPC_STATUS r;
269 RpcConnection *Connection;
270 char generated_endpoint[26];
272 if (!endpoint)
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;
282 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
283 endpoint, NULL, NULL, NULL, NULL);
284 if (r != RPC_S_OK)
285 return r;
287 ((RpcConnection_np*)Connection)->listen_pipe = ncacn_pipe_name(Connection->Endpoint);
288 r = rpcrt4_conn_create_pipe(Connection);
290 EnterCriticalSection(&protseq->cs);
291 list_add_head(&protseq->listeners, &Connection->protseq_entry);
292 Connection->protseq = protseq;
293 LeaveCriticalSection(&protseq->cs);
295 return r;
298 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
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 */
303 new_npc->pipe = old_npc->pipe;
304 old_npc->pipe = 0;
305 assert(!old_npc->listen_event);
308 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
310 DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
311 RPC_STATUS status;
313 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
314 status = rpcrt4_conn_create_pipe(old_conn);
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))
321 ERR("Failed to retrieve the computer name, error %u\n", GetLastError());
322 return RPC_S_OUT_OF_RESOURCES;
325 return status;
328 static RPC_STATUS is_pipe_listening(const char *pipe_name)
330 return WaitNamedPipeA(pipe_name, 1) ? RPC_S_OK : RPC_S_NOT_LISTENING;
333 static RPC_STATUS rpcrt4_ncacn_np_is_server_listening(const char *endpoint)
335 char *pipe_name;
336 RPC_STATUS status;
338 pipe_name = ncacn_pipe_name(endpoint);
339 status = is_pipe_listening(pipe_name);
340 I_RpcFree(pipe_name);
341 return status;
344 static RPC_STATUS rpcrt4_ncalrpc_np_is_server_listening(const char *endpoint)
346 char *pipe_name;
347 RPC_STATUS status;
349 pipe_name = ncalrpc_pipe_name(endpoint);
350 status = is_pipe_listening(pipe_name);
351 I_RpcFree(pipe_name);
352 return status;
355 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
357 DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
358 RPC_STATUS status;
360 TRACE("%s\n", old_conn->Endpoint);
362 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
363 status = rpcrt4_conn_create_pipe(old_conn);
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))
369 ERR("Failed to retrieve the computer name, error %u\n", GetLastError());
370 return RPC_S_OUT_OF_RESOURCES;
373 return status;
376 static int rpcrt4_conn_np_read(RpcConnection *conn, void *buffer, unsigned int count)
378 RpcConnection_np *connection = (RpcConnection_np *) conn;
379 HANDLE event;
380 NTSTATUS status;
382 event = get_np_event(connection);
383 if (!event)
384 return -1;
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)
392 /* check read_closed again before waiting to avoid a race */
393 if (connection->read_closed)
395 IO_STATUS_BLOCK io_status;
396 NtCancelIoFileEx(connection->pipe, &connection->io_status, &io_status);
398 WaitForSingleObject(event, INFINITE);
399 status = connection->io_status.Status;
401 release_np_event(connection, event);
402 return status && status != STATUS_BUFFER_OVERFLOW ? -1 : connection->io_status.Information;
405 static int rpcrt4_conn_np_write(RpcConnection *conn, const void *buffer, unsigned int count)
407 RpcConnection_np *connection = (RpcConnection_np *) conn;
408 IO_STATUS_BLOCK io_status;
409 HANDLE event;
410 NTSTATUS status;
412 event = get_np_event(connection);
413 if (!event)
414 return -1;
416 status = NtWriteFile(connection->pipe, event, NULL, NULL, &io_status, buffer, count, NULL, NULL);
417 if (status == STATUS_PENDING)
419 WaitForSingleObject(event, INFINITE);
420 status = io_status.Status;
422 release_np_event(connection, event);
423 if (status)
424 return -1;
426 assert(io_status.Information == count);
427 return count;
430 static int rpcrt4_conn_np_close(RpcConnection *conn)
432 RpcConnection_np *connection = (RpcConnection_np *) conn;
433 if (connection->pipe)
435 FlushFileBuffers(connection->pipe);
436 CloseHandle(connection->pipe);
437 connection->pipe = 0;
439 if (connection->listen_event)
441 CloseHandle(connection->listen_event);
442 connection->listen_event = 0;
444 if (connection->event_cache)
446 CloseHandle(connection->event_cache);
447 connection->event_cache = 0;
449 return 0;
452 static void rpcrt4_conn_np_close_read(RpcConnection *conn)
454 RpcConnection_np *connection = (RpcConnection_np*)conn;
455 IO_STATUS_BLOCK io_status;
457 connection->read_closed = TRUE;
458 NtCancelIoFileEx(connection->pipe, &connection->io_status, &io_status);
461 static void rpcrt4_conn_np_cancel_call(RpcConnection *conn)
463 RpcConnection_np *connection = (RpcConnection_np *)conn;
464 CancelIoEx(connection->pipe, NULL);
467 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *Connection)
469 /* FIXME: implement when named pipe writes use overlapped I/O */
470 return -1;
473 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
474 const char *networkaddr,
475 const char *endpoint)
477 twr_empty_floor_t *smb_floor;
478 twr_empty_floor_t *nb_floor;
479 size_t size;
480 size_t networkaddr_size;
481 size_t endpoint_size;
483 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
485 networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
486 endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
487 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
489 if (!tower_data)
490 return size;
492 smb_floor = (twr_empty_floor_t *)tower_data;
494 tower_data += sizeof(*smb_floor);
496 smb_floor->count_lhs = sizeof(smb_floor->protid);
497 smb_floor->protid = EPM_PROTOCOL_SMB;
498 smb_floor->count_rhs = endpoint_size;
500 if (endpoint)
501 memcpy(tower_data, endpoint, endpoint_size);
502 else
503 tower_data[0] = 0;
504 tower_data += endpoint_size;
506 nb_floor = (twr_empty_floor_t *)tower_data;
508 tower_data += sizeof(*nb_floor);
510 nb_floor->count_lhs = sizeof(nb_floor->protid);
511 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
512 nb_floor->count_rhs = networkaddr_size;
514 if (networkaddr)
515 memcpy(tower_data, networkaddr, networkaddr_size);
516 else
517 tower_data[0] = 0;
519 return size;
522 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
523 size_t tower_size,
524 char **networkaddr,
525 char **endpoint)
527 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
528 const twr_empty_floor_t *nb_floor;
530 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
532 if (tower_size < sizeof(*smb_floor))
533 return EPT_S_NOT_REGISTERED;
535 tower_data += sizeof(*smb_floor);
536 tower_size -= sizeof(*smb_floor);
538 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
539 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
540 (smb_floor->count_rhs > tower_size) ||
541 (tower_data[smb_floor->count_rhs - 1] != '\0'))
542 return EPT_S_NOT_REGISTERED;
544 if (endpoint)
546 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
547 if (!*endpoint)
548 return RPC_S_OUT_OF_RESOURCES;
549 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
551 tower_data += smb_floor->count_rhs;
552 tower_size -= smb_floor->count_rhs;
554 if (tower_size < sizeof(*nb_floor))
555 return EPT_S_NOT_REGISTERED;
557 nb_floor = (const twr_empty_floor_t *)tower_data;
559 tower_data += sizeof(*nb_floor);
560 tower_size -= sizeof(*nb_floor);
562 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
563 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
564 (nb_floor->count_rhs > tower_size) ||
565 (tower_data[nb_floor->count_rhs - 1] != '\0'))
566 return EPT_S_NOT_REGISTERED;
568 if (networkaddr)
570 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
571 if (!*networkaddr)
573 if (endpoint)
575 I_RpcFree(*endpoint);
576 *endpoint = NULL;
578 return RPC_S_OUT_OF_RESOURCES;
580 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
583 return RPC_S_OK;
586 static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn)
588 RpcConnection_np *npc = (RpcConnection_np *)conn;
589 BOOL ret;
591 TRACE("(%p)\n", conn);
593 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
594 return RPCRT4_default_impersonate_client(conn);
596 ret = ImpersonateNamedPipeClient(npc->pipe);
597 if (!ret)
599 DWORD error = GetLastError();
600 WARN("ImpersonateNamedPipeClient failed with error %u\n", error);
601 switch (error)
603 case ERROR_CANNOT_IMPERSONATE:
604 return RPC_S_NO_CONTEXT_AVAILABLE;
607 return RPC_S_OK;
610 static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn)
612 BOOL ret;
614 TRACE("(%p)\n", conn);
616 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
617 return RPCRT4_default_revert_to_self(conn);
619 ret = RevertToSelf();
620 if (!ret)
622 WARN("RevertToSelf failed with error %u\n", GetLastError());
623 return RPC_S_NO_CONTEXT_AVAILABLE;
625 return RPC_S_OK;
628 typedef struct _RpcServerProtseq_np
630 RpcServerProtseq common;
631 HANDLE mgr_event;
632 } RpcServerProtseq_np;
634 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
636 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps));
637 if (ps)
638 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
639 return &ps->common;
642 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
644 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
645 SetEvent(npps->mgr_event);
648 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
650 HANDLE *objs = prev_array;
651 RpcConnection_np *conn;
652 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
654 EnterCriticalSection(&protseq->cs);
656 /* open and count connections */
657 *count = 1;
658 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
660 if (!conn->pipe && rpcrt4_conn_create_pipe(&conn->common) != RPC_S_OK)
661 continue;
662 if (!conn->listen_event)
664 NTSTATUS status;
665 HANDLE event;
667 event = get_np_event(conn);
668 if (!event)
669 continue;
671 status = NtFsControlFile(conn->pipe, event, NULL, NULL, &conn->io_status, FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
672 switch (status)
674 case STATUS_SUCCESS:
675 case STATUS_PIPE_CONNECTED:
676 conn->io_status.Status = status;
677 SetEvent(event);
678 break;
679 case STATUS_PENDING:
680 break;
681 default:
682 ERR("pipe listen error %x\n", status);
683 continue;
686 conn->listen_event = event;
688 (*count)++;
691 /* make array of connections */
692 if (objs)
693 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
694 else
695 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
696 if (!objs)
698 ERR("couldn't allocate objs\n");
699 LeaveCriticalSection(&protseq->cs);
700 return NULL;
703 objs[0] = npps->mgr_event;
704 *count = 1;
705 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
707 if (conn->listen_event)
708 objs[(*count)++] = conn->listen_event;
710 LeaveCriticalSection(&protseq->cs);
711 return objs;
714 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
716 HeapFree(GetProcessHeap(), 0, array);
719 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
721 HANDLE b_handle;
722 HANDLE *objs = wait_array;
723 DWORD res;
724 RpcConnection *cconn = NULL;
725 RpcConnection_np *conn;
727 if (!objs)
728 return -1;
732 /* an alertable wait isn't strictly necessary, but due to our
733 * overlapped I/O implementation in Wine we need to free some memory
734 * by the file user APC being called, even if no completion routine was
735 * specified at the time of starting the async operation */
736 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
737 } while (res == WAIT_IO_COMPLETION);
739 if (res == WAIT_OBJECT_0)
740 return 0;
741 else if (res == WAIT_FAILED)
743 ERR("wait failed with error %d\n", GetLastError());
744 return -1;
746 else
748 b_handle = objs[res - WAIT_OBJECT_0];
749 /* find which connection got a RPC */
750 EnterCriticalSection(&protseq->cs);
751 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
753 if (b_handle == conn->listen_event)
755 release_np_event(conn, conn->listen_event);
756 conn->listen_event = NULL;
757 if (conn->io_status.Status == STATUS_SUCCESS || conn->io_status.Status == STATUS_PIPE_CONNECTED)
758 cconn = rpcrt4_spawn_connection(&conn->common);
759 else
760 ERR("listen failed %x\n", conn->io_status.Status);
761 break;
764 LeaveCriticalSection(&protseq->cs);
765 if (!cconn)
767 ERR("failed to locate connection for handle %p\n", b_handle);
768 return -1;
770 RPCRT4_new_client(cconn);
771 return 1;
775 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
776 const char *networkaddr,
777 const char *endpoint)
779 twr_empty_floor_t *pipe_floor;
780 size_t size;
781 size_t endpoint_size;
783 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
785 endpoint_size = strlen(endpoint) + 1;
786 size = sizeof(*pipe_floor) + endpoint_size;
788 if (!tower_data)
789 return size;
791 pipe_floor = (twr_empty_floor_t *)tower_data;
793 tower_data += sizeof(*pipe_floor);
795 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
796 pipe_floor->protid = EPM_PROTOCOL_PIPE;
797 pipe_floor->count_rhs = endpoint_size;
799 memcpy(tower_data, endpoint, endpoint_size);
801 return size;
804 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
805 size_t tower_size,
806 char **networkaddr,
807 char **endpoint)
809 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
811 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
813 if (tower_size < sizeof(*pipe_floor))
814 return EPT_S_NOT_REGISTERED;
816 tower_data += sizeof(*pipe_floor);
817 tower_size -= sizeof(*pipe_floor);
819 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
820 (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
821 (pipe_floor->count_rhs > tower_size) ||
822 (tower_data[pipe_floor->count_rhs - 1] != '\0'))
823 return EPT_S_NOT_REGISTERED;
825 if (networkaddr)
826 *networkaddr = NULL;
828 if (endpoint)
830 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
831 if (!*endpoint)
832 return RPC_S_OUT_OF_RESOURCES;
833 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
836 return RPC_S_OK;
839 static BOOL rpcrt4_ncalrpc_is_authorized(RpcConnection *conn)
841 return FALSE;
844 static RPC_STATUS rpcrt4_ncalrpc_authorize(RpcConnection *conn, BOOL first_time,
845 unsigned char *in_buffer,
846 unsigned int in_size,
847 unsigned char *out_buffer,
848 unsigned int *out_size)
850 /* since this protocol is local to the machine there is no need to
851 * authenticate the caller */
852 *out_size = 0;
853 return RPC_S_OK;
856 static RPC_STATUS rpcrt4_ncalrpc_secure_packet(RpcConnection *conn,
857 enum secure_packet_direction dir,
858 RpcPktHdr *hdr, unsigned int hdr_size,
859 unsigned char *stub_data, unsigned int stub_data_size,
860 RpcAuthVerifier *auth_hdr,
861 unsigned char *auth_value, unsigned int auth_value_size)
863 /* since this protocol is local to the machine there is no need to secure
864 * the packet */
865 return RPC_S_OK;
868 static RPC_STATUS rpcrt4_ncalrpc_inquire_auth_client(
869 RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
870 ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
872 TRACE("(%p, %p, %p, %p, %p, %p, 0x%x)\n", conn, privs,
873 server_princ_name, authn_level, authn_svc, authz_svc, flags);
875 if (privs)
877 FIXME("privs not implemented\n");
878 *privs = NULL;
880 if (server_princ_name)
882 FIXME("server_princ_name not implemented\n");
883 *server_princ_name = NULL;
885 if (authn_level) *authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
886 if (authn_svc) *authn_svc = RPC_C_AUTHN_WINNT;
887 if (authz_svc)
889 FIXME("authorization service not implemented\n");
890 *authz_svc = RPC_C_AUTHZ_NONE;
892 if (flags)
893 FIXME("flags 0x%x not implemented\n", flags);
895 return RPC_S_OK;
898 /**** ncacn_ip_tcp support ****/
900 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
901 const char *networkaddr,
902 unsigned char tcp_protid,
903 const char *endpoint)
905 twr_tcp_floor_t *tcp_floor;
906 twr_ipv4_floor_t *ipv4_floor;
907 struct addrinfo *ai;
908 struct addrinfo hints;
909 int ret;
910 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
912 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
914 if (!tower_data)
915 return size;
917 tcp_floor = (twr_tcp_floor_t *)tower_data;
918 tower_data += sizeof(*tcp_floor);
920 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
922 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
923 tcp_floor->protid = tcp_protid;
924 tcp_floor->count_rhs = sizeof(tcp_floor->port);
926 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
927 ipv4_floor->protid = EPM_PROTOCOL_IP;
928 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
930 hints.ai_flags = AI_NUMERICHOST;
931 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
932 hints.ai_family = PF_INET;
933 hints.ai_socktype = SOCK_STREAM;
934 hints.ai_protocol = IPPROTO_TCP;
935 hints.ai_addrlen = 0;
936 hints.ai_addr = NULL;
937 hints.ai_canonname = NULL;
938 hints.ai_next = NULL;
940 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
941 if (ret)
943 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
944 if (ret)
946 ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
947 return 0;
951 if (ai->ai_family == PF_INET)
953 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
954 tcp_floor->port = sin->sin_port;
955 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
957 else
959 ERR("unexpected protocol family %d\n", ai->ai_family);
960 freeaddrinfo(ai);
961 return 0;
964 freeaddrinfo(ai);
966 return size;
969 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
970 size_t tower_size,
971 char **networkaddr,
972 unsigned char tcp_protid,
973 char **endpoint)
975 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
976 const twr_ipv4_floor_t *ipv4_floor;
977 struct in_addr in_addr;
979 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
981 if (tower_size < sizeof(*tcp_floor))
982 return EPT_S_NOT_REGISTERED;
984 tower_data += sizeof(*tcp_floor);
985 tower_size -= sizeof(*tcp_floor);
987 if (tower_size < sizeof(*ipv4_floor))
988 return EPT_S_NOT_REGISTERED;
990 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
992 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
993 (tcp_floor->protid != tcp_protid) ||
994 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
995 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
996 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
997 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
998 return EPT_S_NOT_REGISTERED;
1000 if (endpoint)
1002 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1003 if (!*endpoint)
1004 return RPC_S_OUT_OF_RESOURCES;
1005 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1008 if (networkaddr)
1010 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1011 if (!*networkaddr)
1013 if (endpoint)
1015 I_RpcFree(*endpoint);
1016 *endpoint = NULL;
1018 return RPC_S_OUT_OF_RESOURCES;
1020 in_addr.s_addr = ipv4_floor->ipv4addr;
1021 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1023 ERR("inet_ntop: %u\n", WSAGetLastError());
1024 I_RpcFree(*networkaddr);
1025 *networkaddr = NULL;
1026 if (endpoint)
1028 I_RpcFree(*endpoint);
1029 *endpoint = NULL;
1031 return EPT_S_NOT_REGISTERED;
1035 return RPC_S_OK;
1038 typedef struct _RpcConnection_tcp
1040 RpcConnection common;
1041 int sock;
1042 HANDLE sock_event;
1043 HANDLE cancel_event;
1044 } RpcConnection_tcp;
1046 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1048 static BOOL wsa_inited;
1049 if (!wsa_inited)
1051 WSADATA wsadata;
1052 WSAStartup(MAKEWORD(2, 2), &wsadata);
1053 /* Note: WSAStartup can be called more than once so we don't bother with
1054 * making accesses to wsa_inited thread-safe */
1055 wsa_inited = TRUE;
1057 tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1058 tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1059 if (!tcpc->sock_event || !tcpc->cancel_event)
1061 ERR("event creation failed\n");
1062 if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
1063 return FALSE;
1065 return TRUE;
1068 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1070 HANDLE wait_handles[2];
1071 DWORD res;
1072 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1074 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1075 return FALSE;
1077 wait_handles[0] = tcpc->sock_event;
1078 wait_handles[1] = tcpc->cancel_event;
1079 res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
1080 switch (res)
1082 case WAIT_OBJECT_0:
1083 return TRUE;
1084 case WAIT_OBJECT_0 + 1:
1085 return FALSE;
1086 default:
1087 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1088 return FALSE;
1092 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1094 DWORD res;
1095 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1097 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1098 return FALSE;
1100 res = WaitForSingleObject(tcpc->sock_event, INFINITE);
1101 switch (res)
1103 case WAIT_OBJECT_0:
1104 return TRUE;
1105 default:
1106 ERR("WaitForMultipleObjects() failed with error %d\n", GetLastError());
1107 return FALSE;
1111 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
1113 RpcConnection_tcp *tcpc;
1114 tcpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp));
1115 if (tcpc == NULL)
1116 return NULL;
1117 tcpc->sock = -1;
1118 if (!rpcrt4_sock_wait_init(tcpc))
1120 HeapFree(GetProcessHeap(), 0, tcpc);
1121 return NULL;
1123 return &tcpc->common;
1126 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
1128 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1129 int sock;
1130 int ret;
1131 struct addrinfo *ai;
1132 struct addrinfo *ai_cur;
1133 struct addrinfo hints;
1135 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1137 if (tcpc->sock != -1)
1138 return RPC_S_OK;
1140 hints.ai_flags = 0;
1141 hints.ai_family = PF_UNSPEC;
1142 hints.ai_socktype = SOCK_STREAM;
1143 hints.ai_protocol = IPPROTO_TCP;
1144 hints.ai_addrlen = 0;
1145 hints.ai_addr = NULL;
1146 hints.ai_canonname = NULL;
1147 hints.ai_next = NULL;
1149 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
1150 if (ret)
1152 ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
1153 Connection->Endpoint, gai_strerror(ret));
1154 return RPC_S_SERVER_UNAVAILABLE;
1157 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1159 int val;
1160 u_long nonblocking;
1162 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1164 TRACE("skipping non-IP/IPv6 address family\n");
1165 continue;
1168 if (TRACE_ON(rpc))
1170 char host[256];
1171 char service[256];
1172 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1173 host, sizeof(host), service, sizeof(service),
1174 NI_NUMERICHOST | NI_NUMERICSERV);
1175 TRACE("trying %s:%s\n", host, service);
1178 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1179 if (sock == -1)
1181 WARN("socket() failed: %u\n", WSAGetLastError());
1182 continue;
1185 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
1187 WARN("connect() failed: %u\n", WSAGetLastError());
1188 closesocket(sock);
1189 continue;
1192 /* RPC depends on having minimal latency so disable the Nagle algorithm */
1193 val = 1;
1194 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
1195 nonblocking = 1;
1196 ioctlsocket(sock, FIONBIO, &nonblocking);
1198 tcpc->sock = sock;
1200 freeaddrinfo(ai);
1201 TRACE("connected\n");
1202 return RPC_S_OK;
1205 freeaddrinfo(ai);
1206 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
1207 return RPC_S_SERVER_UNAVAILABLE;
1210 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
1212 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
1213 int sock;
1214 int ret;
1215 struct addrinfo *ai;
1216 struct addrinfo *ai_cur;
1217 struct addrinfo hints;
1219 TRACE("(%p, %s)\n", protseq, endpoint);
1221 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
1222 hints.ai_family = PF_UNSPEC;
1223 hints.ai_socktype = SOCK_STREAM;
1224 hints.ai_protocol = IPPROTO_TCP;
1225 hints.ai_addrlen = 0;
1226 hints.ai_addr = NULL;
1227 hints.ai_canonname = NULL;
1228 hints.ai_next = NULL;
1230 ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
1231 if (ret)
1233 ERR("getaddrinfo for port %s failed: %s\n", endpoint,
1234 gai_strerror(ret));
1235 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
1236 return RPC_S_INVALID_ENDPOINT_FORMAT;
1237 return RPC_S_CANT_CREATE_ENDPOINT;
1240 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1242 RpcConnection_tcp *tcpc;
1243 RPC_STATUS create_status;
1244 struct sockaddr_storage sa;
1245 socklen_t sa_len;
1246 char service[NI_MAXSERV];
1247 u_long nonblocking;
1249 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1251 TRACE("skipping non-IP/IPv6 address family\n");
1252 continue;
1255 if (TRACE_ON(rpc))
1257 char host[256];
1258 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1259 host, sizeof(host), service, sizeof(service),
1260 NI_NUMERICHOST | NI_NUMERICSERV);
1261 TRACE("trying %s:%s\n", host, service);
1264 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1265 if (sock == -1)
1267 WARN("socket() failed: %u\n", WSAGetLastError());
1268 status = RPC_S_CANT_CREATE_ENDPOINT;
1269 continue;
1272 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
1273 if (ret < 0)
1275 WARN("bind failed: %u\n", WSAGetLastError());
1276 closesocket(sock);
1277 if (WSAGetLastError() == WSAEADDRINUSE)
1278 status = RPC_S_DUPLICATE_ENDPOINT;
1279 else
1280 status = RPC_S_CANT_CREATE_ENDPOINT;
1281 continue;
1284 sa_len = sizeof(sa);
1285 if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
1287 WARN("getsockname() failed: %u\n", WSAGetLastError());
1288 closesocket(sock);
1289 status = RPC_S_CANT_CREATE_ENDPOINT;
1290 continue;
1293 ret = getnameinfo((struct sockaddr *)&sa, sa_len,
1294 NULL, 0, service, sizeof(service),
1295 NI_NUMERICSERV);
1296 if (ret)
1298 WARN("getnameinfo failed: %s\n", gai_strerror(ret));
1299 closesocket(sock);
1300 status = RPC_S_CANT_CREATE_ENDPOINT;
1301 continue;
1304 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
1305 protseq->Protseq, NULL,
1306 service, NULL, NULL, NULL, NULL);
1307 if (create_status != RPC_S_OK)
1309 closesocket(sock);
1310 status = create_status;
1311 continue;
1314 tcpc->sock = sock;
1315 ret = listen(sock, protseq->MaxCalls);
1316 if (ret < 0)
1318 WARN("listen failed: %u\n", WSAGetLastError());
1319 RPCRT4_ReleaseConnection(&tcpc->common);
1320 status = RPC_S_OUT_OF_RESOURCES;
1321 continue;
1323 /* need a non-blocking socket, otherwise accept() has a potential
1324 * race-condition (poll() says it is readable, connection drops,
1325 * and accept() blocks until the next connection comes...)
1327 nonblocking = 1;
1328 ret = ioctlsocket(sock, FIONBIO, &nonblocking);
1329 if (ret < 0)
1331 WARN("couldn't make socket non-blocking, error %d\n", ret);
1332 RPCRT4_ReleaseConnection(&tcpc->common);
1333 status = RPC_S_OUT_OF_RESOURCES;
1334 continue;
1337 EnterCriticalSection(&protseq->cs);
1338 list_add_tail(&protseq->listeners, &tcpc->common.protseq_entry);
1339 tcpc->common.protseq = protseq;
1340 LeaveCriticalSection(&protseq->cs);
1342 freeaddrinfo(ai);
1344 /* since IPv4 and IPv6 share the same port space, we only need one
1345 * successful bind to listen for both */
1346 TRACE("listening on %s\n", endpoint);
1347 return RPC_S_OK;
1350 freeaddrinfo(ai);
1351 ERR("couldn't listen on port %s\n", endpoint);
1352 return status;
1355 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1357 int ret;
1358 struct sockaddr_in address;
1359 socklen_t addrsize;
1360 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
1361 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
1362 u_long nonblocking;
1364 addrsize = sizeof(address);
1365 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
1366 if (ret < 0)
1368 ERR("Failed to accept a TCP connection: error %d\n", ret);
1369 return RPC_S_OUT_OF_RESOURCES;
1372 nonblocking = 1;
1373 ioctlsocket(ret, FIONBIO, &nonblocking);
1374 client->sock = ret;
1376 client->common.NetworkAddr = HeapAlloc(GetProcessHeap(), 0, INET6_ADDRSTRLEN);
1377 ret = getnameinfo((struct sockaddr*)&address, addrsize, client->common.NetworkAddr, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
1378 if (ret != 0)
1380 ERR("Failed to retrieve the IP address, error %d\n", ret);
1381 return RPC_S_OUT_OF_RESOURCES;
1384 TRACE("Accepted a new TCP connection from %s\n", client->common.NetworkAddr);
1385 return RPC_S_OK;
1388 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
1389 void *buffer, unsigned int count)
1391 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1392 int bytes_read = 0;
1393 while (bytes_read != count)
1395 int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
1396 if (!r)
1397 return -1;
1398 else if (r > 0)
1399 bytes_read += r;
1400 else if (WSAGetLastError() == WSAEINTR)
1401 continue;
1402 else if (WSAGetLastError() != WSAEWOULDBLOCK)
1404 WARN("recv() failed: %u\n", WSAGetLastError());
1405 return -1;
1407 else
1409 if (!rpcrt4_sock_wait_for_recv(tcpc))
1410 return -1;
1413 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
1414 return bytes_read;
1417 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
1418 const void *buffer, unsigned int count)
1420 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1421 int bytes_written = 0;
1422 while (bytes_written != count)
1424 int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
1425 if (r >= 0)
1426 bytes_written += r;
1427 else if (WSAGetLastError() == WSAEINTR)
1428 continue;
1429 else if (WSAGetLastError() != WSAEWOULDBLOCK)
1430 return -1;
1431 else
1433 if (!rpcrt4_sock_wait_for_send(tcpc))
1434 return -1;
1437 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1438 return bytes_written;
1441 static int rpcrt4_conn_tcp_close(RpcConnection *conn)
1443 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1445 TRACE("%d\n", connection->sock);
1447 if (connection->sock != -1)
1448 closesocket(connection->sock);
1449 connection->sock = -1;
1450 CloseHandle(connection->sock_event);
1451 CloseHandle(connection->cancel_event);
1452 return 0;
1455 static void rpcrt4_conn_tcp_close_read(RpcConnection *conn)
1457 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1458 shutdown(connection->sock, SD_RECEIVE);
1461 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *conn)
1463 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1465 TRACE("%p\n", connection);
1467 SetEvent(connection->cancel_event);
1470 static RPC_STATUS rpcrt4_conn_tcp_is_server_listening(const char *endpoint)
1472 FIXME("\n");
1473 return RPC_S_ACCESS_DENIED;
1476 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
1478 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1480 TRACE("%p\n", Connection);
1482 if (!rpcrt4_sock_wait_for_recv(tcpc))
1483 return -1;
1484 return 0;
1487 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1488 const char *networkaddr,
1489 const char *endpoint)
1491 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1492 EPM_PROTOCOL_TCP, endpoint);
1495 typedef struct _RpcServerProtseq_sock
1497 RpcServerProtseq common;
1498 HANDLE mgr_event;
1499 } RpcServerProtseq_sock;
1501 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1503 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps));
1504 if (ps)
1506 static BOOL wsa_inited;
1507 if (!wsa_inited)
1509 WSADATA wsadata;
1510 WSAStartup(MAKEWORD(2, 2), &wsadata);
1511 /* Note: WSAStartup can be called more than once so we don't bother with
1512 * making accesses to wsa_inited thread-safe */
1513 wsa_inited = TRUE;
1515 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1517 return &ps->common;
1520 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1522 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1523 SetEvent(sockps->mgr_event);
1526 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1528 HANDLE *objs = prev_array;
1529 RpcConnection_tcp *conn;
1530 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1532 EnterCriticalSection(&protseq->cs);
1534 /* open and count connections */
1535 *count = 1;
1536 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1538 if (conn->sock != -1)
1539 (*count)++;
1542 /* make array of connections */
1543 if (objs)
1544 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
1545 else
1546 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
1547 if (!objs)
1549 ERR("couldn't allocate objs\n");
1550 LeaveCriticalSection(&protseq->cs);
1551 return NULL;
1554 objs[0] = sockps->mgr_event;
1555 *count = 1;
1556 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1558 if (conn->sock != -1)
1560 int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
1561 if (res == SOCKET_ERROR)
1562 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1563 else
1565 objs[*count] = conn->sock_event;
1566 (*count)++;
1570 LeaveCriticalSection(&protseq->cs);
1571 return objs;
1574 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1576 HeapFree(GetProcessHeap(), 0, array);
1579 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1581 HANDLE b_handle;
1582 HANDLE *objs = wait_array;
1583 DWORD res;
1584 RpcConnection *cconn = NULL;
1585 RpcConnection_tcp *conn;
1587 if (!objs)
1588 return -1;
1592 /* an alertable wait isn't strictly necessary, but due to our
1593 * overlapped I/O implementation in Wine we need to free some memory
1594 * by the file user APC being called, even if no completion routine was
1595 * specified at the time of starting the async operation */
1596 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
1597 } while (res == WAIT_IO_COMPLETION);
1599 if (res == WAIT_OBJECT_0)
1600 return 0;
1601 if (res == WAIT_FAILED)
1603 ERR("wait failed with error %d\n", GetLastError());
1604 return -1;
1607 b_handle = objs[res - WAIT_OBJECT_0];
1609 /* find which connection got a RPC */
1610 EnterCriticalSection(&protseq->cs);
1611 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1613 if (b_handle == conn->sock_event)
1615 cconn = rpcrt4_spawn_connection(&conn->common);
1616 break;
1619 LeaveCriticalSection(&protseq->cs);
1620 if (!cconn)
1622 ERR("failed to locate connection for handle %p\n", b_handle);
1623 return -1;
1626 RPCRT4_new_client(cconn);
1627 return 1;
1630 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1631 size_t tower_size,
1632 char **networkaddr,
1633 char **endpoint)
1635 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1636 networkaddr, EPM_PROTOCOL_TCP,
1637 endpoint);
1640 /**** ncacn_http support ****/
1642 /* 60 seconds is the period native uses */
1643 #define HTTP_IDLE_TIME 60000
1645 /* reference counted to avoid a race between a cancelled call's connection
1646 * being destroyed and the asynchronous InternetReadFileEx call being
1647 * completed */
1648 typedef struct _RpcHttpAsyncData
1650 LONG refs;
1651 HANDLE completion_event;
1652 WORD async_result;
1653 INTERNET_BUFFERSW inet_buffers;
1654 CRITICAL_SECTION cs;
1655 } RpcHttpAsyncData;
1657 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
1659 return InterlockedIncrement(&data->refs);
1662 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
1664 ULONG refs = InterlockedDecrement(&data->refs);
1665 if (!refs)
1667 TRACE("destroying async data %p\n", data);
1668 CloseHandle(data->completion_event);
1669 HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
1670 data->cs.DebugInfo->Spare[0] = 0;
1671 DeleteCriticalSection(&data->cs);
1672 HeapFree(GetProcessHeap(), 0, data);
1674 return refs;
1677 static void prepare_async_request(RpcHttpAsyncData *async_data)
1679 ResetEvent(async_data->completion_event);
1680 RpcHttpAsyncData_AddRef(async_data);
1683 static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret, HANDLE cancel_event)
1685 HANDLE handles[2] = { async_data->completion_event, cancel_event };
1686 DWORD res;
1688 if(call_ret) {
1689 RpcHttpAsyncData_Release(async_data);
1690 return RPC_S_OK;
1693 if(GetLastError() != ERROR_IO_PENDING) {
1694 RpcHttpAsyncData_Release(async_data);
1695 ERR("Request failed with error %d\n", GetLastError());
1696 return RPC_S_SERVER_UNAVAILABLE;
1699 res = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
1700 if(res != WAIT_OBJECT_0) {
1701 TRACE("Cancelled\n");
1702 return RPC_S_CALL_CANCELLED;
1705 if(async_data->async_result) {
1706 ERR("Async request failed with error %d\n", async_data->async_result);
1707 return RPC_S_SERVER_UNAVAILABLE;
1710 return RPC_S_OK;
1713 struct authinfo
1715 DWORD scheme;
1716 CredHandle cred;
1717 CtxtHandle ctx;
1718 TimeStamp exp;
1719 ULONG attr;
1720 ULONG max_token;
1721 char *data;
1722 unsigned int data_len;
1723 BOOL finished; /* finished authenticating */
1726 typedef struct _RpcConnection_http
1728 RpcConnection common;
1729 HINTERNET app_info;
1730 HINTERNET session;
1731 HINTERNET in_request;
1732 HINTERNET out_request;
1733 WCHAR *servername;
1734 HANDLE timer_cancelled;
1735 HANDLE cancel_event;
1736 DWORD last_sent_time;
1737 ULONG bytes_received;
1738 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
1739 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
1740 UUID connection_uuid;
1741 UUID in_pipe_uuid;
1742 UUID out_pipe_uuid;
1743 RpcHttpAsyncData *async_data;
1744 } RpcConnection_http;
1746 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
1748 RpcConnection_http *httpc;
1749 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
1750 if (!httpc) return NULL;
1751 httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
1752 if (!httpc->async_data)
1754 HeapFree(GetProcessHeap(), 0, httpc);
1755 return NULL;
1757 TRACE("async data = %p\n", httpc->async_data);
1758 httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1759 httpc->async_data->refs = 1;
1760 httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSW);
1761 InitializeCriticalSection(&httpc->async_data->cs);
1762 httpc->async_data->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcHttpAsyncData.cs");
1763 return &httpc->common;
1766 typedef struct _HttpTimerThreadData
1768 PVOID timer_param;
1769 DWORD *last_sent_time;
1770 HANDLE timer_cancelled;
1771 } HttpTimerThreadData;
1773 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
1775 HINTERNET in_request = param;
1776 RpcPktHdr *idle_pkt;
1778 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
1779 0, 0);
1780 if (idle_pkt)
1782 DWORD bytes_written;
1783 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
1784 RPCRT4_FreeHeader(idle_pkt);
1788 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
1790 DWORD cur_time = GetTickCount();
1791 DWORD cached_last_sent_time = *last_sent_time;
1792 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
1795 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
1797 HttpTimerThreadData *data_in = param;
1798 HttpTimerThreadData data;
1799 DWORD timeout;
1801 data = *data_in;
1802 HeapFree(GetProcessHeap(), 0, data_in);
1804 for (timeout = HTTP_IDLE_TIME;
1805 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
1806 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
1808 /* are we too soon after last send? */
1809 if (GetTickCount() - *data.last_sent_time < HTTP_IDLE_TIME)
1810 continue;
1811 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
1814 CloseHandle(data.timer_cancelled);
1815 return 0;
1818 static VOID WINAPI rpcrt4_http_internet_callback(
1819 HINTERNET hInternet,
1820 DWORD_PTR dwContext,
1821 DWORD dwInternetStatus,
1822 LPVOID lpvStatusInformation,
1823 DWORD dwStatusInformationLength)
1825 RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
1827 switch (dwInternetStatus)
1829 case INTERNET_STATUS_REQUEST_COMPLETE:
1830 TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
1831 if (async_data)
1833 INTERNET_ASYNC_RESULT *async_result = lpvStatusInformation;
1835 async_data->async_result = async_result->dwResult ? ERROR_SUCCESS : async_result->dwError;
1836 SetEvent(async_data->completion_event);
1837 RpcHttpAsyncData_Release(async_data);
1839 break;
1843 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
1845 BOOL ret;
1846 DWORD status_code;
1847 DWORD size;
1848 DWORD index;
1849 WCHAR buf[32];
1850 WCHAR *status_text = buf;
1851 TRACE("\n");
1853 index = 0;
1854 size = sizeof(status_code);
1855 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
1856 if (!ret)
1857 return GetLastError();
1858 if (status_code == HTTP_STATUS_OK)
1859 return RPC_S_OK;
1860 index = 0;
1861 size = sizeof(buf);
1862 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1863 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1865 status_text = HeapAlloc(GetProcessHeap(), 0, size);
1866 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1869 ERR("server returned: %d %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
1870 if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
1872 if (status_code == HTTP_STATUS_DENIED)
1873 return ERROR_ACCESS_DENIED;
1874 return RPC_S_SERVER_UNAVAILABLE;
1877 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
1879 static const WCHAR wszUserAgent[] = {'M','S','R','P','C',0};
1880 LPWSTR proxy = NULL;
1881 LPWSTR user = NULL;
1882 LPWSTR password = NULL;
1883 LPWSTR servername = NULL;
1884 const WCHAR *option;
1885 INTERNET_PORT port;
1887 if (httpc->common.QOS &&
1888 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
1890 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
1891 if (http_cred->TransportCredentials)
1893 WCHAR *p;
1894 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
1895 ULONG len = cred->DomainLength + 1 + cred->UserLength;
1896 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1897 if (!user)
1898 return RPC_S_OUT_OF_RESOURCES;
1899 p = user;
1900 if (cred->DomainLength)
1902 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
1903 p += cred->DomainLength;
1904 *p = '\\';
1905 p++;
1907 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
1908 p[cred->UserLength] = 0;
1910 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
1914 for (option = httpc->common.NetworkOptions; option;
1915 option = (strchrW(option, ',') ? strchrW(option, ',')+1 : NULL))
1917 static const WCHAR wszRpcProxy[] = {'R','p','c','P','r','o','x','y','=',0};
1918 static const WCHAR wszHttpProxy[] = {'H','t','t','p','P','r','o','x','y','=',0};
1920 if (!strncmpiW(option, wszRpcProxy, ARRAY_SIZE(wszRpcProxy)-1))
1922 const WCHAR *value_start = option + ARRAY_SIZE(wszRpcProxy)-1;
1923 const WCHAR *value_end;
1924 const WCHAR *p;
1926 value_end = strchrW(option, ',');
1927 if (!value_end)
1928 value_end = value_start + strlenW(value_start);
1929 for (p = value_start; p < value_end; p++)
1930 if (*p == ':')
1932 port = atoiW(p+1);
1933 value_end = p;
1934 break;
1936 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
1937 servername = RPCRT4_strndupW(value_start, value_end-value_start);
1939 else if (!strncmpiW(option, wszHttpProxy, ARRAY_SIZE(wszHttpProxy)-1))
1941 const WCHAR *value_start = option + ARRAY_SIZE(wszHttpProxy)-1;
1942 const WCHAR *value_end;
1944 value_end = strchrW(option, ',');
1945 if (!value_end)
1946 value_end = value_start + strlenW(value_start);
1947 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
1948 proxy = RPCRT4_strndupW(value_start, value_end-value_start);
1950 else
1951 FIXME("unhandled option %s\n", debugstr_w(option));
1954 httpc->app_info = InternetOpenW(wszUserAgent, proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
1955 NULL, NULL, INTERNET_FLAG_ASYNC);
1956 if (!httpc->app_info)
1958 HeapFree(GetProcessHeap(), 0, password);
1959 HeapFree(GetProcessHeap(), 0, user);
1960 HeapFree(GetProcessHeap(), 0, proxy);
1961 HeapFree(GetProcessHeap(), 0, servername);
1962 ERR("InternetOpenW failed with error %d\n", GetLastError());
1963 return RPC_S_SERVER_UNAVAILABLE;
1965 InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
1967 /* if no RpcProxy option specified, set the HTTP server address to the
1968 * RPC server address */
1969 if (!servername)
1971 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
1972 if (!servername)
1974 HeapFree(GetProcessHeap(), 0, password);
1975 HeapFree(GetProcessHeap(), 0, user);
1976 HeapFree(GetProcessHeap(), 0, proxy);
1977 return RPC_S_OUT_OF_RESOURCES;
1979 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
1982 port = (httpc->common.QOS &&
1983 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
1984 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)) ?
1985 INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
1987 httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
1988 INTERNET_SERVICE_HTTP, 0, 0);
1990 HeapFree(GetProcessHeap(), 0, password);
1991 HeapFree(GetProcessHeap(), 0, user);
1992 HeapFree(GetProcessHeap(), 0, proxy);
1994 if (!httpc->session)
1996 ERR("InternetConnectW failed with error %d\n", GetLastError());
1997 HeapFree(GetProcessHeap(), 0, servername);
1998 return RPC_S_SERVER_UNAVAILABLE;
2000 httpc->servername = servername;
2001 return RPC_S_OK;
2004 static int rpcrt4_http_async_read(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2005 void *buffer, unsigned int count)
2007 char *buf = buffer;
2008 BOOL ret;
2009 unsigned int bytes_left = count;
2010 RPC_STATUS status = RPC_S_OK;
2012 async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, count);
2014 while (bytes_left)
2016 async_data->inet_buffers.dwBufferLength = bytes_left;
2017 prepare_async_request(async_data);
2018 ret = InternetReadFileExW(req, &async_data->inet_buffers, IRF_ASYNC, 0);
2019 status = wait_async_request(async_data, ret, cancel_event);
2020 if (status != RPC_S_OK)
2022 if (status == RPC_S_CALL_CANCELLED)
2023 TRACE("call cancelled\n");
2024 break;
2027 if (!async_data->inet_buffers.dwBufferLength)
2028 break;
2029 memcpy(buf, async_data->inet_buffers.lpvBuffer,
2030 async_data->inet_buffers.dwBufferLength);
2032 bytes_left -= async_data->inet_buffers.dwBufferLength;
2033 buf += async_data->inet_buffers.dwBufferLength;
2036 HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
2037 async_data->inet_buffers.lpvBuffer = NULL;
2039 TRACE("%p %p %u -> %u\n", req, buffer, count, status);
2040 return status == RPC_S_OK ? count : -1;
2043 static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2045 BYTE buf[20];
2046 BOOL ret;
2047 RPC_STATUS status;
2049 TRACE("sending echo request to server\n");
2051 prepare_async_request(async_data);
2052 ret = HttpSendRequestW(req, NULL, 0, NULL, 0);
2053 status = wait_async_request(async_data, ret, cancel_event);
2054 if (status != RPC_S_OK) return status;
2056 status = rpcrt4_http_check_response(req);
2057 if (status != RPC_S_OK) return status;
2059 rpcrt4_http_async_read(req, async_data, cancel_event, buf, sizeof(buf));
2060 /* FIXME: do something with retrieved data */
2062 return RPC_S_OK;
2065 static RPC_STATUS insert_content_length_header(HINTERNET request, DWORD len)
2067 static const WCHAR fmtW[] =
2068 {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','u','\r','\n',0};
2069 WCHAR header[ARRAY_SIZE(fmtW) + 10];
2071 sprintfW(header, fmtW, len);
2072 if ((HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))) return RPC_S_OK;
2073 return RPC_S_SERVER_UNAVAILABLE;
2076 /* prepare the in pipe for use by RPC packets */
2077 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2078 const UUID *connection_uuid, const UUID *in_pipe_uuid,
2079 const UUID *association_uuid, BOOL authorized)
2081 BOOL ret;
2082 RPC_STATUS status;
2083 RpcPktHdr *hdr;
2084 INTERNET_BUFFERSW buffers_in;
2085 DWORD bytes_written;
2087 if (!authorized)
2089 /* ask wininet to authorize, if necessary */
2090 status = send_echo_request(in_request, async_data, cancel_event);
2091 if (status != RPC_S_OK) return status;
2093 memset(&buffers_in, 0, sizeof(buffers_in));
2094 buffers_in.dwStructSize = sizeof(buffers_in);
2095 /* FIXME: get this from the registry */
2096 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
2097 status = insert_content_length_header(in_request, buffers_in.dwBufferTotal);
2098 if (status != RPC_S_OK) return status;
2100 prepare_async_request(async_data);
2101 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
2102 status = wait_async_request(async_data, ret, cancel_event);
2103 if (status != RPC_S_OK) return status;
2105 TRACE("sending HTTP connect header to server\n");
2106 hdr = RPCRT4_BuildHttpConnectHeader(FALSE, connection_uuid, in_pipe_uuid, association_uuid);
2107 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2108 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
2109 RPCRT4_FreeHeader(hdr);
2110 if (!ret)
2112 ERR("InternetWriteFile failed with error %d\n", GetLastError());
2113 return RPC_S_SERVER_UNAVAILABLE;
2116 return RPC_S_OK;
2119 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcHttpAsyncData *async_data,
2120 HANDLE cancel_event, RpcPktHdr *hdr, BYTE **data)
2122 unsigned short data_len;
2123 unsigned int size;
2125 if (rpcrt4_http_async_read(request, async_data, cancel_event, hdr, sizeof(hdr->common)) < 0)
2126 return RPC_S_SERVER_UNAVAILABLE;
2127 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
2129 ERR("wrong packet type received %d or wrong frag_len %d\n",
2130 hdr->common.ptype, hdr->common.frag_len);
2131 return RPC_S_PROTOCOL_ERROR;
2134 size = sizeof(hdr->http) - sizeof(hdr->common);
2135 if (rpcrt4_http_async_read(request, async_data, cancel_event, &hdr->common + 1, size) < 0)
2136 return RPC_S_SERVER_UNAVAILABLE;
2138 data_len = hdr->common.frag_len - sizeof(hdr->http);
2139 if (data_len)
2141 *data = HeapAlloc(GetProcessHeap(), 0, data_len);
2142 if (!*data)
2143 return RPC_S_OUT_OF_RESOURCES;
2144 if (rpcrt4_http_async_read(request, async_data, cancel_event, *data, data_len) < 0)
2146 HeapFree(GetProcessHeap(), 0, *data);
2147 return RPC_S_SERVER_UNAVAILABLE;
2150 else
2151 *data = NULL;
2153 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
2155 ERR("invalid http packet\n");
2156 HeapFree(GetProcessHeap(), 0, *data);
2157 return RPC_S_PROTOCOL_ERROR;
2160 return RPC_S_OK;
2163 /* prepare the out pipe for use by RPC packets */
2164 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, RpcHttpAsyncData *async_data,
2165 HANDLE cancel_event, const UUID *connection_uuid,
2166 const UUID *out_pipe_uuid, ULONG *flow_control_increment,
2167 BOOL authorized)
2169 BOOL ret;
2170 RPC_STATUS status;
2171 RpcPktHdr *hdr;
2172 BYTE *data_from_server;
2173 RpcPktHdr pkt_from_server;
2174 ULONG field1, field3;
2175 BYTE buf[20];
2177 if (!authorized)
2179 /* ask wininet to authorize, if necessary */
2180 status = send_echo_request(out_request, async_data, cancel_event);
2181 if (status != RPC_S_OK) return status;
2183 else
2184 rpcrt4_http_async_read(out_request, async_data, cancel_event, buf, sizeof(buf));
2186 hdr = RPCRT4_BuildHttpConnectHeader(TRUE, connection_uuid, out_pipe_uuid, NULL);
2187 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2189 status = insert_content_length_header(out_request, hdr->common.frag_len);
2190 if (status != RPC_S_OK)
2192 RPCRT4_FreeHeader(hdr);
2193 return status;
2196 TRACE("sending HTTP connect header to server\n");
2197 prepare_async_request(async_data);
2198 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
2199 status = wait_async_request(async_data, ret, cancel_event);
2200 RPCRT4_FreeHeader(hdr);
2201 if (status != RPC_S_OK) return status;
2203 status = rpcrt4_http_check_response(out_request);
2204 if (status != RPC_S_OK) return status;
2206 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2207 &pkt_from_server, &data_from_server);
2208 if (status != RPC_S_OK) return status;
2209 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
2210 &field1);
2211 HeapFree(GetProcessHeap(), 0, data_from_server);
2212 if (status != RPC_S_OK) return status;
2213 TRACE("received (%d) from first prepare header\n", field1);
2215 for (;;)
2217 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2218 &pkt_from_server, &data_from_server);
2219 if (status != RPC_S_OK) return status;
2220 if (pkt_from_server.http.flags != 0x0001) break;
2222 TRACE("http idle packet, waiting for real packet\n");
2223 HeapFree(GetProcessHeap(), 0, data_from_server);
2224 if (pkt_from_server.http.num_data_items != 0)
2226 ERR("HTTP idle packet should have no data items instead of %d\n",
2227 pkt_from_server.http.num_data_items);
2228 return RPC_S_PROTOCOL_ERROR;
2231 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
2232 &field1, flow_control_increment,
2233 &field3);
2234 HeapFree(GetProcessHeap(), 0, data_from_server);
2235 if (status != RPC_S_OK) return status;
2236 TRACE("received (0x%08x 0x%08x %d) from second prepare header\n", field1, *flow_control_increment, field3);
2238 return RPC_S_OK;
2241 static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64)
2243 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2244 UINT i = 0, x;
2246 while (len > 0)
2248 /* first 6 bits, all from bin[0] */
2249 base64[i++] = enc[(bin[0] & 0xfc) >> 2];
2250 x = (bin[0] & 3) << 4;
2252 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
2253 if (len == 1)
2255 base64[i++] = enc[x];
2256 base64[i++] = '=';
2257 base64[i++] = '=';
2258 break;
2260 base64[i++] = enc[x | ((bin[1] & 0xf0) >> 4)];
2261 x = (bin[1] & 0x0f) << 2;
2263 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
2264 if (len == 2)
2266 base64[i++] = enc[x];
2267 base64[i++] = '=';
2268 break;
2270 base64[i++] = enc[x | ((bin[2] & 0xc0) >> 6)];
2272 /* last 6 bits, all from bin [2] */
2273 base64[i++] = enc[bin[2] & 0x3f];
2274 bin += 3;
2275 len -= 3;
2277 base64[i] = 0;
2278 return i;
2281 static inline char decode_char( WCHAR c )
2283 if (c >= 'A' && c <= 'Z') return c - 'A';
2284 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2285 if (c >= '0' && c <= '9') return c - '0' + 52;
2286 if (c == '+') return 62;
2287 if (c == '/') return 63;
2288 return 64;
2291 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf )
2293 unsigned int i = 0;
2294 char c0, c1, c2, c3;
2295 const WCHAR *p = base64;
2297 while (len > 4)
2299 if ((c0 = decode_char( p[0] )) > 63) return 0;
2300 if ((c1 = decode_char( p[1] )) > 63) return 0;
2301 if ((c2 = decode_char( p[2] )) > 63) return 0;
2302 if ((c3 = decode_char( p[3] )) > 63) return 0;
2304 if (buf)
2306 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2307 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2308 buf[i + 2] = (c2 << 6) | c3;
2310 len -= 4;
2311 i += 3;
2312 p += 4;
2314 if (p[2] == '=')
2316 if ((c0 = decode_char( p[0] )) > 63) return 0;
2317 if ((c1 = decode_char( p[1] )) > 63) return 0;
2319 if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
2320 i++;
2322 else if (p[3] == '=')
2324 if ((c0 = decode_char( p[0] )) > 63) return 0;
2325 if ((c1 = decode_char( p[1] )) > 63) return 0;
2326 if ((c2 = decode_char( p[2] )) > 63) return 0;
2328 if (buf)
2330 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2331 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2333 i += 2;
2335 else
2337 if ((c0 = decode_char( p[0] )) > 63) return 0;
2338 if ((c1 = decode_char( p[1] )) > 63) return 0;
2339 if ((c2 = decode_char( p[2] )) > 63) return 0;
2340 if ((c3 = decode_char( p[3] )) > 63) return 0;
2342 if (buf)
2344 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2345 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2346 buf[i + 2] = (c2 << 6) | c3;
2348 i += 3;
2350 return i;
2353 static struct authinfo *alloc_authinfo(void)
2355 struct authinfo *ret;
2357 if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret) ))) return NULL;
2359 SecInvalidateHandle(&ret->cred);
2360 SecInvalidateHandle(&ret->ctx);
2361 memset(&ret->exp, 0, sizeof(ret->exp));
2362 ret->scheme = 0;
2363 ret->attr = 0;
2364 ret->max_token = 0;
2365 ret->data = NULL;
2366 ret->data_len = 0;
2367 ret->finished = FALSE;
2368 return ret;
2371 static void destroy_authinfo(struct authinfo *info)
2373 if (!info) return;
2375 if (SecIsValidHandle(&info->ctx))
2376 DeleteSecurityContext(&info->ctx);
2377 if (SecIsValidHandle(&info->cred))
2378 FreeCredentialsHandle(&info->cred);
2380 HeapFree(GetProcessHeap(), 0, info->data);
2381 HeapFree(GetProcessHeap(), 0, info);
2384 static const WCHAR basicW[] = {'B','a','s','i','c',0};
2385 static const WCHAR ntlmW[] = {'N','T','L','M',0};
2386 static const WCHAR passportW[] = {'P','a','s','s','p','o','r','t',0};
2387 static const WCHAR digestW[] = {'D','i','g','e','s','t',0};
2388 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
2390 static const struct
2392 const WCHAR *str;
2393 unsigned int len;
2394 DWORD scheme;
2396 auth_schemes[] =
2398 { basicW, ARRAY_SIZE(basicW) - 1, RPC_C_HTTP_AUTHN_SCHEME_BASIC },
2399 { ntlmW, ARRAY_SIZE(ntlmW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NTLM },
2400 { passportW, ARRAY_SIZE(passportW) - 1, RPC_C_HTTP_AUTHN_SCHEME_PASSPORT },
2401 { digestW, ARRAY_SIZE(digestW) - 1, RPC_C_HTTP_AUTHN_SCHEME_DIGEST },
2402 { negotiateW, ARRAY_SIZE(negotiateW) - 1, RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE }
2405 static DWORD auth_scheme_from_header( const WCHAR *header )
2407 unsigned int i;
2408 for (i = 0; i < ARRAY_SIZE(auth_schemes); i++)
2410 if (!strncmpiW( header, auth_schemes[i].str, auth_schemes[i].len ) &&
2411 (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme;
2413 return 0;
2416 static BOOL get_authvalue(HINTERNET request, DWORD scheme, WCHAR *buffer, DWORD buflen)
2418 DWORD len, index = 0;
2419 for (;;)
2421 len = buflen;
2422 if (!HttpQueryInfoW(request, HTTP_QUERY_WWW_AUTHENTICATE, buffer, &len, &index)) return FALSE;
2423 if (auth_scheme_from_header(buffer) == scheme) break;
2425 return TRUE;
2428 static RPC_STATUS do_authorization(HINTERNET request, SEC_WCHAR *servername,
2429 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds, struct authinfo **auth_ptr)
2431 struct authinfo *info = *auth_ptr;
2432 SEC_WINNT_AUTH_IDENTITY_W *id = creds->TransportCredentials;
2433 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2435 if ((!info && !(info = alloc_authinfo()))) return RPC_S_SERVER_UNAVAILABLE;
2437 switch (creds->AuthnSchemes[0])
2439 case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2441 int userlen = WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, NULL, 0, NULL, NULL);
2442 int passlen = WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, NULL, 0, NULL, NULL);
2444 info->data_len = userlen + passlen + 1;
2445 if (!(info->data = HeapAlloc(GetProcessHeap(), 0, info->data_len)))
2447 status = RPC_S_OUT_OF_MEMORY;
2448 break;
2450 WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, info->data, userlen, NULL, NULL);
2451 info->data[userlen] = ':';
2452 WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, info->data + userlen + 1, passlen, NULL, NULL);
2454 info->scheme = RPC_C_HTTP_AUTHN_SCHEME_BASIC;
2455 info->finished = TRUE;
2456 status = RPC_S_OK;
2457 break;
2459 case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2460 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2463 static SEC_WCHAR ntlmW[] = {'N','T','L','M',0}, negotiateW[] = {'N','e','g','o','t','i','a','t','e',0};
2464 SECURITY_STATUS ret;
2465 SecBufferDesc out_desc, in_desc;
2466 SecBuffer out, in;
2467 ULONG flags = ISC_REQ_CONNECTION|ISC_REQ_USE_DCE_STYLE|ISC_REQ_MUTUAL_AUTH|ISC_REQ_DELEGATE;
2468 SEC_WCHAR *scheme;
2469 int scheme_len;
2470 const WCHAR *p;
2471 WCHAR auth_value[2048];
2472 DWORD size = sizeof(auth_value);
2473 BOOL first = FALSE;
2475 if (creds->AuthnSchemes[0] == RPC_C_HTTP_AUTHN_SCHEME_NTLM) scheme = ntlmW;
2476 else scheme = negotiateW;
2477 scheme_len = strlenW( scheme );
2479 if (!*auth_ptr)
2481 TimeStamp exp;
2482 SecPkgInfoW *pkg_info;
2484 ret = AcquireCredentialsHandleW(NULL, scheme, SECPKG_CRED_OUTBOUND, NULL, id, NULL, NULL, &info->cred, &exp);
2485 if (ret != SEC_E_OK) break;
2487 ret = QuerySecurityPackageInfoW(scheme, &pkg_info);
2488 if (ret != SEC_E_OK) break;
2490 info->max_token = pkg_info->cbMaxToken;
2491 FreeContextBuffer(pkg_info);
2492 first = TRUE;
2494 else
2496 if (info->finished || !get_authvalue(request, creds->AuthnSchemes[0], auth_value, size)) break;
2497 if (auth_scheme_from_header(auth_value) != info->scheme)
2499 ERR("authentication scheme changed\n");
2500 break;
2503 in.BufferType = SECBUFFER_TOKEN;
2504 in.cbBuffer = 0;
2505 in.pvBuffer = NULL;
2507 in_desc.ulVersion = 0;
2508 in_desc.cBuffers = 1;
2509 in_desc.pBuffers = &in;
2511 p = auth_value + scheme_len;
2512 if (!first && *p == ' ')
2514 int len = strlenW(++p);
2515 in.cbBuffer = decode_base64(p, len, NULL);
2516 if (!(in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer))) break;
2517 decode_base64(p, len, in.pvBuffer);
2519 out.BufferType = SECBUFFER_TOKEN;
2520 out.cbBuffer = info->max_token;
2521 if (!(out.pvBuffer = HeapAlloc(GetProcessHeap(), 0, out.cbBuffer)))
2523 HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2524 break;
2526 out_desc.ulVersion = 0;
2527 out_desc.cBuffers = 1;
2528 out_desc.pBuffers = &out;
2530 ret = InitializeSecurityContextW(first ? &info->cred : NULL, first ? NULL : &info->ctx,
2531 first ? servername : NULL, flags, 0, SECURITY_NETWORK_DREP,
2532 in.pvBuffer ? &in_desc : NULL, 0, &info->ctx, &out_desc,
2533 &info->attr, &info->exp);
2534 HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2535 if (ret == SEC_E_OK)
2537 HeapFree(GetProcessHeap(), 0, info->data);
2538 info->data = out.pvBuffer;
2539 info->data_len = out.cbBuffer;
2540 info->finished = TRUE;
2541 TRACE("sending last auth packet\n");
2542 status = RPC_S_OK;
2544 else if (ret == SEC_I_CONTINUE_NEEDED)
2546 HeapFree(GetProcessHeap(), 0, info->data);
2547 info->data = out.pvBuffer;
2548 info->data_len = out.cbBuffer;
2549 TRACE("sending next auth packet\n");
2550 status = RPC_S_OK;
2552 else
2554 ERR("InitializeSecurityContextW failed with error 0x%08x\n", ret);
2555 HeapFree(GetProcessHeap(), 0, out.pvBuffer);
2556 break;
2558 info->scheme = creds->AuthnSchemes[0];
2559 break;
2561 default:
2562 FIXME("scheme %u not supported\n", creds->AuthnSchemes[0]);
2563 break;
2566 if (status != RPC_S_OK)
2568 destroy_authinfo(info);
2569 *auth_ptr = NULL;
2570 return status;
2572 *auth_ptr = info;
2573 return RPC_S_OK;
2576 static RPC_STATUS insert_authorization_header(HINTERNET request, ULONG scheme, char *data, int data_len)
2578 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '};
2579 static const WCHAR basicW[] = {'B','a','s','i','c',' '};
2580 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',' '};
2581 static const WCHAR ntlmW[] = {'N','T','L','M',' '};
2582 int scheme_len, auth_len = ARRAY_SIZE(authW), len = ((data_len + 2) * 4) / 3;
2583 const WCHAR *scheme_str;
2584 WCHAR *header, *ptr;
2585 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2587 switch (scheme)
2589 case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2590 scheme_str = basicW;
2591 scheme_len = ARRAY_SIZE(basicW);
2592 break;
2593 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2594 scheme_str = negotiateW;
2595 scheme_len = ARRAY_SIZE(negotiateW);
2596 break;
2597 case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2598 scheme_str = ntlmW;
2599 scheme_len = ARRAY_SIZE(ntlmW);
2600 break;
2601 default:
2602 ERR("unknown scheme %u\n", scheme);
2603 return RPC_S_SERVER_UNAVAILABLE;
2605 if ((header = HeapAlloc(GetProcessHeap(), 0, (auth_len + scheme_len + len + 2) * sizeof(WCHAR))))
2607 memcpy(header, authW, auth_len * sizeof(WCHAR));
2608 ptr = header + auth_len;
2609 memcpy(ptr, scheme_str, scheme_len * sizeof(WCHAR));
2610 ptr += scheme_len;
2611 len = encode_base64(data, data_len, ptr);
2612 ptr[len++] = '\r';
2613 ptr[len++] = '\n';
2614 ptr[len] = 0;
2615 if (HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE))
2616 status = RPC_S_OK;
2617 HeapFree(GetProcessHeap(), 0, header);
2619 return status;
2622 static void drain_content(HINTERNET request, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2624 DWORD count, len = 0, size = sizeof(len);
2625 char buf[2048];
2627 HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &len, &size, NULL);
2628 if (!len) return;
2629 for (;;)
2631 count = min(sizeof(buf), len);
2632 if (rpcrt4_http_async_read(request, async_data, cancel_event, buf, count) <= 0) return;
2633 len -= count;
2637 static RPC_STATUS authorize_request(RpcConnection_http *httpc, HINTERNET request)
2639 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':','\r','\n',0};
2640 struct authinfo *info = NULL;
2641 RPC_STATUS status;
2642 BOOL ret;
2644 for (;;)
2646 status = do_authorization(request, httpc->servername, httpc->common.QOS->qos->u.HttpCredentials, &info);
2647 if (status != RPC_S_OK) break;
2649 status = insert_authorization_header(request, info->scheme, info->data, info->data_len);
2650 if (status != RPC_S_OK) break;
2652 prepare_async_request(httpc->async_data);
2653 ret = HttpSendRequestW(request, NULL, 0, NULL, 0);
2654 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
2655 if (status != RPC_S_OK || info->finished) break;
2657 status = rpcrt4_http_check_response(request);
2658 if (status != RPC_S_OK && status != ERROR_ACCESS_DENIED) break;
2659 drain_content(request, httpc->async_data, httpc->cancel_event);
2662 if (info->scheme != RPC_C_HTTP_AUTHN_SCHEME_BASIC)
2663 HttpAddRequestHeadersW(request, authW, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
2665 destroy_authinfo(info);
2666 return status;
2669 static BOOL has_credentials(RpcConnection_http *httpc)
2671 RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds;
2672 SEC_WINNT_AUTH_IDENTITY_W *id;
2674 if (!httpc->common.QOS || httpc->common.QOS->qos->AdditionalSecurityInfoType != RPC_C_AUTHN_INFO_TYPE_HTTP)
2675 return FALSE;
2677 creds = httpc->common.QOS->qos->u.HttpCredentials;
2678 if (creds->AuthenticationTarget != RPC_C_HTTP_AUTHN_TARGET_SERVER || !creds->NumberOfAuthnSchemes)
2679 return FALSE;
2681 id = creds->TransportCredentials;
2682 if (!id || !id->User || !id->Password) return FALSE;
2684 return TRUE;
2687 static BOOL is_secure(RpcConnection_http *httpc)
2689 return httpc->common.QOS &&
2690 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2691 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
2694 static RPC_STATUS set_auth_cookie(RpcConnection_http *httpc, const WCHAR *value)
2696 static WCHAR httpW[] = {'h','t','t','p',0};
2697 static WCHAR httpsW[] = {'h','t','t','p','s',0};
2698 URL_COMPONENTSW uc;
2699 DWORD len;
2700 WCHAR *url;
2701 BOOL ret;
2703 if (!value) return RPC_S_OK;
2705 uc.dwStructSize = sizeof(uc);
2706 uc.lpszScheme = is_secure(httpc) ? httpsW : httpW;
2707 uc.dwSchemeLength = 0;
2708 uc.lpszHostName = httpc->servername;
2709 uc.dwHostNameLength = 0;
2710 uc.nPort = 0;
2711 uc.lpszUserName = NULL;
2712 uc.dwUserNameLength = 0;
2713 uc.lpszPassword = NULL;
2714 uc.dwPasswordLength = 0;
2715 uc.lpszUrlPath = NULL;
2716 uc.dwUrlPathLength = 0;
2717 uc.lpszExtraInfo = NULL;
2718 uc.dwExtraInfoLength = 0;
2720 if (!InternetCreateUrlW(&uc, 0, NULL, &len) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
2721 return RPC_S_SERVER_UNAVAILABLE;
2723 if (!(url = HeapAlloc(GetProcessHeap(), 0, len))) return RPC_S_OUT_OF_MEMORY;
2725 len = len / sizeof(WCHAR) - 1;
2726 if (!InternetCreateUrlW(&uc, 0, url, &len))
2728 HeapFree(GetProcessHeap(), 0, url);
2729 return RPC_S_SERVER_UNAVAILABLE;
2732 ret = InternetSetCookieW(url, NULL, value);
2733 HeapFree(GetProcessHeap(), 0, url);
2734 if (!ret) return RPC_S_SERVER_UNAVAILABLE;
2736 return RPC_S_OK;
2739 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
2741 RpcConnection_http *httpc = (RpcConnection_http *)Connection;
2742 static const WCHAR wszVerbIn[] = {'R','P','C','_','I','N','_','D','A','T','A',0};
2743 static const WCHAR wszVerbOut[] = {'R','P','C','_','O','U','T','_','D','A','T','A',0};
2744 static const WCHAR wszRpcProxyPrefix[] = {'/','r','p','c','/','r','p','c','p','r','o','x','y','.','d','l','l','?',0};
2745 static const WCHAR wszColon[] = {':',0};
2746 static const WCHAR wszAcceptType[] = {'a','p','p','l','i','c','a','t','i','o','n','/','r','p','c',0};
2747 LPCWSTR wszAcceptTypes[] = { wszAcceptType, NULL };
2748 DWORD flags;
2749 WCHAR *url;
2750 RPC_STATUS status;
2751 BOOL secure, credentials;
2752 HttpTimerThreadData *timer_data;
2753 HANDLE thread;
2755 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
2757 if (Connection->server)
2759 ERR("ncacn_http servers not supported yet\n");
2760 return RPC_S_SERVER_UNAVAILABLE;
2763 if (httpc->in_request)
2764 return RPC_S_OK;
2766 httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2768 UuidCreate(&httpc->connection_uuid);
2769 UuidCreate(&httpc->in_pipe_uuid);
2770 UuidCreate(&httpc->out_pipe_uuid);
2772 status = rpcrt4_http_internet_connect(httpc);
2773 if (status != RPC_S_OK)
2774 return status;
2776 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
2777 if (!url)
2778 return RPC_S_OUT_OF_MEMORY;
2779 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
2780 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+ARRAY_SIZE(wszRpcProxyPrefix)-1,
2781 strlen(Connection->NetworkAddr)+1);
2782 strcatW(url, wszColon);
2783 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+strlenW(url), strlen(Connection->Endpoint)+1);
2785 secure = is_secure(httpc);
2786 credentials = has_credentials(httpc);
2788 flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE |
2789 INTERNET_FLAG_NO_AUTO_REDIRECT;
2790 if (secure) flags |= INTERNET_FLAG_SECURE;
2791 if (credentials) flags |= INTERNET_FLAG_NO_AUTH;
2793 status = set_auth_cookie(httpc, Connection->CookieAuth);
2794 if (status != RPC_S_OK)
2796 HeapFree(GetProcessHeap(), 0, url);
2797 return status;
2799 httpc->in_request = HttpOpenRequestW(httpc->session, wszVerbIn, url, NULL, NULL, wszAcceptTypes,
2800 flags, (DWORD_PTR)httpc->async_data);
2801 if (!httpc->in_request)
2803 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2804 HeapFree(GetProcessHeap(), 0, url);
2805 return RPC_S_SERVER_UNAVAILABLE;
2808 if (credentials)
2810 status = authorize_request(httpc, httpc->in_request);
2811 if (status != RPC_S_OK)
2813 HeapFree(GetProcessHeap(), 0, url);
2814 return status;
2816 status = rpcrt4_http_check_response(httpc->in_request);
2817 if (status != RPC_S_OK)
2819 HeapFree(GetProcessHeap(), 0, url);
2820 return status;
2822 drain_content(httpc->in_request, httpc->async_data, httpc->cancel_event);
2825 httpc->out_request = HttpOpenRequestW(httpc->session, wszVerbOut, url, NULL, NULL, wszAcceptTypes,
2826 flags, (DWORD_PTR)httpc->async_data);
2827 HeapFree(GetProcessHeap(), 0, url);
2828 if (!httpc->out_request)
2830 ERR("HttpOpenRequestW failed with error %d\n", GetLastError());
2831 return RPC_S_SERVER_UNAVAILABLE;
2834 if (credentials)
2836 status = authorize_request(httpc, httpc->out_request);
2837 if (status != RPC_S_OK)
2838 return status;
2841 status = rpcrt4_http_prepare_in_pipe(httpc->in_request, httpc->async_data, httpc->cancel_event,
2842 &httpc->connection_uuid, &httpc->in_pipe_uuid,
2843 &Connection->assoc->http_uuid, credentials);
2844 if (status != RPC_S_OK)
2845 return status;
2847 status = rpcrt4_http_prepare_out_pipe(httpc->out_request, httpc->async_data, httpc->cancel_event,
2848 &httpc->connection_uuid, &httpc->out_pipe_uuid,
2849 &httpc->flow_control_increment, credentials);
2850 if (status != RPC_S_OK)
2851 return status;
2853 httpc->flow_control_mark = httpc->flow_control_increment / 2;
2854 httpc->last_sent_time = GetTickCount();
2855 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
2857 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
2858 if (!timer_data)
2859 return ERROR_OUTOFMEMORY;
2860 timer_data->timer_param = httpc->in_request;
2861 timer_data->last_sent_time = &httpc->last_sent_time;
2862 timer_data->timer_cancelled = httpc->timer_cancelled;
2863 /* FIXME: should use CreateTimerQueueTimer when implemented */
2864 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
2865 if (!thread)
2867 HeapFree(GetProcessHeap(), 0, timer_data);
2868 return GetLastError();
2870 CloseHandle(thread);
2872 return RPC_S_OK;
2875 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
2877 assert(0);
2878 return RPC_S_SERVER_UNAVAILABLE;
2881 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
2882 void *buffer, unsigned int count)
2884 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2885 return rpcrt4_http_async_read(httpc->out_request, httpc->async_data, httpc->cancel_event, buffer, count);
2888 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
2890 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2891 RPC_STATUS status;
2892 DWORD hdr_length;
2893 LONG dwRead;
2894 RpcPktCommonHdr common_hdr;
2896 *Header = NULL;
2898 TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
2900 again:
2901 /* read packet common header */
2902 dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
2903 if (dwRead != sizeof(common_hdr)) {
2904 WARN("Short read of header, %d bytes\n", dwRead);
2905 status = RPC_S_PROTOCOL_ERROR;
2906 goto fail;
2908 if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
2909 !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
2911 FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
2912 status = RPC_S_PROTOCOL_ERROR;
2913 goto fail;
2916 status = RPCRT4_ValidateCommonHeader(&common_hdr);
2917 if (status != RPC_S_OK) goto fail;
2919 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
2920 if (hdr_length == 0) {
2921 WARN("header length == 0\n");
2922 status = RPC_S_PROTOCOL_ERROR;
2923 goto fail;
2926 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
2927 if (!*Header)
2929 status = RPC_S_OUT_OF_RESOURCES;
2930 goto fail;
2932 memcpy(*Header, &common_hdr, sizeof(common_hdr));
2934 /* read the rest of packet header */
2935 dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
2936 if (dwRead != hdr_length - sizeof(common_hdr)) {
2937 WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length);
2938 status = RPC_S_PROTOCOL_ERROR;
2939 goto fail;
2942 if (common_hdr.frag_len - hdr_length)
2944 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
2945 if (!*Payload)
2947 status = RPC_S_OUT_OF_RESOURCES;
2948 goto fail;
2951 dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
2952 if (dwRead != common_hdr.frag_len - hdr_length)
2954 WARN("bad data length, %d/%d\n", dwRead, common_hdr.frag_len - hdr_length);
2955 status = RPC_S_PROTOCOL_ERROR;
2956 goto fail;
2959 else
2960 *Payload = NULL;
2962 if ((*Header)->common.ptype == PKT_HTTP)
2964 if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
2966 ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
2967 status = RPC_S_PROTOCOL_ERROR;
2968 goto fail;
2970 if ((*Header)->http.flags == 0x0001)
2972 TRACE("http idle packet, waiting for real packet\n");
2973 if ((*Header)->http.num_data_items != 0)
2975 ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
2976 status = RPC_S_PROTOCOL_ERROR;
2977 goto fail;
2980 else if ((*Header)->http.flags == 0x0002)
2982 ULONG bytes_transmitted;
2983 ULONG flow_control_increment;
2984 UUID pipe_uuid;
2985 status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
2986 Connection->server,
2987 &bytes_transmitted,
2988 &flow_control_increment,
2989 &pipe_uuid);
2990 if (status != RPC_S_OK)
2991 goto fail;
2992 TRACE("received http flow control header (0x%x, 0x%x, %s)\n",
2993 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
2994 /* FIXME: do something with parsed data */
2996 else
2998 FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
2999 status = RPC_S_PROTOCOL_ERROR;
3000 goto fail;
3002 RPCRT4_FreeHeader(*Header);
3003 *Header = NULL;
3004 HeapFree(GetProcessHeap(), 0, *Payload);
3005 *Payload = NULL;
3006 goto again;
3009 /* success */
3010 status = RPC_S_OK;
3012 httpc->bytes_received += common_hdr.frag_len;
3014 TRACE("httpc->bytes_received = 0x%x\n", httpc->bytes_received);
3016 if (httpc->bytes_received > httpc->flow_control_mark)
3018 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
3019 httpc->bytes_received,
3020 httpc->flow_control_increment,
3021 &httpc->out_pipe_uuid);
3022 if (hdr)
3024 DWORD bytes_written;
3025 BOOL ret2;
3026 TRACE("sending flow control packet at 0x%x\n", httpc->bytes_received);
3027 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
3028 RPCRT4_FreeHeader(hdr);
3029 if (ret2)
3030 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
3034 fail:
3035 if (status != RPC_S_OK) {
3036 RPCRT4_FreeHeader(*Header);
3037 *Header = NULL;
3038 HeapFree(GetProcessHeap(), 0, *Payload);
3039 *Payload = NULL;
3041 return status;
3044 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
3045 const void *buffer, unsigned int count)
3047 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3048 DWORD bytes_written;
3049 BOOL ret;
3051 httpc->last_sent_time = ~0U; /* disable idle packet sending */
3052 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
3053 httpc->last_sent_time = GetTickCount();
3054 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
3055 return ret ? bytes_written : -1;
3058 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
3060 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3062 TRACE("\n");
3064 SetEvent(httpc->timer_cancelled);
3065 if (httpc->in_request)
3066 InternetCloseHandle(httpc->in_request);
3067 httpc->in_request = NULL;
3068 if (httpc->out_request)
3069 InternetCloseHandle(httpc->out_request);
3070 httpc->out_request = NULL;
3071 if (httpc->app_info)
3072 InternetCloseHandle(httpc->app_info);
3073 httpc->app_info = NULL;
3074 if (httpc->session)
3075 InternetCloseHandle(httpc->session);
3076 httpc->session = NULL;
3077 RpcHttpAsyncData_Release(httpc->async_data);
3078 if (httpc->cancel_event)
3079 CloseHandle(httpc->cancel_event);
3080 HeapFree(GetProcessHeap(), 0, httpc->servername);
3081 httpc->servername = NULL;
3083 return 0;
3086 static void rpcrt4_ncacn_http_close_read(RpcConnection *conn)
3088 rpcrt4_ncacn_http_close(conn); /* FIXME */
3091 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
3093 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3095 SetEvent(httpc->cancel_event);
3098 static RPC_STATUS rpcrt4_ncacn_http_is_server_listening(const char *endpoint)
3100 FIXME("\n");
3101 return RPC_S_ACCESS_DENIED;
3104 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
3106 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3107 BOOL ret;
3108 RPC_STATUS status;
3110 prepare_async_request(httpc->async_data);
3111 ret = InternetQueryDataAvailable(httpc->out_request,
3112 &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
3113 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
3114 return status == RPC_S_OK ? 0 : -1;
3117 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
3118 const char *networkaddr,
3119 const char *endpoint)
3121 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
3122 EPM_PROTOCOL_HTTP, endpoint);
3125 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
3126 size_t tower_size,
3127 char **networkaddr,
3128 char **endpoint)
3130 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
3131 networkaddr, EPM_PROTOCOL_HTTP,
3132 endpoint);
3135 static const struct connection_ops conn_protseq_list[] = {
3136 { "ncacn_np",
3137 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
3138 rpcrt4_conn_np_alloc,
3139 rpcrt4_ncacn_np_open,
3140 rpcrt4_ncacn_np_handoff,
3141 rpcrt4_conn_np_read,
3142 rpcrt4_conn_np_write,
3143 rpcrt4_conn_np_close,
3144 rpcrt4_conn_np_close_read,
3145 rpcrt4_conn_np_cancel_call,
3146 rpcrt4_ncacn_np_is_server_listening,
3147 rpcrt4_conn_np_wait_for_incoming_data,
3148 rpcrt4_ncacn_np_get_top_of_tower,
3149 rpcrt4_ncacn_np_parse_top_of_tower,
3150 NULL,
3151 RPCRT4_default_is_authorized,
3152 RPCRT4_default_authorize,
3153 RPCRT4_default_secure_packet,
3154 rpcrt4_conn_np_impersonate_client,
3155 rpcrt4_conn_np_revert_to_self,
3156 RPCRT4_default_inquire_auth_client,
3158 { "ncalrpc",
3159 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
3160 rpcrt4_conn_np_alloc,
3161 rpcrt4_ncalrpc_open,
3162 rpcrt4_ncalrpc_handoff,
3163 rpcrt4_conn_np_read,
3164 rpcrt4_conn_np_write,
3165 rpcrt4_conn_np_close,
3166 rpcrt4_conn_np_close_read,
3167 rpcrt4_conn_np_cancel_call,
3168 rpcrt4_ncalrpc_np_is_server_listening,
3169 rpcrt4_conn_np_wait_for_incoming_data,
3170 rpcrt4_ncalrpc_get_top_of_tower,
3171 rpcrt4_ncalrpc_parse_top_of_tower,
3172 NULL,
3173 rpcrt4_ncalrpc_is_authorized,
3174 rpcrt4_ncalrpc_authorize,
3175 rpcrt4_ncalrpc_secure_packet,
3176 rpcrt4_conn_np_impersonate_client,
3177 rpcrt4_conn_np_revert_to_self,
3178 rpcrt4_ncalrpc_inquire_auth_client,
3180 { "ncacn_ip_tcp",
3181 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
3182 rpcrt4_conn_tcp_alloc,
3183 rpcrt4_ncacn_ip_tcp_open,
3184 rpcrt4_conn_tcp_handoff,
3185 rpcrt4_conn_tcp_read,
3186 rpcrt4_conn_tcp_write,
3187 rpcrt4_conn_tcp_close,
3188 rpcrt4_conn_tcp_close_read,
3189 rpcrt4_conn_tcp_cancel_call,
3190 rpcrt4_conn_tcp_is_server_listening,
3191 rpcrt4_conn_tcp_wait_for_incoming_data,
3192 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
3193 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
3194 NULL,
3195 RPCRT4_default_is_authorized,
3196 RPCRT4_default_authorize,
3197 RPCRT4_default_secure_packet,
3198 RPCRT4_default_impersonate_client,
3199 RPCRT4_default_revert_to_self,
3200 RPCRT4_default_inquire_auth_client,
3202 { "ncacn_http",
3203 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
3204 rpcrt4_ncacn_http_alloc,
3205 rpcrt4_ncacn_http_open,
3206 rpcrt4_ncacn_http_handoff,
3207 rpcrt4_ncacn_http_read,
3208 rpcrt4_ncacn_http_write,
3209 rpcrt4_ncacn_http_close,
3210 rpcrt4_ncacn_http_close_read,
3211 rpcrt4_ncacn_http_cancel_call,
3212 rpcrt4_ncacn_http_is_server_listening,
3213 rpcrt4_ncacn_http_wait_for_incoming_data,
3214 rpcrt4_ncacn_http_get_top_of_tower,
3215 rpcrt4_ncacn_http_parse_top_of_tower,
3216 rpcrt4_ncacn_http_receive_fragment,
3217 RPCRT4_default_is_authorized,
3218 RPCRT4_default_authorize,
3219 RPCRT4_default_secure_packet,
3220 RPCRT4_default_impersonate_client,
3221 RPCRT4_default_revert_to_self,
3222 RPCRT4_default_inquire_auth_client,
3227 static const struct protseq_ops protseq_list[] =
3230 "ncacn_np",
3231 rpcrt4_protseq_np_alloc,
3232 rpcrt4_protseq_np_signal_state_changed,
3233 rpcrt4_protseq_np_get_wait_array,
3234 rpcrt4_protseq_np_free_wait_array,
3235 rpcrt4_protseq_np_wait_for_new_connection,
3236 rpcrt4_protseq_ncacn_np_open_endpoint,
3239 "ncalrpc",
3240 rpcrt4_protseq_np_alloc,
3241 rpcrt4_protseq_np_signal_state_changed,
3242 rpcrt4_protseq_np_get_wait_array,
3243 rpcrt4_protseq_np_free_wait_array,
3244 rpcrt4_protseq_np_wait_for_new_connection,
3245 rpcrt4_protseq_ncalrpc_open_endpoint,
3248 "ncacn_ip_tcp",
3249 rpcrt4_protseq_sock_alloc,
3250 rpcrt4_protseq_sock_signal_state_changed,
3251 rpcrt4_protseq_sock_get_wait_array,
3252 rpcrt4_protseq_sock_free_wait_array,
3253 rpcrt4_protseq_sock_wait_for_new_connection,
3254 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
3258 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
3260 unsigned int i;
3261 for(i = 0; i < ARRAY_SIZE(protseq_list); i++)
3262 if (!strcmp(protseq_list[i].name, protseq))
3263 return &protseq_list[i];
3264 return NULL;
3267 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
3269 unsigned int i;
3270 for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++)
3271 if (!strcmp(conn_protseq_list[i].name, protseq))
3272 return &conn_protseq_list[i];
3273 return NULL;
3276 /**** interface to rest of code ****/
3278 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
3280 TRACE("(Connection == ^%p)\n", Connection);
3282 assert(!Connection->server);
3283 return Connection->ops->open_connection_client(Connection);
3286 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
3288 TRACE("(Connection == ^%p)\n", Connection);
3289 if (SecIsValidHandle(&Connection->ctx))
3291 DeleteSecurityContext(&Connection->ctx);
3292 SecInvalidateHandle(&Connection->ctx);
3294 rpcrt4_conn_close(Connection);
3295 return RPC_S_OK;
3298 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
3299 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
3300 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth)
3302 static LONG next_id;
3303 const struct connection_ops *ops;
3304 RpcConnection* NewConnection;
3306 ops = rpcrt4_get_conn_protseq_ops(Protseq);
3307 if (!ops)
3309 FIXME("not supported for protseq %s\n", Protseq);
3310 return RPC_S_PROTSEQ_NOT_SUPPORTED;
3313 NewConnection = ops->alloc();
3314 NewConnection->ref = 1;
3315 NewConnection->server = server;
3316 NewConnection->ops = ops;
3317 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
3318 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
3319 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
3320 NewConnection->CookieAuth = RPCRT4_strdupW(CookieAuth);
3321 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
3322 NewConnection->NextCallId = 1;
3324 SecInvalidateHandle(&NewConnection->ctx);
3325 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
3326 NewConnection->AuthInfo = AuthInfo;
3327 NewConnection->auth_context_id = InterlockedIncrement( &next_id );
3328 if (QOS) RpcQualityOfService_AddRef(QOS);
3329 NewConnection->QOS = QOS;
3331 list_init(&NewConnection->conn_pool_entry);
3332 list_init(&NewConnection->protseq_entry);
3334 TRACE("connection: %p\n", NewConnection);
3335 *Connection = NewConnection;
3337 return RPC_S_OK;
3340 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection)
3342 RpcConnection *connection;
3343 RPC_STATUS err;
3345 err = RPCRT4_CreateConnection(&connection, old_connection->server, rpcrt4_conn_get_name(old_connection),
3346 old_connection->NetworkAddr, old_connection->Endpoint, NULL,
3347 old_connection->AuthInfo, old_connection->QOS, old_connection->CookieAuth);
3348 if (err != RPC_S_OK)
3349 return NULL;
3351 rpcrt4_conn_handoff(old_connection, connection);
3352 if (old_connection->protseq)
3354 EnterCriticalSection(&old_connection->protseq->cs);
3355 connection->protseq = old_connection->protseq;
3356 list_add_tail(&old_connection->protseq->connections, &connection->protseq_entry);
3357 LeaveCriticalSection(&old_connection->protseq->cs);
3359 return connection;
3362 void rpcrt4_conn_release_and_wait(RpcConnection *connection)
3364 HANDLE event = NULL;
3366 if (connection->ref > 1)
3367 event = connection->wait_release = CreateEventW(NULL, TRUE, FALSE, NULL);
3369 RPCRT4_ReleaseConnection(connection);
3371 if(event)
3373 WaitForSingleObject(event, INFINITE);
3374 CloseHandle(event);
3378 RpcConnection *RPCRT4_GrabConnection(RpcConnection *connection)
3380 LONG ref = InterlockedIncrement(&connection->ref);
3381 TRACE("%p ref=%u\n", connection, ref);
3382 return connection;
3385 void RPCRT4_ReleaseConnection(RpcConnection *connection)
3387 LONG ref;
3389 /* protseq stores a list of active connections, but does not own references to them.
3390 * It may need to grab a connection from the list, which could lead to a race if
3391 * connection is being released, but not yet removed from the list. We handle that
3392 * by synchronizing on CS here. */
3393 if (connection->protseq)
3395 EnterCriticalSection(&connection->protseq->cs);
3396 ref = InterlockedDecrement(&connection->ref);
3397 if (!ref)
3398 list_remove(&connection->protseq_entry);
3399 LeaveCriticalSection(&connection->protseq->cs);
3401 else
3403 ref = InterlockedDecrement(&connection->ref);
3406 TRACE("%p ref=%u\n", connection, ref);
3408 if (!ref)
3410 RPCRT4_CloseConnection(connection);
3411 RPCRT4_strfree(connection->Endpoint);
3412 RPCRT4_strfree(connection->NetworkAddr);
3413 HeapFree(GetProcessHeap(), 0, connection->NetworkOptions);
3414 HeapFree(GetProcessHeap(), 0, connection->CookieAuth);
3415 if (connection->AuthInfo) RpcAuthInfo_Release(connection->AuthInfo);
3416 if (connection->QOS) RpcQualityOfService_Release(connection->QOS);
3418 /* server-only */
3419 if (connection->server_binding) RPCRT4_ReleaseBinding(connection->server_binding);
3420 else if (connection->assoc) RpcAssoc_ConnectionReleased(connection->assoc);
3422 if (connection->wait_release) SetEvent(connection->wait_release);
3424 HeapFree(GetProcessHeap(), 0, connection);
3428 RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint)
3430 const struct connection_ops *ops;
3432 ops = rpcrt4_get_conn_protseq_ops(protseq);
3433 if (!ops)
3435 FIXME("not supported for protseq %s\n", protseq);
3436 return RPC_S_INVALID_BINDING;
3439 return ops->is_server_listening(endpoint);
3442 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
3443 size_t *tower_size,
3444 const char *protseq,
3445 const char *networkaddr,
3446 const char *endpoint)
3448 twr_empty_floor_t *protocol_floor;
3449 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
3451 *tower_size = 0;
3453 if (!protseq_ops)
3454 return RPC_S_INVALID_RPC_PROTSEQ;
3456 if (!tower_data)
3458 *tower_size = sizeof(*protocol_floor);
3459 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
3460 return RPC_S_OK;
3463 protocol_floor = (twr_empty_floor_t *)tower_data;
3464 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
3465 protocol_floor->protid = protseq_ops->epm_protocols[0];
3466 protocol_floor->count_rhs = 0;
3468 tower_data += sizeof(*protocol_floor);
3470 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
3471 if (!*tower_size)
3472 return EPT_S_NOT_REGISTERED;
3474 *tower_size += sizeof(*protocol_floor);
3476 return RPC_S_OK;
3479 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
3480 size_t tower_size,
3481 char **protseq,
3482 char **networkaddr,
3483 char **endpoint)
3485 const twr_empty_floor_t *protocol_floor;
3486 const twr_empty_floor_t *floor4;
3487 const struct connection_ops *protseq_ops = NULL;
3488 RPC_STATUS status;
3489 unsigned int i;
3491 if (tower_size < sizeof(*protocol_floor))
3492 return EPT_S_NOT_REGISTERED;
3494 protocol_floor = (const twr_empty_floor_t *)tower_data;
3495 tower_data += sizeof(*protocol_floor);
3496 tower_size -= sizeof(*protocol_floor);
3497 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
3498 (protocol_floor->count_rhs > tower_size))
3499 return EPT_S_NOT_REGISTERED;
3500 tower_data += protocol_floor->count_rhs;
3501 tower_size -= protocol_floor->count_rhs;
3503 floor4 = (const twr_empty_floor_t *)tower_data;
3504 if ((tower_size < sizeof(*floor4)) ||
3505 (floor4->count_lhs != sizeof(floor4->protid)))
3506 return EPT_S_NOT_REGISTERED;
3508 for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++)
3509 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
3510 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
3512 protseq_ops = &conn_protseq_list[i];
3513 break;
3516 if (!protseq_ops)
3517 return EPT_S_NOT_REGISTERED;
3519 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
3521 if ((status == RPC_S_OK) && protseq)
3523 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
3524 strcpy(*protseq, protseq_ops->name);
3527 return status;
3530 /***********************************************************************
3531 * RpcNetworkIsProtseqValidW (RPCRT4.@)
3533 * Checks if the given protocol sequence is known by the RPC system.
3534 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
3537 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
3539 char ps[0x10];
3541 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
3542 ps, sizeof ps, NULL, NULL);
3543 if (rpcrt4_get_conn_protseq_ops(ps))
3544 return RPC_S_OK;
3546 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
3548 return RPC_S_INVALID_RPC_PROTSEQ;
3551 /***********************************************************************
3552 * RpcNetworkIsProtseqValidA (RPCRT4.@)
3554 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
3556 UNICODE_STRING protseqW;
3558 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
3560 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
3561 RtlFreeUnicodeString(&protseqW);
3562 return ret;
3564 return RPC_S_OUT_OF_MEMORY;
3567 /***********************************************************************
3568 * RpcProtseqVectorFreeA (RPCRT4.@)
3570 RPC_STATUS WINAPI RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA **protseqs)
3572 TRACE("(%p)\n", protseqs);
3574 if (*protseqs)
3576 unsigned int i;
3577 for (i = 0; i < (*protseqs)->Count; i++)
3578 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3579 HeapFree(GetProcessHeap(), 0, *protseqs);
3580 *protseqs = NULL;
3582 return RPC_S_OK;
3585 /***********************************************************************
3586 * RpcProtseqVectorFreeW (RPCRT4.@)
3588 RPC_STATUS WINAPI RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW **protseqs)
3590 TRACE("(%p)\n", protseqs);
3592 if (*protseqs)
3594 unsigned int i;
3595 for (i = 0; i < (*protseqs)->Count; i++)
3596 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3597 HeapFree(GetProcessHeap(), 0, *protseqs);
3598 *protseqs = NULL;
3600 return RPC_S_OK;
3603 /***********************************************************************
3604 * RpcNetworkInqProtseqsW (RPCRT4.@)
3606 RPC_STATUS WINAPI RpcNetworkInqProtseqsW( RPC_PROTSEQ_VECTORW** protseqs )
3608 RPC_PROTSEQ_VECTORW *pvector;
3609 unsigned int i;
3610 RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3612 TRACE("(%p)\n", protseqs);
3614 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned short*)*ARRAY_SIZE(protseq_list)));
3615 if (!*protseqs)
3616 goto end;
3617 pvector = *protseqs;
3618 pvector->Count = 0;
3619 for (i = 0; i < ARRAY_SIZE(protseq_list); i++)
3621 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, (strlen(protseq_list[i].name)+1)*sizeof(unsigned short));
3622 if (pvector->Protseq[i] == NULL)
3623 goto end;
3624 MultiByteToWideChar(CP_ACP, 0, (CHAR*)protseq_list[i].name, -1,
3625 (WCHAR*)pvector->Protseq[i], strlen(protseq_list[i].name) + 1);
3626 pvector->Count++;
3628 status = RPC_S_OK;
3630 end:
3631 if (status != RPC_S_OK)
3632 RpcProtseqVectorFreeW(protseqs);
3633 return status;
3636 /***********************************************************************
3637 * RpcNetworkInqProtseqsA (RPCRT4.@)
3639 RPC_STATUS WINAPI RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** protseqs)
3641 RPC_PROTSEQ_VECTORA *pvector;
3642 unsigned int i;
3643 RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3645 TRACE("(%p)\n", protseqs);
3647 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned char*)*ARRAY_SIZE(protseq_list)));
3648 if (!*protseqs)
3649 goto end;
3650 pvector = *protseqs;
3651 pvector->Count = 0;
3652 for (i = 0; i < ARRAY_SIZE(protseq_list); i++)
3654 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_list[i].name)+1);
3655 if (pvector->Protseq[i] == NULL)
3656 goto end;
3657 strcpy((char*)pvector->Protseq[i], protseq_list[i].name);
3658 pvector->Count++;
3660 status = RPC_S_OK;
3662 end:
3663 if (status != RPC_S_OK)
3664 RpcProtseqVectorFreeA(protseqs);
3665 return status;