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