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