dwmapi: Clear DWM_TIMING_INFO structure before returning.
[wine.git] / dlls / rpcrt4 / rpc_transport.c
blob82798a5a80def9db097627b65ed140176e390e6f
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"
43 #include "rpc.h"
44 #include "rpcndr.h"
46 #include "wine/debug.h"
48 #include "rpc_binding.h"
49 #include "rpc_assoc.h"
50 #include "rpc_message.h"
51 #include "rpc_server.h"
52 #include "epm_towers.h"
54 #define DEFAULT_NCACN_HTTP_TIMEOUT (60 * 1000)
56 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
58 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection);
60 /**** ncacn_np support ****/
62 typedef struct _RpcConnection_np
64 RpcConnection common;
65 HANDLE pipe;
66 HANDLE listen_event;
67 char *listen_pipe;
68 IO_STATUS_BLOCK io_status;
69 HANDLE event_cache;
70 BOOL read_closed;
71 } RpcConnection_np;
73 static RpcConnection *rpcrt4_conn_np_alloc(void)
75 RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_np));
76 return &npc->common;
79 static HANDLE get_np_event(RpcConnection_np *connection)
81 HANDLE event = InterlockedExchangePointer(&connection->event_cache, NULL);
82 return event ? event : CreateEventW(NULL, TRUE, FALSE, NULL);
85 static void release_np_event(RpcConnection_np *connection, HANDLE event)
87 event = InterlockedExchangePointer(&connection->event_cache, event);
88 if (event)
89 CloseHandle(event);
92 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *conn)
94 RpcConnection_np *connection = (RpcConnection_np *) conn;
96 TRACE("listening on %s\n", connection->listen_pipe);
98 connection->pipe = CreateNamedPipeA(connection->listen_pipe, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
99 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
100 PIPE_UNLIMITED_INSTANCES,
101 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
102 if (connection->pipe == INVALID_HANDLE_VALUE)
104 WARN("CreateNamedPipe failed with error %ld\n", GetLastError());
105 if (GetLastError() == ERROR_FILE_EXISTS)
106 return RPC_S_DUPLICATE_ENDPOINT;
107 else
108 return RPC_S_CANT_CREATE_ENDPOINT;
111 return RPC_S_OK;
114 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
116 RpcConnection_np *npc = (RpcConnection_np *) Connection;
117 HANDLE pipe;
118 DWORD err, dwMode;
120 TRACE("connecting to %s\n", pname);
122 while (TRUE) {
123 DWORD dwFlags = 0;
124 if (Connection->QOS)
126 dwFlags = SECURITY_SQOS_PRESENT;
127 switch (Connection->QOS->qos->ImpersonationType)
129 case RPC_C_IMP_LEVEL_DEFAULT:
130 /* FIXME: what to do here? */
131 break;
132 case RPC_C_IMP_LEVEL_ANONYMOUS:
133 dwFlags |= SECURITY_ANONYMOUS;
134 break;
135 case RPC_C_IMP_LEVEL_IDENTIFY:
136 dwFlags |= SECURITY_IDENTIFICATION;
137 break;
138 case RPC_C_IMP_LEVEL_IMPERSONATE:
139 dwFlags |= SECURITY_IMPERSONATION;
140 break;
141 case RPC_C_IMP_LEVEL_DELEGATE:
142 dwFlags |= SECURITY_DELEGATION;
143 break;
145 if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTITY_DYNAMIC)
146 dwFlags |= SECURITY_CONTEXT_TRACKING;
148 pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
149 OPEN_EXISTING, dwFlags | FILE_FLAG_OVERLAPPED, 0);
150 if (pipe != INVALID_HANDLE_VALUE) break;
151 err = GetLastError();
152 if (err == ERROR_PIPE_BUSY) {
153 if (WaitNamedPipeA(pname, NMPWAIT_USE_DEFAULT_WAIT)) {
154 TRACE("retrying busy server\n");
155 continue;
157 TRACE("connection failed, error=%lx\n", err);
158 return RPC_S_SERVER_TOO_BUSY;
160 if (!wait || !WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
161 err = GetLastError();
162 WARN("connection failed, error=%lx\n", err);
163 return RPC_S_SERVER_UNAVAILABLE;
167 /* success */
168 /* pipe is connected; change to message-read mode. */
169 dwMode = PIPE_READMODE_MESSAGE;
170 SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
171 npc->pipe = pipe;
173 return RPC_S_OK;
176 static char *ncalrpc_pipe_name(const char *endpoint)
178 static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
179 char *pipe_name;
181 /* protseq=ncalrpc: supposed to use NT LPC ports,
182 * but we'll implement it with named pipes for now */
183 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint));
184 strcat(strcpy(pipe_name, prefix), endpoint);
185 return pipe_name;
188 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
190 RpcConnection_np *npc = (RpcConnection_np *) Connection;
191 RPC_STATUS r;
192 LPSTR pname;
194 /* already connected? */
195 if (npc->pipe)
196 return RPC_S_OK;
198 pname = ncalrpc_pipe_name(Connection->Endpoint);
199 r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
200 I_RpcFree(pname);
202 return r;
205 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, const char *endpoint)
207 RPC_STATUS r;
208 RpcConnection *Connection;
209 char generated_endpoint[22];
211 if (!endpoint)
213 static LONG lrpc_nameless_id;
214 DWORD process_id = GetCurrentProcessId();
215 ULONG id = InterlockedIncrement(&lrpc_nameless_id);
216 snprintf(generated_endpoint, sizeof(generated_endpoint),
217 "LRPC%08lx.%08lx", process_id, id);
218 endpoint = generated_endpoint;
221 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
222 endpoint, NULL, NULL, NULL, NULL);
223 if (r != RPC_S_OK)
224 return r;
226 ((RpcConnection_np*)Connection)->listen_pipe = ncalrpc_pipe_name(Connection->Endpoint);
227 r = rpcrt4_conn_create_pipe(Connection);
229 EnterCriticalSection(&protseq->cs);
230 list_add_head(&protseq->listeners, &Connection->protseq_entry);
231 Connection->protseq = protseq;
232 LeaveCriticalSection(&protseq->cs);
234 return r;
237 static char *ncacn_pipe_name(const char *endpoint)
239 static const char prefix[] = "\\\\.";
240 char *pipe_name;
242 /* protseq=ncacn_np: named pipes */
243 pipe_name = I_RpcAllocate(sizeof(prefix) + strlen(endpoint));
244 strcat(strcpy(pipe_name, prefix), endpoint);
245 return pipe_name;
248 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
250 RpcConnection_np *npc = (RpcConnection_np *) Connection;
251 RPC_STATUS r;
252 LPSTR pname;
254 /* already connected? */
255 if (npc->pipe)
256 return RPC_S_OK;
258 pname = ncacn_pipe_name(Connection->Endpoint);
259 r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
260 I_RpcFree(pname);
262 return r;
265 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
267 RPC_STATUS r;
268 RpcConnection *Connection;
269 char generated_endpoint[26];
271 if (!endpoint)
273 static LONG np_nameless_id;
274 DWORD process_id = GetCurrentProcessId();
275 ULONG id = InterlockedExchangeAdd(&np_nameless_id, 1 );
276 snprintf(generated_endpoint, sizeof(generated_endpoint),
277 "\\\\pipe\\\\%08lx.%03lx", process_id, id);
278 endpoint = generated_endpoint;
281 r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
282 endpoint, NULL, NULL, NULL, NULL);
283 if (r != RPC_S_OK)
284 return r;
286 ((RpcConnection_np*)Connection)->listen_pipe = ncacn_pipe_name(Connection->Endpoint);
287 r = rpcrt4_conn_create_pipe(Connection);
289 EnterCriticalSection(&protseq->cs);
290 list_add_head(&protseq->listeners, &Connection->protseq_entry);
291 Connection->protseq = protseq;
292 LeaveCriticalSection(&protseq->cs);
294 return r;
297 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
299 /* because of the way named pipes work, we'll transfer the connected pipe
300 * to the child, then reopen the server binding to continue listening */
302 new_npc->pipe = old_npc->pipe;
303 old_npc->pipe = 0;
304 assert(!old_npc->listen_event);
307 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
309 DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
310 RPC_STATUS status;
312 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
313 status = rpcrt4_conn_create_pipe(old_conn);
315 /* Store the local computer name as the NetworkAddr for ncacn_np as long as
316 * we don't support named pipes over the network. */
317 new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len);
318 if (!GetComputerNameA(new_conn->NetworkAddr, &len))
320 ERR("Failed to retrieve the computer name, error %lu\n", GetLastError());
321 return RPC_S_OUT_OF_RESOURCES;
324 return status;
327 static RPC_STATUS is_pipe_listening(const char *pipe_name)
329 return WaitNamedPipeA(pipe_name, 1) ? RPC_S_OK : RPC_S_NOT_LISTENING;
332 static RPC_STATUS rpcrt4_ncacn_np_is_server_listening(const char *endpoint)
334 char *pipe_name;
335 RPC_STATUS status;
337 pipe_name = ncacn_pipe_name(endpoint);
338 status = is_pipe_listening(pipe_name);
339 I_RpcFree(pipe_name);
340 return status;
343 static RPC_STATUS rpcrt4_ncalrpc_np_is_server_listening(const char *endpoint)
345 char *pipe_name;
346 RPC_STATUS status;
348 pipe_name = ncalrpc_pipe_name(endpoint);
349 status = is_pipe_listening(pipe_name);
350 I_RpcFree(pipe_name);
351 return status;
354 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
356 DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
357 RPC_STATUS status;
359 TRACE("%s\n", old_conn->Endpoint);
361 rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
362 status = rpcrt4_conn_create_pipe(old_conn);
364 /* Store the local computer name as the NetworkAddr for ncalrpc. */
365 new_conn->NetworkAddr = HeapAlloc(GetProcessHeap(), 0, len);
366 if (!GetComputerNameA(new_conn->NetworkAddr, &len))
368 ERR("Failed to retrieve the computer name, error %lu\n", GetLastError());
369 return RPC_S_OUT_OF_RESOURCES;
372 return status;
375 static int rpcrt4_conn_np_read(RpcConnection *conn, void *buffer, unsigned int count)
377 RpcConnection_np *connection = (RpcConnection_np *) conn;
378 HANDLE event;
379 NTSTATUS status;
381 event = get_np_event(connection);
382 if (!event)
383 return -1;
385 if (connection->read_closed)
386 status = STATUS_CANCELLED;
387 else
388 status = NtReadFile(connection->pipe, event, NULL, NULL, &connection->io_status, buffer, count, NULL, NULL);
389 if (status == STATUS_PENDING)
391 /* check read_closed again before waiting to avoid a race */
392 if (connection->read_closed)
394 IO_STATUS_BLOCK io_status;
395 NtCancelIoFileEx(connection->pipe, &connection->io_status, &io_status);
397 WaitForSingleObject(event, INFINITE);
398 status = connection->io_status.Status;
400 release_np_event(connection, event);
401 return status && status != STATUS_BUFFER_OVERFLOW ? -1 : connection->io_status.Information;
404 static int rpcrt4_conn_np_write(RpcConnection *conn, const void *buffer, unsigned int count)
406 RpcConnection_np *connection = (RpcConnection_np *) conn;
407 IO_STATUS_BLOCK io_status;
408 HANDLE event;
409 NTSTATUS status;
411 event = get_np_event(connection);
412 if (!event)
413 return -1;
415 status = NtWriteFile(connection->pipe, event, NULL, NULL, &io_status, buffer, count, NULL, NULL);
416 if (status == STATUS_PENDING)
418 WaitForSingleObject(event, INFINITE);
419 status = io_status.Status;
421 release_np_event(connection, event);
422 if (status)
423 return -1;
425 assert(io_status.Information == count);
426 return count;
429 static int rpcrt4_conn_np_close(RpcConnection *conn)
431 RpcConnection_np *connection = (RpcConnection_np *) conn;
432 if (connection->pipe)
434 FlushFileBuffers(connection->pipe);
435 CloseHandle(connection->pipe);
436 connection->pipe = 0;
438 if (connection->listen_event)
440 CloseHandle(connection->listen_event);
441 connection->listen_event = 0;
443 if (connection->event_cache)
445 CloseHandle(connection->event_cache);
446 connection->event_cache = 0;
448 return 0;
451 static void rpcrt4_conn_np_close_read(RpcConnection *conn)
453 RpcConnection_np *connection = (RpcConnection_np*)conn;
454 IO_STATUS_BLOCK io_status;
456 connection->read_closed = TRUE;
457 NtCancelIoFileEx(connection->pipe, &connection->io_status, &io_status);
460 static void rpcrt4_conn_np_cancel_call(RpcConnection *conn)
462 RpcConnection_np *connection = (RpcConnection_np *)conn;
463 CancelIoEx(connection->pipe, NULL);
466 static int rpcrt4_conn_np_wait_for_incoming_data(RpcConnection *conn)
468 return rpcrt4_conn_np_read(conn, NULL, 0);
471 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
472 const char *networkaddr,
473 const char *endpoint)
475 twr_empty_floor_t *smb_floor;
476 twr_empty_floor_t *nb_floor;
477 size_t size;
478 size_t networkaddr_size;
479 size_t endpoint_size;
481 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
483 networkaddr_size = networkaddr ? strlen(networkaddr) + 1 : 1;
484 endpoint_size = endpoint ? strlen(endpoint) + 1 : 1;
485 size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
487 if (!tower_data)
488 return size;
490 smb_floor = (twr_empty_floor_t *)tower_data;
492 tower_data += sizeof(*smb_floor);
494 smb_floor->count_lhs = sizeof(smb_floor->protid);
495 smb_floor->protid = EPM_PROTOCOL_SMB;
496 smb_floor->count_rhs = endpoint_size;
498 if (endpoint)
499 memcpy(tower_data, endpoint, endpoint_size);
500 else
501 tower_data[0] = 0;
502 tower_data += endpoint_size;
504 nb_floor = (twr_empty_floor_t *)tower_data;
506 tower_data += sizeof(*nb_floor);
508 nb_floor->count_lhs = sizeof(nb_floor->protid);
509 nb_floor->protid = EPM_PROTOCOL_NETBIOS;
510 nb_floor->count_rhs = networkaddr_size;
512 if (networkaddr)
513 memcpy(tower_data, networkaddr, networkaddr_size);
514 else
515 tower_data[0] = 0;
517 return size;
520 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
521 size_t tower_size,
522 char **networkaddr,
523 char **endpoint)
525 const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
526 const twr_empty_floor_t *nb_floor;
528 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
530 if (tower_size < sizeof(*smb_floor))
531 return EPT_S_NOT_REGISTERED;
533 tower_data += sizeof(*smb_floor);
534 tower_size -= sizeof(*smb_floor);
536 if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
537 (smb_floor->protid != EPM_PROTOCOL_SMB) ||
538 (smb_floor->count_rhs > tower_size) ||
539 (tower_data[smb_floor->count_rhs - 1] != '\0'))
540 return EPT_S_NOT_REGISTERED;
542 if (endpoint)
544 *endpoint = I_RpcAllocate(smb_floor->count_rhs);
545 if (!*endpoint)
546 return RPC_S_OUT_OF_RESOURCES;
547 memcpy(*endpoint, tower_data, smb_floor->count_rhs);
549 tower_data += smb_floor->count_rhs;
550 tower_size -= smb_floor->count_rhs;
552 if (tower_size < sizeof(*nb_floor))
553 return EPT_S_NOT_REGISTERED;
555 nb_floor = (const twr_empty_floor_t *)tower_data;
557 tower_data += sizeof(*nb_floor);
558 tower_size -= sizeof(*nb_floor);
560 if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
561 (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
562 (nb_floor->count_rhs > tower_size) ||
563 (tower_data[nb_floor->count_rhs - 1] != '\0'))
564 return EPT_S_NOT_REGISTERED;
566 if (networkaddr)
568 *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
569 if (!*networkaddr)
571 if (endpoint)
573 I_RpcFree(*endpoint);
574 *endpoint = NULL;
576 return RPC_S_OUT_OF_RESOURCES;
578 memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
581 return RPC_S_OK;
584 static RPC_STATUS rpcrt4_conn_np_impersonate_client(RpcConnection *conn)
586 RpcConnection_np *npc = (RpcConnection_np *)conn;
587 BOOL ret;
589 TRACE("(%p)\n", conn);
591 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
592 return RPCRT4_default_impersonate_client(conn);
594 ret = ImpersonateNamedPipeClient(npc->pipe);
595 if (!ret)
597 DWORD error = GetLastError();
598 WARN("ImpersonateNamedPipeClient failed with error %lu\n", error);
599 switch (error)
601 case ERROR_CANNOT_IMPERSONATE:
602 return RPC_S_NO_CONTEXT_AVAILABLE;
605 return RPC_S_OK;
608 static RPC_STATUS rpcrt4_conn_np_revert_to_self(RpcConnection *conn)
610 BOOL ret;
612 TRACE("(%p)\n", conn);
614 if (conn->AuthInfo && SecIsValidHandle(&conn->ctx))
615 return RPCRT4_default_revert_to_self(conn);
617 ret = RevertToSelf();
618 if (!ret)
620 WARN("RevertToSelf failed with error %lu\n", GetLastError());
621 return RPC_S_NO_CONTEXT_AVAILABLE;
623 return RPC_S_OK;
626 typedef struct _RpcServerProtseq_np
628 RpcServerProtseq common;
629 HANDLE mgr_event;
630 } RpcServerProtseq_np;
632 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
634 RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps));
635 if (ps)
636 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
637 return &ps->common;
640 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
642 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
643 SetEvent(npps->mgr_event);
646 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
648 HANDLE *objs = prev_array;
649 RpcConnection_np *conn;
650 RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
652 EnterCriticalSection(&protseq->cs);
654 /* open and count connections */
655 *count = 1;
656 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
658 if (!conn->pipe && rpcrt4_conn_create_pipe(&conn->common) != RPC_S_OK)
659 continue;
660 if (!conn->listen_event)
662 NTSTATUS status;
663 HANDLE event;
665 event = get_np_event(conn);
666 if (!event)
667 continue;
669 status = NtFsControlFile(conn->pipe, event, NULL, NULL, &conn->io_status, FSCTL_PIPE_LISTEN, NULL, 0, NULL, 0);
670 switch (status)
672 case STATUS_SUCCESS:
673 case STATUS_PIPE_CONNECTED:
674 conn->io_status.Status = status;
675 SetEvent(event);
676 break;
677 case STATUS_PENDING:
678 break;
679 default:
680 ERR("pipe listen error %lx\n", status);
681 continue;
684 conn->listen_event = event;
686 (*count)++;
689 /* make array of connections */
690 if (objs)
691 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
692 else
693 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
694 if (!objs)
696 ERR("couldn't allocate objs\n");
697 LeaveCriticalSection(&protseq->cs);
698 return NULL;
701 objs[0] = npps->mgr_event;
702 *count = 1;
703 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
705 if (conn->listen_event)
706 objs[(*count)++] = conn->listen_event;
708 LeaveCriticalSection(&protseq->cs);
709 return objs;
712 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
714 HeapFree(GetProcessHeap(), 0, array);
717 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
719 HANDLE b_handle;
720 HANDLE *objs = wait_array;
721 DWORD res;
722 RpcConnection *cconn = NULL;
723 RpcConnection_np *conn;
725 if (!objs)
726 return -1;
730 /* an alertable wait isn't strictly necessary, but due to our
731 * overlapped I/O implementation in Wine we need to free some memory
732 * by the file user APC being called, even if no completion routine was
733 * specified at the time of starting the async operation */
734 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
735 } while (res == WAIT_IO_COMPLETION);
737 if (res == WAIT_OBJECT_0)
738 return 0;
739 else if (res == WAIT_FAILED)
741 ERR("wait failed with error %ld\n", GetLastError());
742 return -1;
744 else
746 b_handle = objs[res - WAIT_OBJECT_0];
747 /* find which connection got a RPC */
748 EnterCriticalSection(&protseq->cs);
749 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_np, common.protseq_entry)
751 if (b_handle == conn->listen_event)
753 release_np_event(conn, conn->listen_event);
754 conn->listen_event = NULL;
755 if (conn->io_status.Status == STATUS_SUCCESS || conn->io_status.Status == STATUS_PIPE_CONNECTED)
756 cconn = rpcrt4_spawn_connection(&conn->common);
757 else
758 ERR("listen failed %lx\n", conn->io_status.Status);
759 break;
762 LeaveCriticalSection(&protseq->cs);
763 if (!cconn)
765 ERR("failed to locate connection for handle %p\n", b_handle);
766 return -1;
768 RPCRT4_new_client(cconn);
769 return 1;
773 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
774 const char *networkaddr,
775 const char *endpoint)
777 twr_empty_floor_t *pipe_floor;
778 size_t size;
779 size_t endpoint_size;
781 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
783 endpoint_size = strlen(endpoint) + 1;
784 size = sizeof(*pipe_floor) + endpoint_size;
786 if (!tower_data)
787 return size;
789 pipe_floor = (twr_empty_floor_t *)tower_data;
791 tower_data += sizeof(*pipe_floor);
793 pipe_floor->count_lhs = sizeof(pipe_floor->protid);
794 pipe_floor->protid = EPM_PROTOCOL_PIPE;
795 pipe_floor->count_rhs = endpoint_size;
797 memcpy(tower_data, endpoint, endpoint_size);
799 return size;
802 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
803 size_t tower_size,
804 char **networkaddr,
805 char **endpoint)
807 const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
809 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
811 if (tower_size < sizeof(*pipe_floor))
812 return EPT_S_NOT_REGISTERED;
814 tower_data += sizeof(*pipe_floor);
815 tower_size -= sizeof(*pipe_floor);
817 if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
818 (pipe_floor->protid != EPM_PROTOCOL_PIPE) ||
819 (pipe_floor->count_rhs > tower_size) ||
820 (tower_data[pipe_floor->count_rhs - 1] != '\0'))
821 return EPT_S_NOT_REGISTERED;
823 if (networkaddr)
824 *networkaddr = NULL;
826 if (endpoint)
828 *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
829 if (!*endpoint)
830 return RPC_S_OUT_OF_RESOURCES;
831 memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
834 return RPC_S_OK;
837 static BOOL rpcrt4_ncalrpc_is_authorized(RpcConnection *conn)
839 return FALSE;
842 static RPC_STATUS rpcrt4_ncalrpc_authorize(RpcConnection *conn, BOOL first_time,
843 unsigned char *in_buffer,
844 unsigned int in_size,
845 unsigned char *out_buffer,
846 unsigned int *out_size)
848 /* since this protocol is local to the machine there is no need to
849 * authenticate the caller */
850 *out_size = 0;
851 return RPC_S_OK;
854 static RPC_STATUS rpcrt4_ncalrpc_secure_packet(RpcConnection *conn,
855 enum secure_packet_direction dir,
856 RpcPktHdr *hdr, unsigned int hdr_size,
857 unsigned char *stub_data, unsigned int stub_data_size,
858 RpcAuthVerifier *auth_hdr,
859 unsigned char *auth_value, unsigned int auth_value_size)
861 /* since this protocol is local to the machine there is no need to secure
862 * the packet */
863 return RPC_S_OK;
866 static RPC_STATUS rpcrt4_ncalrpc_inquire_auth_client(
867 RpcConnection *conn, RPC_AUTHZ_HANDLE *privs, RPC_WSTR *server_princ_name,
868 ULONG *authn_level, ULONG *authn_svc, ULONG *authz_svc, ULONG flags)
870 TRACE("(%p, %p, %p, %p, %p, %p, 0x%lx)\n", conn, privs,
871 server_princ_name, authn_level, authn_svc, authz_svc, flags);
873 if (privs)
875 FIXME("privs not implemented\n");
876 *privs = NULL;
878 if (server_princ_name)
880 FIXME("server_princ_name not implemented\n");
881 *server_princ_name = NULL;
883 if (authn_level) *authn_level = RPC_C_AUTHN_LEVEL_PKT_PRIVACY;
884 if (authn_svc) *authn_svc = RPC_C_AUTHN_WINNT;
885 if (authz_svc)
887 FIXME("authorization service not implemented\n");
888 *authz_svc = RPC_C_AUTHZ_NONE;
890 if (flags)
891 FIXME("flags 0x%lx not implemented\n", flags);
893 return RPC_S_OK;
896 /**** ncacn_ip_tcp support ****/
898 static size_t rpcrt4_ip_tcp_get_top_of_tower(unsigned char *tower_data,
899 const char *networkaddr,
900 unsigned char tcp_protid,
901 const char *endpoint)
903 twr_tcp_floor_t *tcp_floor;
904 twr_ipv4_floor_t *ipv4_floor;
905 struct addrinfo *ai;
906 struct addrinfo hints;
907 int ret;
908 size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
910 TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
912 if (!tower_data)
913 return size;
915 tcp_floor = (twr_tcp_floor_t *)tower_data;
916 tower_data += sizeof(*tcp_floor);
918 ipv4_floor = (twr_ipv4_floor_t *)tower_data;
920 tcp_floor->count_lhs = sizeof(tcp_floor->protid);
921 tcp_floor->protid = tcp_protid;
922 tcp_floor->count_rhs = sizeof(tcp_floor->port);
924 ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
925 ipv4_floor->protid = EPM_PROTOCOL_IP;
926 ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
928 hints.ai_flags = AI_NUMERICHOST;
929 /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
930 hints.ai_family = PF_INET;
931 hints.ai_socktype = SOCK_STREAM;
932 hints.ai_protocol = IPPROTO_TCP;
933 hints.ai_addrlen = 0;
934 hints.ai_addr = NULL;
935 hints.ai_canonname = NULL;
936 hints.ai_next = NULL;
938 ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
939 if (ret)
941 ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
942 if (ret)
944 ERR("getaddrinfo failed, error %u\n", WSAGetLastError());
945 return 0;
949 if (ai->ai_family == PF_INET)
951 const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
952 tcp_floor->port = sin->sin_port;
953 ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
955 else
957 ERR("unexpected protocol family %d\n", ai->ai_family);
958 freeaddrinfo(ai);
959 return 0;
962 freeaddrinfo(ai);
964 return size;
967 static RPC_STATUS rpcrt4_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
968 size_t tower_size,
969 char **networkaddr,
970 unsigned char tcp_protid,
971 char **endpoint)
973 const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
974 const twr_ipv4_floor_t *ipv4_floor;
975 struct in_addr in_addr;
977 TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
979 if (tower_size < sizeof(*tcp_floor))
980 return EPT_S_NOT_REGISTERED;
982 tower_data += sizeof(*tcp_floor);
983 tower_size -= sizeof(*tcp_floor);
985 if (tower_size < sizeof(*ipv4_floor))
986 return EPT_S_NOT_REGISTERED;
988 ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
990 if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
991 (tcp_floor->protid != tcp_protid) ||
992 (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
993 (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
994 (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
995 (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
996 return EPT_S_NOT_REGISTERED;
998 if (endpoint)
1000 *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1001 if (!*endpoint)
1002 return RPC_S_OUT_OF_RESOURCES;
1003 sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1006 if (networkaddr)
1008 *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1009 if (!*networkaddr)
1011 if (endpoint)
1013 I_RpcFree(*endpoint);
1014 *endpoint = NULL;
1016 return RPC_S_OUT_OF_RESOURCES;
1018 in_addr.s_addr = ipv4_floor->ipv4addr;
1019 if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1021 ERR("inet_ntop: %u\n", WSAGetLastError());
1022 I_RpcFree(*networkaddr);
1023 *networkaddr = NULL;
1024 if (endpoint)
1026 I_RpcFree(*endpoint);
1027 *endpoint = NULL;
1029 return EPT_S_NOT_REGISTERED;
1033 return RPC_S_OK;
1036 typedef struct _RpcConnection_tcp
1038 RpcConnection common;
1039 int sock;
1040 HANDLE sock_event;
1041 HANDLE cancel_event;
1042 } RpcConnection_tcp;
1044 static BOOL rpcrt4_sock_wait_init(RpcConnection_tcp *tcpc)
1046 static BOOL wsa_inited;
1047 if (!wsa_inited)
1049 WSADATA wsadata;
1050 WSAStartup(MAKEWORD(2, 2), &wsadata);
1051 /* Note: WSAStartup can be called more than once so we don't bother with
1052 * making accesses to wsa_inited thread-safe */
1053 wsa_inited = TRUE;
1055 tcpc->sock_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1056 tcpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1057 if (!tcpc->sock_event || !tcpc->cancel_event)
1059 ERR("event creation failed\n");
1060 if (tcpc->sock_event) CloseHandle(tcpc->sock_event);
1061 return FALSE;
1063 return TRUE;
1066 static BOOL rpcrt4_sock_wait_for_recv(RpcConnection_tcp *tcpc)
1068 HANDLE wait_handles[2];
1069 DWORD res;
1070 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1072 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1073 return FALSE;
1075 wait_handles[0] = tcpc->sock_event;
1076 wait_handles[1] = tcpc->cancel_event;
1077 res = WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE);
1078 switch (res)
1080 case WAIT_OBJECT_0:
1081 return TRUE;
1082 case WAIT_OBJECT_0 + 1:
1083 return FALSE;
1084 default:
1085 ERR("WaitForMultipleObjects() failed with error %ld\n", GetLastError());
1086 return FALSE;
1090 static BOOL rpcrt4_sock_wait_for_send(RpcConnection_tcp *tcpc)
1092 DWORD res;
1093 if (WSAEventSelect(tcpc->sock, tcpc->sock_event, FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1095 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1096 return FALSE;
1098 res = WaitForSingleObject(tcpc->sock_event, INFINITE);
1099 switch (res)
1101 case WAIT_OBJECT_0:
1102 return TRUE;
1103 default:
1104 ERR("WaitForMultipleObjects() failed with error %ld\n", GetLastError());
1105 return FALSE;
1109 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
1111 RpcConnection_tcp *tcpc;
1112 tcpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection_tcp));
1113 if (tcpc == NULL)
1114 return NULL;
1115 tcpc->sock = -1;
1116 if (!rpcrt4_sock_wait_init(tcpc))
1118 HeapFree(GetProcessHeap(), 0, tcpc);
1119 return NULL;
1121 return &tcpc->common;
1124 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
1126 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1127 int sock;
1128 int ret;
1129 struct addrinfo *ai;
1130 struct addrinfo *ai_cur;
1131 struct addrinfo hints;
1133 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
1135 if (tcpc->sock != -1)
1136 return RPC_S_OK;
1138 hints.ai_flags = 0;
1139 hints.ai_family = PF_UNSPEC;
1140 hints.ai_socktype = SOCK_STREAM;
1141 hints.ai_protocol = IPPROTO_TCP;
1142 hints.ai_addrlen = 0;
1143 hints.ai_addr = NULL;
1144 hints.ai_canonname = NULL;
1145 hints.ai_next = NULL;
1147 ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
1148 if (ret)
1150 ERR("getaddrinfo for %s:%s failed, error %u\n", Connection->NetworkAddr,
1151 Connection->Endpoint, WSAGetLastError());
1152 return RPC_S_SERVER_UNAVAILABLE;
1155 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1157 int val;
1158 u_long nonblocking;
1160 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1162 TRACE("skipping non-IP/IPv6 address family\n");
1163 continue;
1166 if (TRACE_ON(rpc))
1168 char host[256];
1169 char service[256];
1170 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1171 host, sizeof(host), service, sizeof(service),
1172 NI_NUMERICHOST | NI_NUMERICSERV);
1173 TRACE("trying %s:%s\n", host, service);
1176 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1177 if (sock == -1)
1179 WARN("socket() failed: %u\n", WSAGetLastError());
1180 continue;
1183 if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
1185 WARN("connect() failed: %u\n", WSAGetLastError());
1186 closesocket(sock);
1187 continue;
1190 /* RPC depends on having minimal latency so disable the Nagle algorithm */
1191 val = 1;
1192 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
1193 nonblocking = 1;
1194 ioctlsocket(sock, FIONBIO, &nonblocking);
1196 tcpc->sock = sock;
1198 freeaddrinfo(ai);
1199 TRACE("connected\n");
1200 return RPC_S_OK;
1203 freeaddrinfo(ai);
1204 ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
1205 return RPC_S_SERVER_UNAVAILABLE;
1208 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, const char *endpoint)
1210 RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
1211 int sock;
1212 int ret;
1213 struct addrinfo *ai;
1214 struct addrinfo *ai_cur;
1215 struct addrinfo hints;
1217 TRACE("(%p, %s)\n", protseq, endpoint);
1219 hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */;
1220 hints.ai_family = PF_UNSPEC;
1221 hints.ai_socktype = SOCK_STREAM;
1222 hints.ai_protocol = IPPROTO_TCP;
1223 hints.ai_addrlen = 0;
1224 hints.ai_addr = NULL;
1225 hints.ai_canonname = NULL;
1226 hints.ai_next = NULL;
1228 ret = getaddrinfo(NULL, endpoint ? endpoint : "0", &hints, &ai);
1229 if (ret)
1231 ERR("getaddrinfo for port %s failed, error %u\n", endpoint, WSAGetLastError());
1232 if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
1233 return RPC_S_INVALID_ENDPOINT_FORMAT;
1234 return RPC_S_CANT_CREATE_ENDPOINT;
1237 for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
1239 RpcConnection_tcp *tcpc;
1240 RPC_STATUS create_status;
1241 struct sockaddr_storage sa;
1242 socklen_t sa_len;
1243 char service[NI_MAXSERV];
1244 u_long nonblocking;
1246 if (ai_cur->ai_family != AF_INET && ai_cur->ai_family != AF_INET6)
1248 TRACE("skipping non-IP/IPv6 address family\n");
1249 continue;
1252 if (TRACE_ON(rpc))
1254 char host[256];
1255 getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
1256 host, sizeof(host), service, sizeof(service),
1257 NI_NUMERICHOST | NI_NUMERICSERV);
1258 TRACE("trying %s:%s\n", host, service);
1261 sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
1262 if (sock == -1)
1264 WARN("socket() failed: %u\n", WSAGetLastError());
1265 status = RPC_S_CANT_CREATE_ENDPOINT;
1266 continue;
1269 ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
1270 if (ret < 0)
1272 WARN("bind failed: %u\n", WSAGetLastError());
1273 closesocket(sock);
1274 if (WSAGetLastError() == WSAEADDRINUSE)
1275 status = RPC_S_DUPLICATE_ENDPOINT;
1276 else
1277 status = RPC_S_CANT_CREATE_ENDPOINT;
1278 continue;
1281 sa_len = sizeof(sa);
1282 if (getsockname(sock, (struct sockaddr *)&sa, &sa_len))
1284 WARN("getsockname() failed: %u\n", WSAGetLastError());
1285 closesocket(sock);
1286 status = RPC_S_CANT_CREATE_ENDPOINT;
1287 continue;
1290 ret = getnameinfo((struct sockaddr *)&sa, sa_len,
1291 NULL, 0, service, sizeof(service),
1292 NI_NUMERICSERV);
1293 if (ret)
1295 WARN("getnameinfo failed, error %u\n", WSAGetLastError());
1296 closesocket(sock);
1297 status = RPC_S_CANT_CREATE_ENDPOINT;
1298 continue;
1301 create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
1302 protseq->Protseq, NULL,
1303 service, NULL, NULL, NULL, NULL);
1304 if (create_status != RPC_S_OK)
1306 closesocket(sock);
1307 status = create_status;
1308 continue;
1311 tcpc->sock = sock;
1312 ret = listen(sock, protseq->MaxCalls);
1313 if (ret < 0)
1315 WARN("listen failed: %u\n", WSAGetLastError());
1316 RPCRT4_ReleaseConnection(&tcpc->common);
1317 status = RPC_S_OUT_OF_RESOURCES;
1318 continue;
1320 /* need a non-blocking socket, otherwise accept() has a potential
1321 * race-condition (poll() says it is readable, connection drops,
1322 * and accept() blocks until the next connection comes...)
1324 nonblocking = 1;
1325 ret = ioctlsocket(sock, FIONBIO, &nonblocking);
1326 if (ret < 0)
1328 WARN("couldn't make socket non-blocking, error %d\n", ret);
1329 RPCRT4_ReleaseConnection(&tcpc->common);
1330 status = RPC_S_OUT_OF_RESOURCES;
1331 continue;
1334 EnterCriticalSection(&protseq->cs);
1335 list_add_tail(&protseq->listeners, &tcpc->common.protseq_entry);
1336 tcpc->common.protseq = protseq;
1337 LeaveCriticalSection(&protseq->cs);
1339 freeaddrinfo(ai);
1341 /* since IPv4 and IPv6 share the same port space, we only need one
1342 * successful bind to listen for both */
1343 TRACE("listening on %s\n", endpoint);
1344 return RPC_S_OK;
1347 freeaddrinfo(ai);
1348 ERR("couldn't listen on port %s\n", endpoint);
1349 return status;
1352 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
1354 int ret;
1355 struct sockaddr_in address;
1356 socklen_t addrsize;
1357 RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
1358 RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
1359 u_long nonblocking;
1361 addrsize = sizeof(address);
1362 ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
1363 if (ret < 0)
1365 ERR("Failed to accept a TCP connection: error %d\n", ret);
1366 return RPC_S_OUT_OF_RESOURCES;
1369 nonblocking = 1;
1370 ioctlsocket(ret, FIONBIO, &nonblocking);
1371 client->sock = ret;
1373 client->common.NetworkAddr = HeapAlloc(GetProcessHeap(), 0, INET6_ADDRSTRLEN);
1374 ret = getnameinfo((struct sockaddr*)&address, addrsize, client->common.NetworkAddr, INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST);
1375 if (ret != 0)
1377 ERR("Failed to retrieve the IP address, error %d\n", ret);
1378 return RPC_S_OUT_OF_RESOURCES;
1381 TRACE("Accepted a new TCP connection from %s\n", client->common.NetworkAddr);
1382 return RPC_S_OK;
1385 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
1386 void *buffer, unsigned int count)
1388 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1389 int bytes_read = 0;
1390 while (bytes_read != count)
1392 int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
1393 if (!r)
1394 return -1;
1395 else if (r > 0)
1396 bytes_read += r;
1397 else if (WSAGetLastError() == WSAEINTR)
1398 continue;
1399 else if (WSAGetLastError() != WSAEWOULDBLOCK)
1401 WARN("recv() failed: %u\n", WSAGetLastError());
1402 return -1;
1404 else
1406 if (!rpcrt4_sock_wait_for_recv(tcpc))
1407 return -1;
1410 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
1411 return bytes_read;
1414 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
1415 const void *buffer, unsigned int count)
1417 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1418 int bytes_written = 0;
1419 while (bytes_written != count)
1421 int r = send(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written, 0);
1422 if (r >= 0)
1423 bytes_written += r;
1424 else if (WSAGetLastError() == WSAEINTR)
1425 continue;
1426 else if (WSAGetLastError() != WSAEWOULDBLOCK)
1427 return -1;
1428 else
1430 if (!rpcrt4_sock_wait_for_send(tcpc))
1431 return -1;
1434 TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1435 return bytes_written;
1438 static int rpcrt4_conn_tcp_close(RpcConnection *conn)
1440 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1442 TRACE("%d\n", connection->sock);
1444 if (connection->sock != -1)
1445 closesocket(connection->sock);
1446 connection->sock = -1;
1447 CloseHandle(connection->sock_event);
1448 CloseHandle(connection->cancel_event);
1449 return 0;
1452 static void rpcrt4_conn_tcp_close_read(RpcConnection *conn)
1454 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1455 shutdown(connection->sock, SD_RECEIVE);
1458 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *conn)
1460 RpcConnection_tcp *connection = (RpcConnection_tcp *) conn;
1462 TRACE("%p\n", connection);
1464 SetEvent(connection->cancel_event);
1467 static RPC_STATUS rpcrt4_conn_tcp_is_server_listening(const char *endpoint)
1469 FIXME("\n");
1470 return RPC_S_ACCESS_DENIED;
1473 static int rpcrt4_conn_tcp_wait_for_incoming_data(RpcConnection *Connection)
1475 RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1477 TRACE("%p\n", Connection);
1479 if (!rpcrt4_sock_wait_for_recv(tcpc))
1480 return -1;
1481 return 0;
1484 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1485 const char *networkaddr,
1486 const char *endpoint)
1488 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
1489 EPM_PROTOCOL_TCP, endpoint);
1492 typedef struct _RpcServerProtseq_sock
1494 RpcServerProtseq common;
1495 HANDLE mgr_event;
1496 } RpcServerProtseq_sock;
1498 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1500 RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ps));
1501 if (ps)
1503 static BOOL wsa_inited;
1504 if (!wsa_inited)
1506 WSADATA wsadata;
1507 WSAStartup(MAKEWORD(2, 2), &wsadata);
1508 /* Note: WSAStartup can be called more than once so we don't bother with
1509 * making accesses to wsa_inited thread-safe */
1510 wsa_inited = TRUE;
1512 ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1514 return &ps->common;
1517 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1519 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1520 SetEvent(sockps->mgr_event);
1523 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1525 HANDLE *objs = prev_array;
1526 RpcConnection_tcp *conn;
1527 RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1529 EnterCriticalSection(&protseq->cs);
1531 /* open and count connections */
1532 *count = 1;
1533 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1535 if (conn->sock != -1)
1536 (*count)++;
1539 /* make array of connections */
1540 if (objs)
1541 objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
1542 else
1543 objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
1544 if (!objs)
1546 ERR("couldn't allocate objs\n");
1547 LeaveCriticalSection(&protseq->cs);
1548 return NULL;
1551 objs[0] = sockps->mgr_event;
1552 *count = 1;
1553 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1555 if (conn->sock != -1)
1557 int res = WSAEventSelect(conn->sock, conn->sock_event, FD_ACCEPT);
1558 if (res == SOCKET_ERROR)
1559 ERR("WSAEventSelect() failed with error %d\n", WSAGetLastError());
1560 else
1562 objs[*count] = conn->sock_event;
1563 (*count)++;
1567 LeaveCriticalSection(&protseq->cs);
1568 return objs;
1571 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1573 HeapFree(GetProcessHeap(), 0, array);
1576 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1578 HANDLE b_handle;
1579 HANDLE *objs = wait_array;
1580 DWORD res;
1581 RpcConnection *cconn = NULL;
1582 RpcConnection_tcp *conn;
1584 if (!objs)
1585 return -1;
1589 /* an alertable wait isn't strictly necessary, but due to our
1590 * overlapped I/O implementation in Wine we need to free some memory
1591 * by the file user APC being called, even if no completion routine was
1592 * specified at the time of starting the async operation */
1593 res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
1594 } while (res == WAIT_IO_COMPLETION);
1596 if (res == WAIT_OBJECT_0)
1597 return 0;
1598 if (res == WAIT_FAILED)
1600 ERR("wait failed with error %ld\n", GetLastError());
1601 return -1;
1604 b_handle = objs[res - WAIT_OBJECT_0];
1606 /* find which connection got a RPC */
1607 EnterCriticalSection(&protseq->cs);
1608 LIST_FOR_EACH_ENTRY(conn, &protseq->listeners, RpcConnection_tcp, common.protseq_entry)
1610 if (b_handle == conn->sock_event)
1612 cconn = rpcrt4_spawn_connection(&conn->common);
1613 break;
1616 LeaveCriticalSection(&protseq->cs);
1617 if (!cconn)
1619 ERR("failed to locate connection for handle %p\n", b_handle);
1620 return -1;
1623 RPCRT4_new_client(cconn);
1624 return 1;
1627 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1628 size_t tower_size,
1629 char **networkaddr,
1630 char **endpoint)
1632 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
1633 networkaddr, EPM_PROTOCOL_TCP,
1634 endpoint);
1637 /**** ncacn_http support ****/
1639 /* 60 seconds is the period native uses */
1640 #define HTTP_IDLE_TIME 60000
1642 /* reference counted to avoid a race between a cancelled call's connection
1643 * being destroyed and the asynchronous InternetReadFileEx call being
1644 * completed */
1645 typedef struct _RpcHttpAsyncData
1647 LONG refs;
1648 HANDLE completion_event;
1649 WORD async_result;
1650 INTERNET_BUFFERSW inet_buffers;
1651 CRITICAL_SECTION cs;
1652 } RpcHttpAsyncData;
1654 static ULONG RpcHttpAsyncData_AddRef(RpcHttpAsyncData *data)
1656 return InterlockedIncrement(&data->refs);
1659 static ULONG RpcHttpAsyncData_Release(RpcHttpAsyncData *data)
1661 ULONG refs = InterlockedDecrement(&data->refs);
1662 if (!refs)
1664 TRACE("destroying async data %p\n", data);
1665 CloseHandle(data->completion_event);
1666 HeapFree(GetProcessHeap(), 0, data->inet_buffers.lpvBuffer);
1667 data->cs.DebugInfo->Spare[0] = 0;
1668 DeleteCriticalSection(&data->cs);
1669 HeapFree(GetProcessHeap(), 0, data);
1671 return refs;
1674 static void prepare_async_request(RpcHttpAsyncData *async_data)
1676 ResetEvent(async_data->completion_event);
1677 RpcHttpAsyncData_AddRef(async_data);
1680 static RPC_STATUS wait_async_request(RpcHttpAsyncData *async_data, BOOL call_ret, HANDLE cancel_event)
1682 HANDLE handles[2] = { async_data->completion_event, cancel_event };
1683 DWORD res;
1685 if(call_ret) {
1686 RpcHttpAsyncData_Release(async_data);
1687 return RPC_S_OK;
1690 if(GetLastError() != ERROR_IO_PENDING) {
1691 RpcHttpAsyncData_Release(async_data);
1692 ERR("Request failed with error %ld\n", GetLastError());
1693 return RPC_S_SERVER_UNAVAILABLE;
1696 res = WaitForMultipleObjects(2, handles, FALSE, DEFAULT_NCACN_HTTP_TIMEOUT);
1697 if(res != WAIT_OBJECT_0) {
1698 TRACE("Cancelled\n");
1699 return RPC_S_CALL_CANCELLED;
1702 if(async_data->async_result) {
1703 ERR("Async request failed with error %d\n", async_data->async_result);
1704 return RPC_S_SERVER_UNAVAILABLE;
1707 return RPC_S_OK;
1710 struct authinfo
1712 DWORD scheme;
1713 CredHandle cred;
1714 CtxtHandle ctx;
1715 TimeStamp exp;
1716 ULONG attr;
1717 ULONG max_token;
1718 char *data;
1719 unsigned int data_len;
1720 BOOL finished; /* finished authenticating */
1723 typedef struct _RpcConnection_http
1725 RpcConnection common;
1726 HINTERNET app_info;
1727 HINTERNET session;
1728 HINTERNET in_request;
1729 HINTERNET out_request;
1730 WCHAR *servername;
1731 HANDLE timer_cancelled;
1732 HANDLE cancel_event;
1733 DWORD last_sent_time;
1734 ULONG bytes_received;
1735 ULONG flow_control_mark; /* send a control packet to the server when this many bytes received */
1736 ULONG flow_control_increment; /* number of bytes to increment flow_control_mark by */
1737 UUID connection_uuid;
1738 UUID in_pipe_uuid;
1739 UUID out_pipe_uuid;
1740 RpcHttpAsyncData *async_data;
1741 } RpcConnection_http;
1743 static RpcConnection *rpcrt4_ncacn_http_alloc(void)
1745 RpcConnection_http *httpc;
1746 httpc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*httpc));
1747 if (!httpc) return NULL;
1748 httpc->async_data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcHttpAsyncData));
1749 if (!httpc->async_data)
1751 HeapFree(GetProcessHeap(), 0, httpc);
1752 return NULL;
1754 TRACE("async data = %p\n", httpc->async_data);
1755 httpc->cancel_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1756 httpc->async_data->refs = 1;
1757 httpc->async_data->inet_buffers.dwStructSize = sizeof(INTERNET_BUFFERSW);
1758 InitializeCriticalSection(&httpc->async_data->cs);
1759 httpc->async_data->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RpcHttpAsyncData.cs");
1760 return &httpc->common;
1763 typedef struct _HttpTimerThreadData
1765 PVOID timer_param;
1766 DWORD *last_sent_time;
1767 HANDLE timer_cancelled;
1768 } HttpTimerThreadData;
1770 static VOID rpcrt4_http_keep_connection_active_timer_proc(PVOID param, BOOLEAN dummy)
1772 HINTERNET in_request = param;
1773 RpcPktHdr *idle_pkt;
1775 idle_pkt = RPCRT4_BuildHttpHeader(NDR_LOCAL_DATA_REPRESENTATION, 0x0001,
1776 0, 0);
1777 if (idle_pkt)
1779 DWORD bytes_written;
1780 InternetWriteFile(in_request, idle_pkt, idle_pkt->common.frag_len, &bytes_written);
1781 RPCRT4_FreeHeader(idle_pkt);
1785 static inline DWORD rpcrt4_http_timer_calc_timeout(DWORD *last_sent_time)
1787 DWORD cur_time = GetTickCount();
1788 DWORD cached_last_sent_time = *last_sent_time;
1789 return HTTP_IDLE_TIME - (cur_time - cached_last_sent_time > HTTP_IDLE_TIME ? 0 : cur_time - cached_last_sent_time);
1792 static DWORD CALLBACK rpcrt4_http_timer_thread(PVOID param)
1794 HttpTimerThreadData *data_in = param;
1795 HttpTimerThreadData data;
1796 DWORD timeout;
1798 data = *data_in;
1799 HeapFree(GetProcessHeap(), 0, data_in);
1801 for (timeout = HTTP_IDLE_TIME;
1802 WaitForSingleObject(data.timer_cancelled, timeout) == WAIT_TIMEOUT;
1803 timeout = rpcrt4_http_timer_calc_timeout(data.last_sent_time))
1805 /* are we too soon after last send? */
1806 if (GetTickCount() - *data.last_sent_time < HTTP_IDLE_TIME)
1807 continue;
1808 rpcrt4_http_keep_connection_active_timer_proc(data.timer_param, TRUE);
1811 CloseHandle(data.timer_cancelled);
1812 return 0;
1815 static VOID WINAPI rpcrt4_http_internet_callback(
1816 HINTERNET hInternet,
1817 DWORD_PTR dwContext,
1818 DWORD dwInternetStatus,
1819 LPVOID lpvStatusInformation,
1820 DWORD dwStatusInformationLength)
1822 RpcHttpAsyncData *async_data = (RpcHttpAsyncData *)dwContext;
1824 switch (dwInternetStatus)
1826 case INTERNET_STATUS_REQUEST_COMPLETE:
1827 TRACE("INTERNET_STATUS_REQUEST_COMPLETED\n");
1828 if (async_data)
1830 INTERNET_ASYNC_RESULT *async_result = lpvStatusInformation;
1832 async_data->async_result = async_result->dwResult ? ERROR_SUCCESS : async_result->dwError;
1833 SetEvent(async_data->completion_event);
1834 RpcHttpAsyncData_Release(async_data);
1836 break;
1840 static RPC_STATUS rpcrt4_http_check_response(HINTERNET hor)
1842 BOOL ret;
1843 DWORD status_code;
1844 DWORD size;
1845 DWORD index;
1846 WCHAR buf[32];
1847 WCHAR *status_text = buf;
1848 TRACE("\n");
1850 index = 0;
1851 size = sizeof(status_code);
1852 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_CODE|HTTP_QUERY_FLAG_NUMBER, &status_code, &size, &index);
1853 if (!ret)
1854 return GetLastError();
1855 if (status_code == HTTP_STATUS_OK)
1856 return RPC_S_OK;
1857 index = 0;
1858 size = sizeof(buf);
1859 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1860 if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1862 status_text = HeapAlloc(GetProcessHeap(), 0, size);
1863 ret = HttpQueryInfoW(hor, HTTP_QUERY_STATUS_TEXT, status_text, &size, &index);
1866 ERR("server returned: %ld %s\n", status_code, ret ? debugstr_w(status_text) : "<status text unavailable>");
1867 if(status_text != buf) HeapFree(GetProcessHeap(), 0, status_text);
1869 if (status_code == HTTP_STATUS_DENIED)
1870 return ERROR_ACCESS_DENIED;
1871 return RPC_S_SERVER_UNAVAILABLE;
1874 static RPC_STATUS rpcrt4_http_internet_connect(RpcConnection_http *httpc)
1876 LPWSTR proxy = NULL;
1877 LPWSTR user = NULL;
1878 LPWSTR password = NULL;
1879 LPWSTR servername = NULL;
1880 const WCHAR *option;
1881 INTERNET_PORT port;
1883 if (httpc->common.QOS &&
1884 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP))
1886 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_cred = httpc->common.QOS->qos->u.HttpCredentials;
1887 if (http_cred->TransportCredentials)
1889 WCHAR *p;
1890 const SEC_WINNT_AUTH_IDENTITY_W *cred = http_cred->TransportCredentials;
1891 ULONG len = cred->DomainLength + 1 + cred->UserLength;
1892 user = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
1893 if (!user)
1894 return RPC_S_OUT_OF_RESOURCES;
1895 p = user;
1896 if (cred->DomainLength)
1898 memcpy(p, cred->Domain, cred->DomainLength * sizeof(WCHAR));
1899 p += cred->DomainLength;
1900 *p = '\\';
1901 p++;
1903 memcpy(p, cred->User, cred->UserLength * sizeof(WCHAR));
1904 p[cred->UserLength] = 0;
1906 password = RPCRT4_strndupW(cred->Password, cred->PasswordLength);
1910 for (option = httpc->common.NetworkOptions; option;
1911 option = (wcschr(option, ',') ? wcschr(option, ',')+1 : NULL))
1913 if (!wcsnicmp(option, L"RpcProxy=", ARRAY_SIZE(L"RpcProxy=")-1))
1915 const WCHAR *value_start = option + ARRAY_SIZE(L"RpcProxy=")-1;
1916 const WCHAR *value_end;
1917 const WCHAR *p;
1919 value_end = wcschr(option, ',');
1920 if (!value_end)
1921 value_end = value_start + lstrlenW(value_start);
1922 for (p = value_start; p < value_end; p++)
1923 if (*p == ':')
1925 port = wcstol(p+1, NULL, 10);
1926 value_end = p;
1927 break;
1929 TRACE("RpcProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
1930 servername = RPCRT4_strndupW(value_start, value_end-value_start);
1932 else if (!wcsnicmp(option, L"HttpProxy=", ARRAY_SIZE(L"HttpProxy=")-1))
1934 const WCHAR *value_start = option + ARRAY_SIZE(L"HttpProxy=")-1;
1935 const WCHAR *value_end;
1937 value_end = wcschr(option, ',');
1938 if (!value_end)
1939 value_end = value_start + lstrlenW(value_start);
1940 TRACE("HttpProxy value is %s\n", debugstr_wn(value_start, value_end-value_start));
1941 proxy = RPCRT4_strndupW(value_start, value_end-value_start);
1943 else
1944 FIXME("unhandled option %s\n", debugstr_w(option));
1947 httpc->app_info = InternetOpenW(L"MSRPC", proxy ? INTERNET_OPEN_TYPE_PROXY : INTERNET_OPEN_TYPE_PRECONFIG,
1948 NULL, NULL, INTERNET_FLAG_ASYNC);
1949 if (!httpc->app_info)
1951 HeapFree(GetProcessHeap(), 0, password);
1952 HeapFree(GetProcessHeap(), 0, user);
1953 HeapFree(GetProcessHeap(), 0, proxy);
1954 HeapFree(GetProcessHeap(), 0, servername);
1955 ERR("InternetOpenW failed with error %ld\n", GetLastError());
1956 return RPC_S_SERVER_UNAVAILABLE;
1958 InternetSetStatusCallbackW(httpc->app_info, rpcrt4_http_internet_callback);
1960 /* if no RpcProxy option specified, set the HTTP server address to the
1961 * RPC server address */
1962 if (!servername)
1964 servername = HeapAlloc(GetProcessHeap(), 0, (strlen(httpc->common.NetworkAddr) + 1)*sizeof(WCHAR));
1965 if (!servername)
1967 HeapFree(GetProcessHeap(), 0, password);
1968 HeapFree(GetProcessHeap(), 0, user);
1969 HeapFree(GetProcessHeap(), 0, proxy);
1970 return RPC_S_OUT_OF_RESOURCES;
1972 MultiByteToWideChar(CP_ACP, 0, httpc->common.NetworkAddr, -1, servername, strlen(httpc->common.NetworkAddr) + 1);
1975 port = (httpc->common.QOS &&
1976 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
1977 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL)) ?
1978 INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
1980 httpc->session = InternetConnectW(httpc->app_info, servername, port, user, password,
1981 INTERNET_SERVICE_HTTP, 0, 0);
1983 HeapFree(GetProcessHeap(), 0, password);
1984 HeapFree(GetProcessHeap(), 0, user);
1985 HeapFree(GetProcessHeap(), 0, proxy);
1987 if (!httpc->session)
1989 ERR("InternetConnectW failed with error %ld\n", GetLastError());
1990 HeapFree(GetProcessHeap(), 0, servername);
1991 return RPC_S_SERVER_UNAVAILABLE;
1993 httpc->servername = servername;
1994 return RPC_S_OK;
1997 static int rpcrt4_http_async_read(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event,
1998 void *buffer, unsigned int count)
2000 char *buf = buffer;
2001 BOOL ret;
2002 unsigned int bytes_left = count;
2003 RPC_STATUS status = RPC_S_OK;
2005 async_data->inet_buffers.lpvBuffer = HeapAlloc(GetProcessHeap(), 0, count);
2007 while (bytes_left)
2009 async_data->inet_buffers.dwBufferLength = bytes_left;
2010 prepare_async_request(async_data);
2011 ret = InternetReadFileExW(req, &async_data->inet_buffers, IRF_ASYNC, 0);
2012 status = wait_async_request(async_data, ret, cancel_event);
2013 if (status != RPC_S_OK)
2015 if (status == RPC_S_CALL_CANCELLED)
2016 TRACE("call cancelled\n");
2017 break;
2020 if (!async_data->inet_buffers.dwBufferLength)
2021 break;
2022 memcpy(buf, async_data->inet_buffers.lpvBuffer,
2023 async_data->inet_buffers.dwBufferLength);
2025 bytes_left -= async_data->inet_buffers.dwBufferLength;
2026 buf += async_data->inet_buffers.dwBufferLength;
2029 HeapFree(GetProcessHeap(), 0, async_data->inet_buffers.lpvBuffer);
2030 async_data->inet_buffers.lpvBuffer = NULL;
2032 TRACE("%p %p %u -> %lu\n", req, buffer, count, status);
2033 return status == RPC_S_OK ? count : -1;
2036 static RPC_STATUS send_echo_request(HINTERNET req, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2038 BYTE buf[20];
2039 BOOL ret;
2040 RPC_STATUS status;
2042 TRACE("sending echo request to server\n");
2044 prepare_async_request(async_data);
2045 ret = HttpSendRequestW(req, NULL, 0, NULL, 0);
2046 status = wait_async_request(async_data, ret, cancel_event);
2047 if (status != RPC_S_OK) return status;
2049 status = rpcrt4_http_check_response(req);
2050 if (status != RPC_S_OK) return status;
2052 rpcrt4_http_async_read(req, async_data, cancel_event, buf, sizeof(buf));
2053 /* FIXME: do something with retrieved data */
2055 return RPC_S_OK;
2058 static RPC_STATUS insert_content_length_header(HINTERNET request, DWORD len)
2060 WCHAR header[ARRAY_SIZE(L"Content-Length: %u\r\n") + 10];
2062 swprintf(header, ARRAY_SIZE(header), L"Content-Length: %u\r\n", len);
2063 if ((HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))) return RPC_S_OK;
2064 return RPC_S_SERVER_UNAVAILABLE;
2067 /* prepare the in pipe for use by RPC packets */
2068 static RPC_STATUS rpcrt4_http_prepare_in_pipe(HINTERNET in_request, RpcHttpAsyncData *async_data, HANDLE cancel_event,
2069 const UUID *connection_uuid, const UUID *in_pipe_uuid,
2070 const UUID *association_uuid, BOOL authorized)
2072 BOOL ret;
2073 RPC_STATUS status;
2074 RpcPktHdr *hdr;
2075 INTERNET_BUFFERSW buffers_in;
2076 DWORD bytes_written;
2078 if (!authorized)
2080 /* ask wininet to authorize, if necessary */
2081 status = send_echo_request(in_request, async_data, cancel_event);
2082 if (status != RPC_S_OK) return status;
2084 memset(&buffers_in, 0, sizeof(buffers_in));
2085 buffers_in.dwStructSize = sizeof(buffers_in);
2086 /* FIXME: get this from the registry */
2087 buffers_in.dwBufferTotal = 1024 * 1024 * 1024; /* 1Gb */
2088 status = insert_content_length_header(in_request, buffers_in.dwBufferTotal);
2089 if (status != RPC_S_OK) return status;
2091 prepare_async_request(async_data);
2092 ret = HttpSendRequestExW(in_request, &buffers_in, NULL, 0, 0);
2093 status = wait_async_request(async_data, ret, cancel_event);
2094 if (status != RPC_S_OK) return status;
2096 TRACE("sending HTTP connect header to server\n");
2097 hdr = RPCRT4_BuildHttpConnectHeader(FALSE, connection_uuid, in_pipe_uuid, association_uuid);
2098 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2099 ret = InternetWriteFile(in_request, hdr, hdr->common.frag_len, &bytes_written);
2100 RPCRT4_FreeHeader(hdr);
2101 if (!ret)
2103 ERR("InternetWriteFile failed with error %ld\n", GetLastError());
2104 return RPC_S_SERVER_UNAVAILABLE;
2107 return RPC_S_OK;
2110 static RPC_STATUS rpcrt4_http_read_http_packet(HINTERNET request, RpcHttpAsyncData *async_data,
2111 HANDLE cancel_event, RpcPktHdr *hdr, BYTE **data)
2113 unsigned short data_len;
2114 unsigned int size;
2116 if (rpcrt4_http_async_read(request, async_data, cancel_event, hdr, sizeof(hdr->common)) < 0)
2117 return RPC_S_SERVER_UNAVAILABLE;
2118 if (hdr->common.ptype != PKT_HTTP || hdr->common.frag_len < sizeof(hdr->http))
2120 ERR("wrong packet type received %d or wrong frag_len %d\n",
2121 hdr->common.ptype, hdr->common.frag_len);
2122 return RPC_S_PROTOCOL_ERROR;
2125 size = sizeof(hdr->http) - sizeof(hdr->common);
2126 if (rpcrt4_http_async_read(request, async_data, cancel_event, &hdr->common + 1, size) < 0)
2127 return RPC_S_SERVER_UNAVAILABLE;
2129 data_len = hdr->common.frag_len - sizeof(hdr->http);
2130 if (data_len)
2132 *data = HeapAlloc(GetProcessHeap(), 0, data_len);
2133 if (!*data)
2134 return RPC_S_OUT_OF_RESOURCES;
2135 if (rpcrt4_http_async_read(request, async_data, cancel_event, *data, data_len) < 0)
2137 HeapFree(GetProcessHeap(), 0, *data);
2138 return RPC_S_SERVER_UNAVAILABLE;
2141 else
2142 *data = NULL;
2144 if (!RPCRT4_IsValidHttpPacket(hdr, *data, data_len))
2146 ERR("invalid http packet\n");
2147 HeapFree(GetProcessHeap(), 0, *data);
2148 return RPC_S_PROTOCOL_ERROR;
2151 return RPC_S_OK;
2154 /* prepare the out pipe for use by RPC packets */
2155 static RPC_STATUS rpcrt4_http_prepare_out_pipe(HINTERNET out_request, RpcHttpAsyncData *async_data,
2156 HANDLE cancel_event, const UUID *connection_uuid,
2157 const UUID *out_pipe_uuid, ULONG *flow_control_increment,
2158 BOOL authorized)
2160 BOOL ret;
2161 RPC_STATUS status;
2162 RpcPktHdr *hdr;
2163 BYTE *data_from_server;
2164 RpcPktHdr pkt_from_server;
2165 ULONG field1, field3;
2166 BYTE buf[20];
2168 if (!authorized)
2170 /* ask wininet to authorize, if necessary */
2171 status = send_echo_request(out_request, async_data, cancel_event);
2172 if (status != RPC_S_OK) return status;
2174 else
2175 rpcrt4_http_async_read(out_request, async_data, cancel_event, buf, sizeof(buf));
2177 hdr = RPCRT4_BuildHttpConnectHeader(TRUE, connection_uuid, out_pipe_uuid, NULL);
2178 if (!hdr) return RPC_S_OUT_OF_RESOURCES;
2180 status = insert_content_length_header(out_request, hdr->common.frag_len);
2181 if (status != RPC_S_OK)
2183 RPCRT4_FreeHeader(hdr);
2184 return status;
2187 TRACE("sending HTTP connect header to server\n");
2188 prepare_async_request(async_data);
2189 ret = HttpSendRequestW(out_request, NULL, 0, hdr, hdr->common.frag_len);
2190 status = wait_async_request(async_data, ret, cancel_event);
2191 RPCRT4_FreeHeader(hdr);
2192 if (status != RPC_S_OK) return status;
2194 status = rpcrt4_http_check_response(out_request);
2195 if (status != RPC_S_OK) return status;
2197 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2198 &pkt_from_server, &data_from_server);
2199 if (status != RPC_S_OK) return status;
2200 status = RPCRT4_ParseHttpPrepareHeader1(&pkt_from_server, data_from_server,
2201 &field1);
2202 HeapFree(GetProcessHeap(), 0, data_from_server);
2203 if (status != RPC_S_OK) return status;
2204 TRACE("received (%ld) from first prepare header\n", field1);
2206 for (;;)
2208 status = rpcrt4_http_read_http_packet(out_request, async_data, cancel_event,
2209 &pkt_from_server, &data_from_server);
2210 if (status != RPC_S_OK) return status;
2211 if (pkt_from_server.http.flags != 0x0001) break;
2213 TRACE("http idle packet, waiting for real packet\n");
2214 HeapFree(GetProcessHeap(), 0, data_from_server);
2215 if (pkt_from_server.http.num_data_items != 0)
2217 ERR("HTTP idle packet should have no data items instead of %d\n",
2218 pkt_from_server.http.num_data_items);
2219 return RPC_S_PROTOCOL_ERROR;
2222 status = RPCRT4_ParseHttpPrepareHeader2(&pkt_from_server, data_from_server,
2223 &field1, flow_control_increment,
2224 &field3);
2225 HeapFree(GetProcessHeap(), 0, data_from_server);
2226 if (status != RPC_S_OK) return status;
2227 TRACE("received (0x%08lx 0x%08lx %ld) from second prepare header\n", field1, *flow_control_increment, field3);
2229 return RPC_S_OK;
2232 static UINT encode_base64(const char *bin, unsigned int len, WCHAR *base64)
2234 static const char enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2235 UINT i = 0, x;
2237 while (len > 0)
2239 /* first 6 bits, all from bin[0] */
2240 base64[i++] = enc[(bin[0] & 0xfc) >> 2];
2241 x = (bin[0] & 3) << 4;
2243 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
2244 if (len == 1)
2246 base64[i++] = enc[x];
2247 base64[i++] = '=';
2248 base64[i++] = '=';
2249 break;
2251 base64[i++] = enc[x | ((bin[1] & 0xf0) >> 4)];
2252 x = (bin[1] & 0x0f) << 2;
2254 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
2255 if (len == 2)
2257 base64[i++] = enc[x];
2258 base64[i++] = '=';
2259 break;
2261 base64[i++] = enc[x | ((bin[2] & 0xc0) >> 6)];
2263 /* last 6 bits, all from bin [2] */
2264 base64[i++] = enc[bin[2] & 0x3f];
2265 bin += 3;
2266 len -= 3;
2268 base64[i] = 0;
2269 return i;
2272 static inline char decode_char( WCHAR c )
2274 if (c >= 'A' && c <= 'Z') return c - 'A';
2275 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
2276 if (c >= '0' && c <= '9') return c - '0' + 52;
2277 if (c == '+') return 62;
2278 if (c == '/') return 63;
2279 return 64;
2282 static unsigned int decode_base64( const WCHAR *base64, unsigned int len, char *buf )
2284 unsigned int i = 0;
2285 char c0, c1, c2, c3;
2286 const WCHAR *p = base64;
2288 while (len > 4)
2290 if ((c0 = decode_char( p[0] )) > 63) return 0;
2291 if ((c1 = decode_char( p[1] )) > 63) return 0;
2292 if ((c2 = decode_char( p[2] )) > 63) return 0;
2293 if ((c3 = decode_char( p[3] )) > 63) return 0;
2295 if (buf)
2297 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2298 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2299 buf[i + 2] = (c2 << 6) | c3;
2301 len -= 4;
2302 i += 3;
2303 p += 4;
2305 if (p[2] == '=')
2307 if ((c0 = decode_char( p[0] )) > 63) return 0;
2308 if ((c1 = decode_char( p[1] )) > 63) return 0;
2310 if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
2311 i++;
2313 else if (p[3] == '=')
2315 if ((c0 = decode_char( p[0] )) > 63) return 0;
2316 if ((c1 = decode_char( p[1] )) > 63) return 0;
2317 if ((c2 = decode_char( p[2] )) > 63) return 0;
2319 if (buf)
2321 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2322 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2324 i += 2;
2326 else
2328 if ((c0 = decode_char( p[0] )) > 63) return 0;
2329 if ((c1 = decode_char( p[1] )) > 63) return 0;
2330 if ((c2 = decode_char( p[2] )) > 63) return 0;
2331 if ((c3 = decode_char( p[3] )) > 63) return 0;
2333 if (buf)
2335 buf[i + 0] = (c0 << 2) | (c1 >> 4);
2336 buf[i + 1] = (c1 << 4) | (c2 >> 2);
2337 buf[i + 2] = (c2 << 6) | c3;
2339 i += 3;
2341 return i;
2344 static struct authinfo *alloc_authinfo(void)
2346 struct authinfo *ret;
2348 if (!(ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret) ))) return NULL;
2350 SecInvalidateHandle(&ret->cred);
2351 SecInvalidateHandle(&ret->ctx);
2352 memset(&ret->exp, 0, sizeof(ret->exp));
2353 ret->scheme = 0;
2354 ret->attr = 0;
2355 ret->max_token = 0;
2356 ret->data = NULL;
2357 ret->data_len = 0;
2358 ret->finished = FALSE;
2359 return ret;
2362 static void destroy_authinfo(struct authinfo *info)
2364 if (!info) return;
2366 if (SecIsValidHandle(&info->ctx))
2367 DeleteSecurityContext(&info->ctx);
2368 if (SecIsValidHandle(&info->cred))
2369 FreeCredentialsHandle(&info->cred);
2371 HeapFree(GetProcessHeap(), 0, info->data);
2372 HeapFree(GetProcessHeap(), 0, info);
2375 static const struct
2377 const WCHAR *str;
2378 unsigned int len;
2379 DWORD scheme;
2381 auth_schemes[] =
2383 { L"Basic", ARRAY_SIZE(L"Basic") - 1, RPC_C_HTTP_AUTHN_SCHEME_BASIC },
2384 { L"NTLM", ARRAY_SIZE(L"NTLM") - 1, RPC_C_HTTP_AUTHN_SCHEME_NTLM },
2385 { L"Passport", ARRAY_SIZE(L"Passport") - 1, RPC_C_HTTP_AUTHN_SCHEME_PASSPORT },
2386 { L"Digest", ARRAY_SIZE(L"Digest") - 1, RPC_C_HTTP_AUTHN_SCHEME_DIGEST },
2387 { L"Negotiate", ARRAY_SIZE(L"Negotiate") - 1, RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE }
2390 static DWORD auth_scheme_from_header( const WCHAR *header )
2392 unsigned int i;
2393 for (i = 0; i < ARRAY_SIZE(auth_schemes); i++)
2395 if (!wcsnicmp( header, auth_schemes[i].str, auth_schemes[i].len ) &&
2396 (header[auth_schemes[i].len] == ' ' || !header[auth_schemes[i].len])) return auth_schemes[i].scheme;
2398 return 0;
2401 static BOOL get_authvalue(HINTERNET request, DWORD scheme, WCHAR *buffer, DWORD buflen)
2403 DWORD len, index = 0;
2404 for (;;)
2406 len = buflen;
2407 if (!HttpQueryInfoW(request, HTTP_QUERY_WWW_AUTHENTICATE, buffer, &len, &index)) return FALSE;
2408 if (auth_scheme_from_header(buffer) == scheme) break;
2410 return TRUE;
2413 static RPC_STATUS do_authorization(HINTERNET request, SEC_WCHAR *servername,
2414 const RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds, struct authinfo **auth_ptr)
2416 struct authinfo *info = *auth_ptr;
2417 SEC_WINNT_AUTH_IDENTITY_W *id = creds->TransportCredentials;
2418 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2420 if ((!info && !(info = alloc_authinfo()))) return RPC_S_SERVER_UNAVAILABLE;
2422 switch (creds->AuthnSchemes[0])
2424 case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2426 int userlen = WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, NULL, 0, NULL, NULL);
2427 int passlen = WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, NULL, 0, NULL, NULL);
2429 info->data_len = userlen + passlen + 1;
2430 if (!(info->data = HeapAlloc(GetProcessHeap(), 0, info->data_len)))
2432 status = RPC_S_OUT_OF_MEMORY;
2433 break;
2435 WideCharToMultiByte(CP_UTF8, 0, id->User, id->UserLength, info->data, userlen, NULL, NULL);
2436 info->data[userlen] = ':';
2437 WideCharToMultiByte(CP_UTF8, 0, id->Password, id->PasswordLength, info->data + userlen + 1, passlen, NULL, NULL);
2439 info->scheme = RPC_C_HTTP_AUTHN_SCHEME_BASIC;
2440 info->finished = TRUE;
2441 status = RPC_S_OK;
2442 break;
2444 case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2445 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2448 static SEC_WCHAR ntlmW[] = L"NTLM", negotiateW[] = L"Negotiate";
2449 SECURITY_STATUS ret;
2450 SecBufferDesc out_desc, in_desc;
2451 SecBuffer out, in;
2452 ULONG flags = ISC_REQ_CONNECTION|ISC_REQ_USE_DCE_STYLE|ISC_REQ_MUTUAL_AUTH|ISC_REQ_DELEGATE;
2453 SEC_WCHAR *scheme;
2454 int scheme_len;
2455 const WCHAR *p;
2456 WCHAR auth_value[2048];
2457 DWORD size = sizeof(auth_value);
2458 BOOL first = FALSE;
2460 if (creds->AuthnSchemes[0] == RPC_C_HTTP_AUTHN_SCHEME_NTLM) scheme = ntlmW;
2461 else scheme = negotiateW;
2462 scheme_len = lstrlenW( scheme );
2464 if (!*auth_ptr)
2466 TimeStamp exp;
2467 SecPkgInfoW *pkg_info;
2469 ret = AcquireCredentialsHandleW(NULL, scheme, SECPKG_CRED_OUTBOUND, NULL, id, NULL, NULL, &info->cred, &exp);
2470 if (ret != SEC_E_OK) break;
2472 ret = QuerySecurityPackageInfoW(scheme, &pkg_info);
2473 if (ret != SEC_E_OK) break;
2475 info->max_token = pkg_info->cbMaxToken;
2476 FreeContextBuffer(pkg_info);
2477 first = TRUE;
2479 else
2481 if (info->finished || !get_authvalue(request, creds->AuthnSchemes[0], auth_value, size)) break;
2482 if (auth_scheme_from_header(auth_value) != info->scheme)
2484 ERR("authentication scheme changed\n");
2485 break;
2488 in.BufferType = SECBUFFER_TOKEN;
2489 in.cbBuffer = 0;
2490 in.pvBuffer = NULL;
2492 in_desc.ulVersion = 0;
2493 in_desc.cBuffers = 1;
2494 in_desc.pBuffers = &in;
2496 p = auth_value + scheme_len;
2497 if (!first && *p == ' ')
2499 int len = lstrlenW(++p);
2500 in.cbBuffer = decode_base64(p, len, NULL);
2501 if (!(in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer))) break;
2502 decode_base64(p, len, in.pvBuffer);
2504 out.BufferType = SECBUFFER_TOKEN;
2505 out.cbBuffer = info->max_token;
2506 if (!(out.pvBuffer = HeapAlloc(GetProcessHeap(), 0, out.cbBuffer)))
2508 HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2509 break;
2511 out_desc.ulVersion = 0;
2512 out_desc.cBuffers = 1;
2513 out_desc.pBuffers = &out;
2515 ret = InitializeSecurityContextW(first ? &info->cred : NULL, first ? NULL : &info->ctx,
2516 first ? servername : NULL, flags, 0, SECURITY_NETWORK_DREP,
2517 in.pvBuffer ? &in_desc : NULL, 0, &info->ctx, &out_desc,
2518 &info->attr, &info->exp);
2519 HeapFree(GetProcessHeap(), 0, in.pvBuffer);
2520 if (ret == SEC_E_OK)
2522 HeapFree(GetProcessHeap(), 0, info->data);
2523 info->data = out.pvBuffer;
2524 info->data_len = out.cbBuffer;
2525 info->finished = TRUE;
2526 TRACE("sending last auth packet\n");
2527 status = RPC_S_OK;
2529 else if (ret == SEC_I_CONTINUE_NEEDED)
2531 HeapFree(GetProcessHeap(), 0, info->data);
2532 info->data = out.pvBuffer;
2533 info->data_len = out.cbBuffer;
2534 TRACE("sending next auth packet\n");
2535 status = RPC_S_OK;
2537 else
2539 ERR("InitializeSecurityContextW failed with error 0x%08lx\n", ret);
2540 HeapFree(GetProcessHeap(), 0, out.pvBuffer);
2541 break;
2543 info->scheme = creds->AuthnSchemes[0];
2544 break;
2546 default:
2547 FIXME("scheme %lu not supported\n", creds->AuthnSchemes[0]);
2548 break;
2551 if (status != RPC_S_OK)
2553 destroy_authinfo(info);
2554 *auth_ptr = NULL;
2555 return status;
2557 *auth_ptr = info;
2558 return RPC_S_OK;
2561 static RPC_STATUS insert_authorization_header(HINTERNET request, ULONG scheme, char *data, int data_len)
2563 static const WCHAR authW[] = {'A','u','t','h','o','r','i','z','a','t','i','o','n',':',' '};
2564 static const WCHAR basicW[] = {'B','a','s','i','c',' '};
2565 static const WCHAR negotiateW[] = {'N','e','g','o','t','i','a','t','e',' '};
2566 static const WCHAR ntlmW[] = {'N','T','L','M',' '};
2567 int scheme_len, auth_len = ARRAY_SIZE(authW), len = ((data_len + 2) * 4) / 3;
2568 const WCHAR *scheme_str;
2569 WCHAR *header, *ptr;
2570 RPC_STATUS status = RPC_S_SERVER_UNAVAILABLE;
2572 switch (scheme)
2574 case RPC_C_HTTP_AUTHN_SCHEME_BASIC:
2575 scheme_str = basicW;
2576 scheme_len = ARRAY_SIZE(basicW);
2577 break;
2578 case RPC_C_HTTP_AUTHN_SCHEME_NEGOTIATE:
2579 scheme_str = negotiateW;
2580 scheme_len = ARRAY_SIZE(negotiateW);
2581 break;
2582 case RPC_C_HTTP_AUTHN_SCHEME_NTLM:
2583 scheme_str = ntlmW;
2584 scheme_len = ARRAY_SIZE(ntlmW);
2585 break;
2586 default:
2587 ERR("unknown scheme %lu\n", scheme);
2588 return RPC_S_SERVER_UNAVAILABLE;
2590 if ((header = HeapAlloc(GetProcessHeap(), 0, (auth_len + scheme_len + len + 2) * sizeof(WCHAR))))
2592 memcpy(header, authW, auth_len * sizeof(WCHAR));
2593 ptr = header + auth_len;
2594 memcpy(ptr, scheme_str, scheme_len * sizeof(WCHAR));
2595 ptr += scheme_len;
2596 len = encode_base64(data, data_len, ptr);
2597 ptr[len++] = '\r';
2598 ptr[len++] = '\n';
2599 ptr[len] = 0;
2600 if (HttpAddRequestHeadersW(request, header, -1, HTTP_ADDREQ_FLAG_ADD|HTTP_ADDREQ_FLAG_REPLACE))
2601 status = RPC_S_OK;
2602 HeapFree(GetProcessHeap(), 0, header);
2604 return status;
2607 static void drain_content(HINTERNET request, RpcHttpAsyncData *async_data, HANDLE cancel_event)
2609 DWORD count, len = 0, size = sizeof(len);
2610 char buf[2048];
2612 HttpQueryInfoW(request, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH, &len, &size, NULL);
2613 if (!len) return;
2614 for (;;)
2616 count = min(sizeof(buf), len);
2617 if (rpcrt4_http_async_read(request, async_data, cancel_event, buf, count) <= 0) return;
2618 len -= count;
2622 static RPC_STATUS authorize_request(RpcConnection_http *httpc, HINTERNET request)
2624 struct authinfo *info = NULL;
2625 RPC_STATUS status;
2626 BOOL ret;
2628 for (;;)
2630 status = do_authorization(request, httpc->servername, httpc->common.QOS->qos->u.HttpCredentials, &info);
2631 if (status != RPC_S_OK) break;
2633 status = insert_authorization_header(request, info->scheme, info->data, info->data_len);
2634 if (status != RPC_S_OK) break;
2636 prepare_async_request(httpc->async_data);
2637 ret = HttpSendRequestW(request, NULL, 0, NULL, 0);
2638 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
2639 if (status != RPC_S_OK || info->finished) break;
2641 status = rpcrt4_http_check_response(request);
2642 if (status != RPC_S_OK && status != ERROR_ACCESS_DENIED) break;
2643 drain_content(request, httpc->async_data, httpc->cancel_event);
2646 if (info->scheme != RPC_C_HTTP_AUTHN_SCHEME_BASIC)
2647 HttpAddRequestHeadersW(request, L"Authorization:\r\n", -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD);
2649 destroy_authinfo(info);
2650 return status;
2653 static BOOL has_credentials(RpcConnection_http *httpc)
2655 RPC_HTTP_TRANSPORT_CREDENTIALS_W *creds;
2656 SEC_WINNT_AUTH_IDENTITY_W *id;
2658 if (!httpc->common.QOS || httpc->common.QOS->qos->AdditionalSecurityInfoType != RPC_C_AUTHN_INFO_TYPE_HTTP)
2659 return FALSE;
2661 creds = httpc->common.QOS->qos->u.HttpCredentials;
2662 if (creds->AuthenticationTarget != RPC_C_HTTP_AUTHN_TARGET_SERVER || !creds->NumberOfAuthnSchemes)
2663 return FALSE;
2665 id = creds->TransportCredentials;
2666 if (!id || !id->User || !id->Password) return FALSE;
2668 return TRUE;
2671 static BOOL is_secure(RpcConnection_http *httpc)
2673 return httpc->common.QOS &&
2674 (httpc->common.QOS->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) &&
2675 (httpc->common.QOS->qos->u.HttpCredentials->Flags & RPC_C_HTTP_FLAG_USE_SSL);
2678 static RPC_STATUS set_auth_cookie(RpcConnection_http *httpc, const WCHAR *value)
2680 static WCHAR httpW[] = L"http";
2681 static WCHAR httpsW[] = L"https";
2682 URL_COMPONENTSW uc;
2683 DWORD len;
2684 WCHAR *url;
2685 BOOL ret;
2687 if (!value) return RPC_S_OK;
2689 uc.dwStructSize = sizeof(uc);
2690 uc.lpszScheme = is_secure(httpc) ? httpsW : httpW;
2691 uc.dwSchemeLength = 0;
2692 uc.lpszHostName = httpc->servername;
2693 uc.dwHostNameLength = 0;
2694 uc.nPort = 0;
2695 uc.lpszUserName = NULL;
2696 uc.dwUserNameLength = 0;
2697 uc.lpszPassword = NULL;
2698 uc.dwPasswordLength = 0;
2699 uc.lpszUrlPath = NULL;
2700 uc.dwUrlPathLength = 0;
2701 uc.lpszExtraInfo = NULL;
2702 uc.dwExtraInfoLength = 0;
2704 if (!InternetCreateUrlW(&uc, 0, NULL, &len) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
2705 return RPC_S_SERVER_UNAVAILABLE;
2707 if (!(url = HeapAlloc(GetProcessHeap(), 0, len))) return RPC_S_OUT_OF_MEMORY;
2709 len = len / sizeof(WCHAR) - 1;
2710 if (!InternetCreateUrlW(&uc, 0, url, &len))
2712 HeapFree(GetProcessHeap(), 0, url);
2713 return RPC_S_SERVER_UNAVAILABLE;
2716 ret = InternetSetCookieW(url, NULL, value);
2717 HeapFree(GetProcessHeap(), 0, url);
2718 if (!ret) return RPC_S_SERVER_UNAVAILABLE;
2720 return RPC_S_OK;
2723 static RPC_STATUS rpcrt4_ncacn_http_open(RpcConnection* Connection)
2725 RpcConnection_http *httpc = (RpcConnection_http *)Connection;
2726 static const WCHAR wszRpcProxyPrefix[] = L"/rpc/rpcproxy.dll?";
2727 LPCWSTR wszAcceptTypes[] = { L"application/rpc", NULL };
2728 DWORD flags;
2729 WCHAR *url;
2730 RPC_STATUS status;
2731 BOOL secure, credentials;
2732 HttpTimerThreadData *timer_data;
2733 HANDLE thread;
2735 TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
2737 if (Connection->server)
2739 ERR("ncacn_http servers not supported yet\n");
2740 return RPC_S_SERVER_UNAVAILABLE;
2743 if (httpc->in_request)
2744 return RPC_S_OK;
2746 httpc->async_data->completion_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2748 UuidCreate(&httpc->connection_uuid);
2749 UuidCreate(&httpc->in_pipe_uuid);
2750 UuidCreate(&httpc->out_pipe_uuid);
2752 status = rpcrt4_http_internet_connect(httpc);
2753 if (status != RPC_S_OK)
2754 return status;
2756 url = HeapAlloc(GetProcessHeap(), 0, sizeof(wszRpcProxyPrefix) + (strlen(Connection->NetworkAddr) + 1 + strlen(Connection->Endpoint))*sizeof(WCHAR));
2757 if (!url)
2758 return RPC_S_OUT_OF_MEMORY;
2759 memcpy(url, wszRpcProxyPrefix, sizeof(wszRpcProxyPrefix));
2760 MultiByteToWideChar(CP_ACP, 0, Connection->NetworkAddr, -1, url+ARRAY_SIZE(wszRpcProxyPrefix)-1,
2761 strlen(Connection->NetworkAddr)+1);
2762 lstrcatW(url, L":");
2763 MultiByteToWideChar(CP_ACP, 0, Connection->Endpoint, -1, url+lstrlenW(url), strlen(Connection->Endpoint)+1);
2765 secure = is_secure(httpc);
2766 credentials = has_credentials(httpc);
2768 flags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE |
2769 INTERNET_FLAG_NO_AUTO_REDIRECT;
2770 if (secure) flags |= INTERNET_FLAG_SECURE;
2771 if (credentials) flags |= INTERNET_FLAG_NO_AUTH;
2773 status = set_auth_cookie(httpc, Connection->CookieAuth);
2774 if (status != RPC_S_OK)
2776 HeapFree(GetProcessHeap(), 0, url);
2777 return status;
2779 httpc->in_request = HttpOpenRequestW(httpc->session, L"RPC_IN_DATA", url, NULL, NULL, wszAcceptTypes,
2780 flags, (DWORD_PTR)httpc->async_data);
2781 if (!httpc->in_request)
2783 ERR("HttpOpenRequestW failed with error %ld\n", GetLastError());
2784 HeapFree(GetProcessHeap(), 0, url);
2785 return RPC_S_SERVER_UNAVAILABLE;
2788 if (credentials)
2790 status = authorize_request(httpc, httpc->in_request);
2791 if (status != RPC_S_OK)
2793 HeapFree(GetProcessHeap(), 0, url);
2794 return status;
2796 status = rpcrt4_http_check_response(httpc->in_request);
2797 if (status != RPC_S_OK)
2799 HeapFree(GetProcessHeap(), 0, url);
2800 return status;
2802 drain_content(httpc->in_request, httpc->async_data, httpc->cancel_event);
2805 httpc->out_request = HttpOpenRequestW(httpc->session, L"RPC_OUT_DATA", url, NULL, NULL, wszAcceptTypes,
2806 flags, (DWORD_PTR)httpc->async_data);
2807 HeapFree(GetProcessHeap(), 0, url);
2808 if (!httpc->out_request)
2810 ERR("HttpOpenRequestW failed with error %ld\n", GetLastError());
2811 return RPC_S_SERVER_UNAVAILABLE;
2814 if (credentials)
2816 status = authorize_request(httpc, httpc->out_request);
2817 if (status != RPC_S_OK)
2818 return status;
2821 status = rpcrt4_http_prepare_in_pipe(httpc->in_request, httpc->async_data, httpc->cancel_event,
2822 &httpc->connection_uuid, &httpc->in_pipe_uuid,
2823 &Connection->assoc->http_uuid, credentials);
2824 if (status != RPC_S_OK)
2825 return status;
2827 status = rpcrt4_http_prepare_out_pipe(httpc->out_request, httpc->async_data, httpc->cancel_event,
2828 &httpc->connection_uuid, &httpc->out_pipe_uuid,
2829 &httpc->flow_control_increment, credentials);
2830 if (status != RPC_S_OK)
2831 return status;
2833 httpc->flow_control_mark = httpc->flow_control_increment / 2;
2834 httpc->last_sent_time = GetTickCount();
2835 httpc->timer_cancelled = CreateEventW(NULL, FALSE, FALSE, NULL);
2837 timer_data = HeapAlloc(GetProcessHeap(), 0, sizeof(*timer_data));
2838 if (!timer_data)
2839 return ERROR_OUTOFMEMORY;
2840 timer_data->timer_param = httpc->in_request;
2841 timer_data->last_sent_time = &httpc->last_sent_time;
2842 timer_data->timer_cancelled = httpc->timer_cancelled;
2843 /* FIXME: should use CreateTimerQueueTimer when implemented */
2844 thread = CreateThread(NULL, 0, rpcrt4_http_timer_thread, timer_data, 0, NULL);
2845 if (!thread)
2847 HeapFree(GetProcessHeap(), 0, timer_data);
2848 return GetLastError();
2850 CloseHandle(thread);
2852 return RPC_S_OK;
2855 static RPC_STATUS rpcrt4_ncacn_http_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
2857 assert(0);
2858 return RPC_S_SERVER_UNAVAILABLE;
2861 static int rpcrt4_ncacn_http_read(RpcConnection *Connection,
2862 void *buffer, unsigned int count)
2864 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2865 return rpcrt4_http_async_read(httpc->out_request, httpc->async_data, httpc->cancel_event, buffer, count);
2868 static RPC_STATUS rpcrt4_ncacn_http_receive_fragment(RpcConnection *Connection, RpcPktHdr **Header, void **Payload)
2870 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
2871 RPC_STATUS status;
2872 DWORD hdr_length;
2873 LONG dwRead;
2874 RpcPktCommonHdr common_hdr;
2876 *Header = NULL;
2878 TRACE("(%p, %p, %p)\n", Connection, Header, Payload);
2880 again:
2881 /* read packet common header */
2882 dwRead = rpcrt4_ncacn_http_read(Connection, &common_hdr, sizeof(common_hdr));
2883 if (dwRead != sizeof(common_hdr)) {
2884 WARN("Short read of header, %ld bytes\n", dwRead);
2885 status = RPC_S_PROTOCOL_ERROR;
2886 goto fail;
2888 if (!memcmp(&common_hdr, "HTTP/1.1", sizeof("HTTP/1.1")) ||
2889 !memcmp(&common_hdr, "HTTP/1.0", sizeof("HTTP/1.0")))
2891 FIXME("server returned %s\n", debugstr_a((const char *)&common_hdr));
2892 status = RPC_S_PROTOCOL_ERROR;
2893 goto fail;
2896 status = RPCRT4_ValidateCommonHeader(&common_hdr);
2897 if (status != RPC_S_OK) goto fail;
2899 hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr);
2900 if (hdr_length == 0) {
2901 WARN("header length == 0\n");
2902 status = RPC_S_PROTOCOL_ERROR;
2903 goto fail;
2906 *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length);
2907 if (!*Header)
2909 status = RPC_S_OUT_OF_RESOURCES;
2910 goto fail;
2912 memcpy(*Header, &common_hdr, sizeof(common_hdr));
2914 /* read the rest of packet header */
2915 dwRead = rpcrt4_ncacn_http_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr));
2916 if (dwRead != hdr_length - sizeof(common_hdr)) {
2917 WARN("bad header length, %ld bytes, hdr_length %ld\n", dwRead, hdr_length);
2918 status = RPC_S_PROTOCOL_ERROR;
2919 goto fail;
2922 if (common_hdr.frag_len - hdr_length)
2924 *Payload = HeapAlloc(GetProcessHeap(), 0, common_hdr.frag_len - hdr_length);
2925 if (!*Payload)
2927 status = RPC_S_OUT_OF_RESOURCES;
2928 goto fail;
2931 dwRead = rpcrt4_ncacn_http_read(Connection, *Payload, common_hdr.frag_len - hdr_length);
2932 if (dwRead != common_hdr.frag_len - hdr_length)
2934 WARN("bad data length, %ld/%ld\n", dwRead, common_hdr.frag_len - hdr_length);
2935 status = RPC_S_PROTOCOL_ERROR;
2936 goto fail;
2939 else
2940 *Payload = NULL;
2942 if ((*Header)->common.ptype == PKT_HTTP)
2944 if (!RPCRT4_IsValidHttpPacket(*Header, *Payload, common_hdr.frag_len - hdr_length))
2946 ERR("invalid http packet of length %d bytes\n", (*Header)->common.frag_len);
2947 status = RPC_S_PROTOCOL_ERROR;
2948 goto fail;
2950 if ((*Header)->http.flags == 0x0001)
2952 TRACE("http idle packet, waiting for real packet\n");
2953 if ((*Header)->http.num_data_items != 0)
2955 ERR("HTTP idle packet should have no data items instead of %d\n", (*Header)->http.num_data_items);
2956 status = RPC_S_PROTOCOL_ERROR;
2957 goto fail;
2960 else if ((*Header)->http.flags == 0x0002)
2962 ULONG bytes_transmitted;
2963 ULONG flow_control_increment;
2964 UUID pipe_uuid;
2965 status = RPCRT4_ParseHttpFlowControlHeader(*Header, *Payload,
2966 Connection->server,
2967 &bytes_transmitted,
2968 &flow_control_increment,
2969 &pipe_uuid);
2970 if (status != RPC_S_OK)
2971 goto fail;
2972 TRACE("received http flow control header (0x%lx, 0x%lx, %s)\n",
2973 bytes_transmitted, flow_control_increment, debugstr_guid(&pipe_uuid));
2974 /* FIXME: do something with parsed data */
2976 else
2978 FIXME("unrecognised http packet with flags 0x%04x\n", (*Header)->http.flags);
2979 status = RPC_S_PROTOCOL_ERROR;
2980 goto fail;
2982 RPCRT4_FreeHeader(*Header);
2983 *Header = NULL;
2984 HeapFree(GetProcessHeap(), 0, *Payload);
2985 *Payload = NULL;
2986 goto again;
2989 /* success */
2990 status = RPC_S_OK;
2992 httpc->bytes_received += common_hdr.frag_len;
2994 TRACE("httpc->bytes_received = 0x%lx\n", httpc->bytes_received);
2996 if (httpc->bytes_received > httpc->flow_control_mark)
2998 RpcPktHdr *hdr = RPCRT4_BuildHttpFlowControlHeader(httpc->common.server,
2999 httpc->bytes_received,
3000 httpc->flow_control_increment,
3001 &httpc->out_pipe_uuid);
3002 if (hdr)
3004 DWORD bytes_written;
3005 BOOL ret2;
3006 TRACE("sending flow control packet at 0x%lx\n", httpc->bytes_received);
3007 ret2 = InternetWriteFile(httpc->in_request, hdr, hdr->common.frag_len, &bytes_written);
3008 RPCRT4_FreeHeader(hdr);
3009 if (ret2)
3010 httpc->flow_control_mark = httpc->bytes_received + httpc->flow_control_increment / 2;
3014 fail:
3015 if (status != RPC_S_OK) {
3016 RPCRT4_FreeHeader(*Header);
3017 *Header = NULL;
3018 HeapFree(GetProcessHeap(), 0, *Payload);
3019 *Payload = NULL;
3021 return status;
3024 static int rpcrt4_ncacn_http_write(RpcConnection *Connection,
3025 const void *buffer, unsigned int count)
3027 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3028 DWORD bytes_written;
3029 BOOL ret;
3031 httpc->last_sent_time = ~0U; /* disable idle packet sending */
3032 ret = InternetWriteFile(httpc->in_request, buffer, count, &bytes_written);
3033 httpc->last_sent_time = GetTickCount();
3034 TRACE("%p %p %u -> %s\n", httpc->in_request, buffer, count, ret ? "TRUE" : "FALSE");
3035 return ret ? bytes_written : -1;
3038 static int rpcrt4_ncacn_http_close(RpcConnection *Connection)
3040 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3042 TRACE("\n");
3044 SetEvent(httpc->timer_cancelled);
3045 if (httpc->in_request)
3046 InternetCloseHandle(httpc->in_request);
3047 httpc->in_request = NULL;
3048 if (httpc->out_request)
3049 InternetCloseHandle(httpc->out_request);
3050 httpc->out_request = NULL;
3051 if (httpc->app_info)
3052 InternetCloseHandle(httpc->app_info);
3053 httpc->app_info = NULL;
3054 if (httpc->session)
3055 InternetCloseHandle(httpc->session);
3056 httpc->session = NULL;
3057 RpcHttpAsyncData_Release(httpc->async_data);
3058 if (httpc->cancel_event)
3059 CloseHandle(httpc->cancel_event);
3060 HeapFree(GetProcessHeap(), 0, httpc->servername);
3061 httpc->servername = NULL;
3063 return 0;
3066 static void rpcrt4_ncacn_http_close_read(RpcConnection *conn)
3068 rpcrt4_ncacn_http_close(conn); /* FIXME */
3071 static void rpcrt4_ncacn_http_cancel_call(RpcConnection *Connection)
3073 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3075 SetEvent(httpc->cancel_event);
3078 static RPC_STATUS rpcrt4_ncacn_http_is_server_listening(const char *endpoint)
3080 FIXME("\n");
3081 return RPC_S_ACCESS_DENIED;
3084 static int rpcrt4_ncacn_http_wait_for_incoming_data(RpcConnection *Connection)
3086 RpcConnection_http *httpc = (RpcConnection_http *) Connection;
3087 BOOL ret;
3088 RPC_STATUS status;
3090 prepare_async_request(httpc->async_data);
3091 ret = InternetQueryDataAvailable(httpc->out_request,
3092 &httpc->async_data->inet_buffers.dwBufferLength, IRF_ASYNC, 0);
3093 status = wait_async_request(httpc->async_data, ret, httpc->cancel_event);
3094 return status == RPC_S_OK ? 0 : -1;
3097 static size_t rpcrt4_ncacn_http_get_top_of_tower(unsigned char *tower_data,
3098 const char *networkaddr,
3099 const char *endpoint)
3101 return rpcrt4_ip_tcp_get_top_of_tower(tower_data, networkaddr,
3102 EPM_PROTOCOL_HTTP, endpoint);
3105 static RPC_STATUS rpcrt4_ncacn_http_parse_top_of_tower(const unsigned char *tower_data,
3106 size_t tower_size,
3107 char **networkaddr,
3108 char **endpoint)
3110 return rpcrt4_ip_tcp_parse_top_of_tower(tower_data, tower_size,
3111 networkaddr, EPM_PROTOCOL_HTTP,
3112 endpoint);
3115 static const struct connection_ops conn_protseq_list[] = {
3116 { "ncacn_np",
3117 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
3118 rpcrt4_conn_np_alloc,
3119 rpcrt4_ncacn_np_open,
3120 rpcrt4_ncacn_np_handoff,
3121 rpcrt4_conn_np_read,
3122 rpcrt4_conn_np_write,
3123 rpcrt4_conn_np_close,
3124 rpcrt4_conn_np_close_read,
3125 rpcrt4_conn_np_cancel_call,
3126 rpcrt4_ncacn_np_is_server_listening,
3127 rpcrt4_conn_np_wait_for_incoming_data,
3128 rpcrt4_ncacn_np_get_top_of_tower,
3129 rpcrt4_ncacn_np_parse_top_of_tower,
3130 NULL,
3131 RPCRT4_default_is_authorized,
3132 RPCRT4_default_authorize,
3133 RPCRT4_default_secure_packet,
3134 rpcrt4_conn_np_impersonate_client,
3135 rpcrt4_conn_np_revert_to_self,
3136 RPCRT4_default_inquire_auth_client,
3138 { "ncalrpc",
3139 { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
3140 rpcrt4_conn_np_alloc,
3141 rpcrt4_ncalrpc_open,
3142 rpcrt4_ncalrpc_handoff,
3143 rpcrt4_conn_np_read,
3144 rpcrt4_conn_np_write,
3145 rpcrt4_conn_np_close,
3146 rpcrt4_conn_np_close_read,
3147 rpcrt4_conn_np_cancel_call,
3148 rpcrt4_ncalrpc_np_is_server_listening,
3149 rpcrt4_conn_np_wait_for_incoming_data,
3150 rpcrt4_ncalrpc_get_top_of_tower,
3151 rpcrt4_ncalrpc_parse_top_of_tower,
3152 NULL,
3153 rpcrt4_ncalrpc_is_authorized,
3154 rpcrt4_ncalrpc_authorize,
3155 rpcrt4_ncalrpc_secure_packet,
3156 rpcrt4_conn_np_impersonate_client,
3157 rpcrt4_conn_np_revert_to_self,
3158 rpcrt4_ncalrpc_inquire_auth_client,
3160 { "ncacn_ip_tcp",
3161 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
3162 rpcrt4_conn_tcp_alloc,
3163 rpcrt4_ncacn_ip_tcp_open,
3164 rpcrt4_conn_tcp_handoff,
3165 rpcrt4_conn_tcp_read,
3166 rpcrt4_conn_tcp_write,
3167 rpcrt4_conn_tcp_close,
3168 rpcrt4_conn_tcp_close_read,
3169 rpcrt4_conn_tcp_cancel_call,
3170 rpcrt4_conn_tcp_is_server_listening,
3171 rpcrt4_conn_tcp_wait_for_incoming_data,
3172 rpcrt4_ncacn_ip_tcp_get_top_of_tower,
3173 rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
3174 NULL,
3175 RPCRT4_default_is_authorized,
3176 RPCRT4_default_authorize,
3177 RPCRT4_default_secure_packet,
3178 RPCRT4_default_impersonate_client,
3179 RPCRT4_default_revert_to_self,
3180 RPCRT4_default_inquire_auth_client,
3182 { "ncacn_http",
3183 { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_HTTP },
3184 rpcrt4_ncacn_http_alloc,
3185 rpcrt4_ncacn_http_open,
3186 rpcrt4_ncacn_http_handoff,
3187 rpcrt4_ncacn_http_read,
3188 rpcrt4_ncacn_http_write,
3189 rpcrt4_ncacn_http_close,
3190 rpcrt4_ncacn_http_close_read,
3191 rpcrt4_ncacn_http_cancel_call,
3192 rpcrt4_ncacn_http_is_server_listening,
3193 rpcrt4_ncacn_http_wait_for_incoming_data,
3194 rpcrt4_ncacn_http_get_top_of_tower,
3195 rpcrt4_ncacn_http_parse_top_of_tower,
3196 rpcrt4_ncacn_http_receive_fragment,
3197 RPCRT4_default_is_authorized,
3198 RPCRT4_default_authorize,
3199 RPCRT4_default_secure_packet,
3200 RPCRT4_default_impersonate_client,
3201 RPCRT4_default_revert_to_self,
3202 RPCRT4_default_inquire_auth_client,
3207 static const struct protseq_ops protseq_list[] =
3210 "ncacn_np",
3211 rpcrt4_protseq_np_alloc,
3212 rpcrt4_protseq_np_signal_state_changed,
3213 rpcrt4_protseq_np_get_wait_array,
3214 rpcrt4_protseq_np_free_wait_array,
3215 rpcrt4_protseq_np_wait_for_new_connection,
3216 rpcrt4_protseq_ncacn_np_open_endpoint,
3219 "ncalrpc",
3220 rpcrt4_protseq_np_alloc,
3221 rpcrt4_protseq_np_signal_state_changed,
3222 rpcrt4_protseq_np_get_wait_array,
3223 rpcrt4_protseq_np_free_wait_array,
3224 rpcrt4_protseq_np_wait_for_new_connection,
3225 rpcrt4_protseq_ncalrpc_open_endpoint,
3228 "ncacn_ip_tcp",
3229 rpcrt4_protseq_sock_alloc,
3230 rpcrt4_protseq_sock_signal_state_changed,
3231 rpcrt4_protseq_sock_get_wait_array,
3232 rpcrt4_protseq_sock_free_wait_array,
3233 rpcrt4_protseq_sock_wait_for_new_connection,
3234 rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
3238 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
3240 unsigned int i;
3241 for(i = 0; i < ARRAY_SIZE(protseq_list); i++)
3242 if (!strcmp(protseq_list[i].name, protseq))
3243 return &protseq_list[i];
3244 return NULL;
3247 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
3249 unsigned int i;
3250 for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++)
3251 if (!strcmp(conn_protseq_list[i].name, protseq))
3252 return &conn_protseq_list[i];
3253 return NULL;
3256 /**** interface to rest of code ****/
3258 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
3260 TRACE("(Connection == ^%p)\n", Connection);
3262 assert(!Connection->server);
3263 return Connection->ops->open_connection_client(Connection);
3266 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
3268 TRACE("(Connection == ^%p)\n", Connection);
3269 if (SecIsValidHandle(&Connection->ctx))
3271 DeleteSecurityContext(&Connection->ctx);
3272 SecInvalidateHandle(&Connection->ctx);
3274 rpcrt4_conn_close(Connection);
3275 return RPC_S_OK;
3278 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
3279 LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
3280 LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS, LPCWSTR CookieAuth)
3282 static LONG next_id;
3283 const struct connection_ops *ops;
3284 RpcConnection* NewConnection;
3286 ops = rpcrt4_get_conn_protseq_ops(Protseq);
3287 if (!ops)
3289 FIXME("not supported for protseq %s\n", Protseq);
3290 return RPC_S_PROTSEQ_NOT_SUPPORTED;
3293 NewConnection = ops->alloc();
3294 NewConnection->ref = 1;
3295 NewConnection->server = server;
3296 NewConnection->ops = ops;
3297 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
3298 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
3299 NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
3300 NewConnection->CookieAuth = RPCRT4_strdupW(CookieAuth);
3301 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
3302 NewConnection->NextCallId = 1;
3304 SecInvalidateHandle(&NewConnection->ctx);
3305 if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
3306 NewConnection->AuthInfo = AuthInfo;
3307 NewConnection->auth_context_id = InterlockedIncrement( &next_id );
3308 if (QOS) RpcQualityOfService_AddRef(QOS);
3309 NewConnection->QOS = QOS;
3311 list_init(&NewConnection->conn_pool_entry);
3312 list_init(&NewConnection->protseq_entry);
3314 TRACE("connection: %p\n", NewConnection);
3315 *Connection = NewConnection;
3317 return RPC_S_OK;
3320 static RpcConnection *rpcrt4_spawn_connection(RpcConnection *old_connection)
3322 RpcConnection *connection;
3323 RPC_STATUS err;
3325 err = RPCRT4_CreateConnection(&connection, old_connection->server, rpcrt4_conn_get_name(old_connection),
3326 old_connection->NetworkAddr, old_connection->Endpoint, NULL,
3327 old_connection->AuthInfo, old_connection->QOS, old_connection->CookieAuth);
3328 if (err != RPC_S_OK)
3329 return NULL;
3331 rpcrt4_conn_handoff(old_connection, connection);
3332 if (old_connection->protseq)
3334 EnterCriticalSection(&old_connection->protseq->cs);
3335 connection->protseq = old_connection->protseq;
3336 list_add_tail(&old_connection->protseq->connections, &connection->protseq_entry);
3337 LeaveCriticalSection(&old_connection->protseq->cs);
3339 return connection;
3342 void rpcrt4_conn_release_and_wait(RpcConnection *connection)
3344 HANDLE event = NULL;
3346 if (connection->ref > 1)
3347 event = connection->wait_release = CreateEventW(NULL, TRUE, FALSE, NULL);
3349 RPCRT4_ReleaseConnection(connection);
3351 if(event)
3353 WaitForSingleObject(event, INFINITE);
3354 CloseHandle(event);
3358 RpcConnection *RPCRT4_GrabConnection(RpcConnection *connection)
3360 LONG ref = InterlockedIncrement(&connection->ref);
3361 TRACE("%p ref=%lu\n", connection, ref);
3362 return connection;
3365 void RPCRT4_ReleaseConnection(RpcConnection *connection)
3367 LONG ref;
3369 /* protseq stores a list of active connections, but does not own references to them.
3370 * It may need to grab a connection from the list, which could lead to a race if
3371 * connection is being released, but not yet removed from the list. We handle that
3372 * by synchronizing on CS here. */
3373 if (connection->protseq)
3375 EnterCriticalSection(&connection->protseq->cs);
3376 ref = InterlockedDecrement(&connection->ref);
3377 if (!ref)
3378 list_remove(&connection->protseq_entry);
3379 LeaveCriticalSection(&connection->protseq->cs);
3381 else
3383 ref = InterlockedDecrement(&connection->ref);
3386 TRACE("%p ref=%lu\n", connection, ref);
3388 if (!ref)
3390 RPCRT4_CloseConnection(connection);
3391 RPCRT4_strfree(connection->Endpoint);
3392 RPCRT4_strfree(connection->NetworkAddr);
3393 HeapFree(GetProcessHeap(), 0, connection->NetworkOptions);
3394 HeapFree(GetProcessHeap(), 0, connection->CookieAuth);
3395 if (connection->AuthInfo) RpcAuthInfo_Release(connection->AuthInfo);
3396 if (connection->QOS) RpcQualityOfService_Release(connection->QOS);
3398 /* server-only */
3399 if (connection->server_binding) RPCRT4_ReleaseBinding(connection->server_binding);
3400 else if (connection->assoc) RpcAssoc_ConnectionReleased(connection->assoc);
3402 if (connection->wait_release) SetEvent(connection->wait_release);
3404 HeapFree(GetProcessHeap(), 0, connection);
3408 RPC_STATUS RPCRT4_IsServerListening(const char *protseq, const char *endpoint)
3410 const struct connection_ops *ops;
3412 ops = rpcrt4_get_conn_protseq_ops(protseq);
3413 if (!ops)
3415 FIXME("not supported for protseq %s\n", protseq);
3416 return RPC_S_INVALID_BINDING;
3419 return ops->is_server_listening(endpoint);
3422 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
3423 size_t *tower_size,
3424 const char *protseq,
3425 const char *networkaddr,
3426 const char *endpoint)
3428 twr_empty_floor_t *protocol_floor;
3429 const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
3431 *tower_size = 0;
3433 if (!protseq_ops)
3434 return RPC_S_INVALID_RPC_PROTSEQ;
3436 if (!tower_data)
3438 *tower_size = sizeof(*protocol_floor);
3439 *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
3440 return RPC_S_OK;
3443 protocol_floor = (twr_empty_floor_t *)tower_data;
3444 protocol_floor->count_lhs = sizeof(protocol_floor->protid);
3445 protocol_floor->protid = protseq_ops->epm_protocols[0];
3446 protocol_floor->count_rhs = 0;
3448 tower_data += sizeof(*protocol_floor);
3450 *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
3451 if (!*tower_size)
3452 return EPT_S_NOT_REGISTERED;
3454 *tower_size += sizeof(*protocol_floor);
3456 return RPC_S_OK;
3459 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
3460 size_t tower_size,
3461 char **protseq,
3462 char **networkaddr,
3463 char **endpoint)
3465 const twr_empty_floor_t *protocol_floor;
3466 const twr_empty_floor_t *floor4;
3467 const struct connection_ops *protseq_ops = NULL;
3468 RPC_STATUS status;
3469 unsigned int i;
3471 if (tower_size < sizeof(*protocol_floor))
3472 return EPT_S_NOT_REGISTERED;
3474 protocol_floor = (const twr_empty_floor_t *)tower_data;
3475 tower_data += sizeof(*protocol_floor);
3476 tower_size -= sizeof(*protocol_floor);
3477 if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
3478 (protocol_floor->count_rhs > tower_size))
3479 return EPT_S_NOT_REGISTERED;
3480 tower_data += protocol_floor->count_rhs;
3481 tower_size -= protocol_floor->count_rhs;
3483 floor4 = (const twr_empty_floor_t *)tower_data;
3484 if ((tower_size < sizeof(*floor4)) ||
3485 (floor4->count_lhs != sizeof(floor4->protid)))
3486 return EPT_S_NOT_REGISTERED;
3488 for(i = 0; i < ARRAY_SIZE(conn_protseq_list); i++)
3489 if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
3490 (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
3492 protseq_ops = &conn_protseq_list[i];
3493 break;
3496 if (!protseq_ops)
3497 return EPT_S_NOT_REGISTERED;
3499 status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
3501 if ((status == RPC_S_OK) && protseq)
3503 *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
3504 strcpy(*protseq, protseq_ops->name);
3507 return status;
3510 /***********************************************************************
3511 * RpcNetworkIsProtseqValidW (RPCRT4.@)
3513 * Checks if the given protocol sequence is known by the RPC system.
3514 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
3517 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
3519 char ps[0x10];
3521 WideCharToMultiByte(CP_ACP, 0, protseq, -1,
3522 ps, sizeof ps, NULL, NULL);
3523 if (rpcrt4_get_conn_protseq_ops(ps))
3524 return RPC_S_OK;
3526 FIXME("Unknown protseq %s\n", debugstr_w(protseq));
3528 return RPC_S_INVALID_RPC_PROTSEQ;
3531 /***********************************************************************
3532 * RpcNetworkIsProtseqValidA (RPCRT4.@)
3534 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
3536 UNICODE_STRING protseqW;
3538 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
3540 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
3541 RtlFreeUnicodeString(&protseqW);
3542 return ret;
3544 return RPC_S_OUT_OF_MEMORY;
3547 /***********************************************************************
3548 * RpcProtseqVectorFreeA (RPCRT4.@)
3550 RPC_STATUS WINAPI RpcProtseqVectorFreeA(RPC_PROTSEQ_VECTORA **protseqs)
3552 TRACE("(%p)\n", protseqs);
3554 if (*protseqs)
3556 unsigned int i;
3557 for (i = 0; i < (*protseqs)->Count; i++)
3558 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3559 HeapFree(GetProcessHeap(), 0, *protseqs);
3560 *protseqs = NULL;
3562 return RPC_S_OK;
3565 /***********************************************************************
3566 * RpcProtseqVectorFreeW (RPCRT4.@)
3568 RPC_STATUS WINAPI RpcProtseqVectorFreeW(RPC_PROTSEQ_VECTORW **protseqs)
3570 TRACE("(%p)\n", protseqs);
3572 if (*protseqs)
3574 unsigned int i;
3575 for (i = 0; i < (*protseqs)->Count; i++)
3576 HeapFree(GetProcessHeap(), 0, (*protseqs)->Protseq[i]);
3577 HeapFree(GetProcessHeap(), 0, *protseqs);
3578 *protseqs = NULL;
3580 return RPC_S_OK;
3583 /***********************************************************************
3584 * RpcNetworkInqProtseqsW (RPCRT4.@)
3586 RPC_STATUS WINAPI RpcNetworkInqProtseqsW( RPC_PROTSEQ_VECTORW** protseqs )
3588 RPC_PROTSEQ_VECTORW *pvector;
3589 unsigned int i;
3590 RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3592 TRACE("(%p)\n", protseqs);
3594 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned short*)*ARRAY_SIZE(protseq_list)));
3595 if (!*protseqs)
3596 goto end;
3597 pvector = *protseqs;
3598 pvector->Count = 0;
3599 for (i = 0; i < ARRAY_SIZE(protseq_list); i++)
3601 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, (strlen(protseq_list[i].name)+1)*sizeof(unsigned short));
3602 if (pvector->Protseq[i] == NULL)
3603 goto end;
3604 MultiByteToWideChar(CP_ACP, 0, (CHAR*)protseq_list[i].name, -1,
3605 (WCHAR*)pvector->Protseq[i], strlen(protseq_list[i].name) + 1);
3606 pvector->Count++;
3608 status = RPC_S_OK;
3610 end:
3611 if (status != RPC_S_OK)
3612 RpcProtseqVectorFreeW(protseqs);
3613 return status;
3616 /***********************************************************************
3617 * RpcNetworkInqProtseqsA (RPCRT4.@)
3619 RPC_STATUS WINAPI RpcNetworkInqProtseqsA(RPC_PROTSEQ_VECTORA** protseqs)
3621 RPC_PROTSEQ_VECTORA *pvector;
3622 unsigned int i;
3623 RPC_STATUS status = RPC_S_OUT_OF_MEMORY;
3625 TRACE("(%p)\n", protseqs);
3627 *protseqs = HeapAlloc(GetProcessHeap(), 0, sizeof(RPC_PROTSEQ_VECTORW)+(sizeof(unsigned char*)*ARRAY_SIZE(protseq_list)));
3628 if (!*protseqs)
3629 goto end;
3630 pvector = *protseqs;
3631 pvector->Count = 0;
3632 for (i = 0; i < ARRAY_SIZE(protseq_list); i++)
3634 pvector->Protseq[i] = HeapAlloc(GetProcessHeap(), 0, strlen(protseq_list[i].name)+1);
3635 if (pvector->Protseq[i] == NULL)
3636 goto end;
3637 strcpy((char*)pvector->Protseq[i], protseq_list[i].name);
3638 pvector->Count++;
3640 status = RPC_S_OK;
3642 end:
3643 if (status != RPC_S_OK)
3644 RpcProtseqVectorFreeA(protseqs);
3645 return status;