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