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