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