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