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