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