msi: Fixed buffer overflow in number parsing.
[wine] / dlls / rpcrt4 / rpc_transport.c
1 /*
2  * RPC transport layer
3  *
4  * Copyright 2001 Ove Kåven, TransGaming Technologies
5  * Copyright 2003 Mike Hearn
6  * Copyright 2004 Filip Navara
7  * Copyright 2006 Mike McCormack
8  * Copyright 2006 Damjan Jovanovic
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  */
25
26 #include "config.h"
27
28 #include <stdarg.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <fcntl.h>
38 #include <stdlib.h>
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif
43 #ifdef HAVE_NETINET_IN_H
44 # include <netinet/in.h>
45 #endif
46 #ifdef HAVE_NETINET_TCP_H
47 # include <netinet/tcp.h>
48 #endif
49 #ifdef HAVE_ARPA_INET_H
50 # include <arpa/inet.h>
51 #endif
52 #ifdef HAVE_NETDB_H
53 #include <netdb.h>
54 #endif
55 #ifdef HAVE_SYS_POLL_H
56 #include <sys/poll.h>
57 #endif
58
59 #include "windef.h"
60 #include "winbase.h"
61 #include "winnls.h"
62 #include "winerror.h"
63 #include "winternl.h"
64 #include "wine/unicode.h"
65
66 #include "rpc.h"
67 #include "rpcndr.h"
68
69 #include "wine/debug.h"
70
71 #include "rpc_binding.h"
72 #include "rpc_message.h"
73 #include "rpc_server.h"
74 #include "epm_towers.h"
75
76 #ifndef SOL_TCP
77 # define SOL_TCP IPPROTO_TCP
78 #endif
79
80 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
81
82 static CRITICAL_SECTION assoc_list_cs;
83 static CRITICAL_SECTION_DEBUG assoc_list_cs_debug =
84 {
85     0, 0, &assoc_list_cs,
86     { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList },
87       0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") }
88 };
89 static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 };
90
91 static struct list assoc_list = LIST_INIT(assoc_list);
92
93 /**** ncacn_np support ****/
94
95 typedef struct _RpcConnection_np
96 {
97   RpcConnection common;
98   HANDLE pipe;
99   OVERLAPPED ovl;
100   BOOL listening;
101 } RpcConnection_np;
102
103 static RpcConnection *rpcrt4_conn_np_alloc(void)
104 {
105   RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np));
106   if (npc)
107   {
108     npc->pipe = NULL;
109     memset(&npc->ovl, 0, sizeof(npc->ovl));
110     npc->listening = FALSE;
111   }
112   return &npc->common;
113 }
114
115 static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc)
116 {
117   if (npc->listening)
118     return RPC_S_OK;
119
120   npc->listening = TRUE;
121   if (ConnectNamedPipe(npc->pipe, &npc->ovl))
122     return RPC_S_OK;
123
124   if (GetLastError() == ERROR_PIPE_CONNECTED) {
125     SetEvent(npc->ovl.hEvent);
126     return RPC_S_OK;
127   }
128   if (GetLastError() == ERROR_IO_PENDING) {
129     /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */
130     return RPC_S_OK;
131   }
132   npc->listening = FALSE;
133   WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError());
134   return RPC_S_OUT_OF_RESOURCES;
135 }
136
137 static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname)
138 {
139   RpcConnection_np *npc = (RpcConnection_np *) Connection;
140   TRACE("listening on %s\n", pname);
141
142   npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX,
143                                PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
144                                PIPE_UNLIMITED_INSTANCES,
145                                RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
146   if (npc->pipe == INVALID_HANDLE_VALUE) {
147     WARN("CreateNamedPipe failed with error %d\n", GetLastError());
148     if (GetLastError() == ERROR_FILE_EXISTS)
149       return RPC_S_DUPLICATE_ENDPOINT;
150     else
151       return RPC_S_CANT_CREATE_ENDPOINT;
152   }
153
154   memset(&npc->ovl, 0, sizeof(npc->ovl));
155   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
156
157   /* Note: we don't call ConnectNamedPipe here because it must be done in the
158    * server thread as the thread must be alertable */
159   return RPC_S_OK;
160 }
161
162 static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait)
163 {
164   RpcConnection_np *npc = (RpcConnection_np *) Connection;
165   HANDLE pipe;
166   DWORD err, dwMode;
167
168   TRACE("connecting to %s\n", pname);
169
170   while (TRUE) {
171     DWORD dwFlags = 0;
172     if (Connection->QOS)
173     {
174         dwFlags = SECURITY_SQOS_PRESENT;
175         switch (Connection->QOS->qos->ImpersonationType)
176         {
177             case RPC_C_IMP_LEVEL_DEFAULT:
178                 /* FIXME: what to do here? */
179                 break;
180             case RPC_C_IMP_LEVEL_ANONYMOUS:
181                 dwFlags |= SECURITY_ANONYMOUS;
182                 break;
183             case RPC_C_IMP_LEVEL_IDENTIFY:
184                 dwFlags |= SECURITY_IDENTIFICATION;
185                 break;
186             case RPC_C_IMP_LEVEL_IMPERSONATE:
187                 dwFlags |= SECURITY_IMPERSONATION;
188                 break;
189             case RPC_C_IMP_LEVEL_DELEGATE:
190                 dwFlags |= SECURITY_DELEGATION;
191                 break;
192         }
193         if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC)
194             dwFlags |= SECURITY_CONTEXT_TRACKING;
195     }
196     pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
197                        OPEN_EXISTING, dwFlags, 0);
198     if (pipe != INVALID_HANDLE_VALUE) break;
199     err = GetLastError();
200     if (err == ERROR_PIPE_BUSY) {
201       TRACE("connection failed, error=%x\n", err);
202       return RPC_S_SERVER_TOO_BUSY;
203     }
204     if (!wait)
205       return RPC_S_SERVER_UNAVAILABLE;
206     if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
207       err = GetLastError();
208       WARN("connection failed, error=%x\n", err);
209       return RPC_S_SERVER_UNAVAILABLE;
210     }
211   }
212
213   /* success */
214   memset(&npc->ovl, 0, sizeof(npc->ovl));
215   /* pipe is connected; change to message-read mode. */
216   dwMode = PIPE_READMODE_MESSAGE;
217   SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
218   npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
219   npc->pipe = pipe;
220
221   return RPC_S_OK;
222 }
223
224 static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection)
225 {
226   RpcConnection_np *npc = (RpcConnection_np *) Connection;
227   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
228   RPC_STATUS r;
229   LPSTR pname;
230
231   /* already connected? */
232   if (npc->pipe)
233     return RPC_S_OK;
234
235   /* protseq=ncalrpc: supposed to use NT LPC ports,
236    * but we'll implement it with named pipes for now */
237   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
238   strcat(strcpy(pname, prefix), Connection->Endpoint);
239   r = rpcrt4_conn_open_pipe(Connection, pname, TRUE);
240   I_RpcFree(pname);
241
242   return r;
243 }
244
245 static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint)
246 {
247   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
248   RPC_STATUS r;
249   LPSTR pname;
250   RpcConnection *Connection;
251
252   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
253                               endpoint, NULL, NULL, NULL);
254   if (r != RPC_S_OK)
255       return r;
256
257   /* protseq=ncalrpc: supposed to use NT LPC ports,
258    * but we'll implement it with named pipes for now */
259   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
260   strcat(strcpy(pname, prefix), Connection->Endpoint);
261   r = rpcrt4_conn_create_pipe(Connection, pname);
262   I_RpcFree(pname);
263
264   EnterCriticalSection(&protseq->cs);
265   Connection->Next = protseq->conn;
266   protseq->conn = Connection;
267   LeaveCriticalSection(&protseq->cs);
268
269   return r;
270 }
271
272 static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection)
273 {
274   RpcConnection_np *npc = (RpcConnection_np *) Connection;
275   static const char prefix[] = "\\\\.";
276   RPC_STATUS r;
277   LPSTR pname;
278
279   /* already connected? */
280   if (npc->pipe)
281     return RPC_S_OK;
282
283   /* protseq=ncacn_np: named pipes */
284   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
285   strcat(strcpy(pname, prefix), Connection->Endpoint);
286   r = rpcrt4_conn_open_pipe(Connection, pname, FALSE);
287   I_RpcFree(pname);
288
289   return r;
290 }
291
292 static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
293 {
294   static const char prefix[] = "\\\\.";
295   RPC_STATUS r;
296   LPSTR pname;
297   RpcConnection *Connection;
298
299   r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL,
300                               endpoint, NULL, NULL, NULL);
301   if (r != RPC_S_OK)
302     return r;
303
304   /* protseq=ncacn_np: named pipes */
305   pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1);
306   strcat(strcpy(pname, prefix), Connection->Endpoint);
307   r = rpcrt4_conn_create_pipe(Connection, pname);
308   I_RpcFree(pname);
309
310   EnterCriticalSection(&protseq->cs);
311   Connection->Next = protseq->conn;
312   protseq->conn = Connection;
313   LeaveCriticalSection(&protseq->cs);
314
315   return r;
316 }
317
318 static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc)
319 {    
320   /* because of the way named pipes work, we'll transfer the connected pipe
321    * to the child, then reopen the server binding to continue listening */
322
323   new_npc->pipe = old_npc->pipe;
324   new_npc->ovl = old_npc->ovl;
325   old_npc->pipe = 0;
326   memset(&old_npc->ovl, 0, sizeof(old_npc->ovl));
327   old_npc->listening = FALSE;
328 }
329
330 static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
331 {
332   RPC_STATUS status;
333   LPSTR pname;
334   static const char prefix[] = "\\\\.";
335
336   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
337
338   pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
339   strcat(strcpy(pname, prefix), old_conn->Endpoint);
340   status = rpcrt4_conn_create_pipe(old_conn, pname);
341   I_RpcFree(pname);
342
343   return status;
344 }
345
346 static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
347 {
348   RPC_STATUS status;
349   LPSTR pname;
350   static const char prefix[] = "\\\\.\\pipe\\lrpc\\";
351
352   TRACE("%s\n", old_conn->Endpoint);
353
354   rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn);
355
356   pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1);
357   strcat(strcpy(pname, prefix), old_conn->Endpoint);
358   status = rpcrt4_conn_create_pipe(old_conn, pname);
359   I_RpcFree(pname);
360     
361   return status;
362 }
363
364 static int rpcrt4_conn_np_read(RpcConnection *Connection,
365                         void *buffer, unsigned int count)
366 {
367   RpcConnection_np *npc = (RpcConnection_np *) Connection;
368   char *buf = buffer;
369   BOOL ret = TRUE;
370   unsigned int bytes_left = count;
371
372   while (bytes_left)
373   {
374     DWORD bytes_read;
375     ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL);
376     if (!ret || !bytes_read)
377         break;
378     bytes_left -= bytes_read;
379     buf += bytes_read;
380   }
381   return ret ? count : -1;
382 }
383
384 static int rpcrt4_conn_np_write(RpcConnection *Connection,
385                              const void *buffer, unsigned int count)
386 {
387   RpcConnection_np *npc = (RpcConnection_np *) Connection;
388   const char *buf = buffer;
389   BOOL ret = TRUE;
390   unsigned int bytes_left = count;
391
392   while (bytes_left)
393   {
394     DWORD bytes_written;
395     ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL);
396     if (!ret || !bytes_written)
397         break;
398     bytes_left -= bytes_written;
399     buf += bytes_written;
400   }
401   return ret ? count : -1;
402 }
403
404 static int rpcrt4_conn_np_close(RpcConnection *Connection)
405 {
406   RpcConnection_np *npc = (RpcConnection_np *) Connection;
407   if (npc->pipe) {
408     FlushFileBuffers(npc->pipe);
409     CloseHandle(npc->pipe);
410     npc->pipe = 0;
411   }
412   if (npc->ovl.hEvent) {
413     CloseHandle(npc->ovl.hEvent);
414     npc->ovl.hEvent = 0;
415   }
416   return 0;
417 }
418
419 static void rpcrt4_conn_np_cancel_call(RpcConnection *Connection)
420 {
421     /* FIXME: implement when named pipe writes use overlapped I/O */
422 }
423
424 static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data,
425                                                const char *networkaddr,
426                                                const char *endpoint)
427 {
428     twr_empty_floor_t *smb_floor;
429     twr_empty_floor_t *nb_floor;
430     size_t size;
431     size_t networkaddr_size;
432     size_t endpoint_size;
433
434     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
435
436     networkaddr_size = strlen(networkaddr) + 1;
437     endpoint_size = strlen(endpoint) + 1;
438     size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size;
439
440     if (!tower_data)
441         return size;
442
443     smb_floor = (twr_empty_floor_t *)tower_data;
444
445     tower_data += sizeof(*smb_floor);
446
447     smb_floor->count_lhs = sizeof(smb_floor->protid);
448     smb_floor->protid = EPM_PROTOCOL_SMB;
449     smb_floor->count_rhs = endpoint_size;
450
451     memcpy(tower_data, endpoint, endpoint_size);
452     tower_data += endpoint_size;
453
454     nb_floor = (twr_empty_floor_t *)tower_data;
455
456     tower_data += sizeof(*nb_floor);
457
458     nb_floor->count_lhs = sizeof(nb_floor->protid);
459     nb_floor->protid = EPM_PROTOCOL_NETBIOS;
460     nb_floor->count_rhs = networkaddr_size;
461
462     memcpy(tower_data, networkaddr, networkaddr_size);
463     tower_data += networkaddr_size;
464
465     return size;
466 }
467
468 static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data,
469                                                      size_t tower_size,
470                                                      char **networkaddr,
471                                                      char **endpoint)
472 {
473     const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data;
474     const twr_empty_floor_t *nb_floor;
475
476     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
477
478     if (tower_size < sizeof(*smb_floor))
479         return EPT_S_NOT_REGISTERED;
480
481     tower_data += sizeof(*smb_floor);
482     tower_size -= sizeof(*smb_floor);
483
484     if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) ||
485         (smb_floor->protid != EPM_PROTOCOL_SMB) ||
486         (smb_floor->count_rhs > tower_size))
487         return EPT_S_NOT_REGISTERED;
488
489     if (endpoint)
490     {
491         *endpoint = I_RpcAllocate(smb_floor->count_rhs);
492         if (!*endpoint)
493             return RPC_S_OUT_OF_RESOURCES;
494         memcpy(*endpoint, tower_data, smb_floor->count_rhs);
495     }
496     tower_data += smb_floor->count_rhs;
497     tower_size -= smb_floor->count_rhs;
498
499     if (tower_size < sizeof(*nb_floor))
500         return EPT_S_NOT_REGISTERED;
501
502     nb_floor = (const twr_empty_floor_t *)tower_data;
503
504     tower_data += sizeof(*nb_floor);
505     tower_size -= sizeof(*nb_floor);
506
507     if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) ||
508         (nb_floor->protid != EPM_PROTOCOL_NETBIOS) ||
509         (nb_floor->count_rhs > tower_size))
510         return EPT_S_NOT_REGISTERED;
511
512     if (networkaddr)
513     {
514         *networkaddr = I_RpcAllocate(nb_floor->count_rhs);
515         if (!*networkaddr)
516         {
517             if (endpoint)
518             {
519                 I_RpcFree(*endpoint);
520                 *endpoint = NULL;
521             }
522             return RPC_S_OUT_OF_RESOURCES;
523         }
524         memcpy(*networkaddr, tower_data, nb_floor->count_rhs);
525     }
526
527     return RPC_S_OK;
528 }
529
530 typedef struct _RpcServerProtseq_np
531 {
532     RpcServerProtseq common;
533     HANDLE mgr_event;
534 } RpcServerProtseq_np;
535
536 static RpcServerProtseq *rpcrt4_protseq_np_alloc(void)
537 {
538     RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
539     if (ps)
540         ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL);
541     return &ps->common;
542 }
543
544 static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq)
545 {
546     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
547     SetEvent(npps->mgr_event);
548 }
549
550 static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
551 {
552     HANDLE *objs = prev_array;
553     RpcConnection_np *conn;
554     RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common);
555     
556     EnterCriticalSection(&protseq->cs);
557     
558     /* open and count connections */
559     *count = 1;
560     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
561     while (conn) {
562         rpcrt4_conn_listen_pipe(conn);
563         if (conn->ovl.hEvent)
564             (*count)++;
565         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
566     }
567     
568     /* make array of connections */
569     if (objs)
570         objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE));
571     else
572         objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE));
573     if (!objs)
574     {
575         ERR("couldn't allocate objs\n");
576         LeaveCriticalSection(&protseq->cs);
577         return NULL;
578     }
579     
580     objs[0] = npps->mgr_event;
581     *count = 1;
582     conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
583     while (conn) {
584         if ((objs[*count] = conn->ovl.hEvent))
585             (*count)++;
586         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
587     }
588     LeaveCriticalSection(&protseq->cs);
589     return objs;
590 }
591
592 static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array)
593 {
594     HeapFree(GetProcessHeap(), 0, array);
595 }
596
597 static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
598 {
599     HANDLE b_handle;
600     HANDLE *objs = wait_array;
601     DWORD res;
602     RpcConnection *cconn;
603     RpcConnection_np *conn;
604     
605     if (!objs)
606         return -1;
607
608     do
609     {
610         /* an alertable wait isn't strictly necessary, but due to our
611          * overlapped I/O implementation in Wine we need to free some memory
612          * by the file user APC being called, even if no completion routine was
613          * specified at the time of starting the async operation */
614         res = WaitForMultipleObjectsEx(count, objs, FALSE, INFINITE, TRUE);
615     } while (res == WAIT_IO_COMPLETION);
616
617     if (res == WAIT_OBJECT_0)
618         return 0;
619     else if (res == WAIT_FAILED)
620     {
621         ERR("wait failed with error %d\n", GetLastError());
622         return -1;
623     }
624     else
625     {
626         b_handle = objs[res - WAIT_OBJECT_0];
627         /* find which connection got a RPC */
628         EnterCriticalSection(&protseq->cs);
629         conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common);
630         while (conn) {
631             if (b_handle == conn->ovl.hEvent) break;
632             conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common);
633         }
634         cconn = NULL;
635         if (conn)
636             RPCRT4_SpawnConnection(&cconn, &conn->common);
637         else
638             ERR("failed to locate connection for handle %p\n", b_handle);
639         LeaveCriticalSection(&protseq->cs);
640         if (cconn)
641         {
642             RPCRT4_new_client(cconn);
643             return 1;
644         }
645         else return -1;
646     }
647 }
648
649 static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data,
650                                               const char *networkaddr,
651                                               const char *endpoint)
652 {
653     twr_empty_floor_t *pipe_floor;
654     size_t size;
655     size_t endpoint_size;
656
657     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
658
659     endpoint_size = strlen(networkaddr) + 1;
660     size = sizeof(*pipe_floor) + endpoint_size;
661
662     if (!tower_data)
663         return size;
664
665     pipe_floor = (twr_empty_floor_t *)tower_data;
666
667     tower_data += sizeof(*pipe_floor);
668
669     pipe_floor->count_lhs = sizeof(pipe_floor->protid);
670     pipe_floor->protid = EPM_PROTOCOL_SMB;
671     pipe_floor->count_rhs = endpoint_size;
672
673     memcpy(tower_data, endpoint, endpoint_size);
674     tower_data += endpoint_size;
675
676     return size;
677 }
678
679 static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data,
680                                                     size_t tower_size,
681                                                     char **networkaddr,
682                                                     char **endpoint)
683 {
684     const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data;
685
686     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
687
688     *networkaddr = NULL;
689     *endpoint = NULL;
690
691     if (tower_size < sizeof(*pipe_floor))
692         return EPT_S_NOT_REGISTERED;
693
694     tower_data += sizeof(*pipe_floor);
695     tower_size -= sizeof(*pipe_floor);
696
697     if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) ||
698         (pipe_floor->protid != EPM_PROTOCOL_SMB) ||
699         (pipe_floor->count_rhs > tower_size))
700         return EPT_S_NOT_REGISTERED;
701
702     if (endpoint)
703     {
704         *endpoint = I_RpcAllocate(pipe_floor->count_rhs);
705         if (!*endpoint)
706             return RPC_S_OUT_OF_RESOURCES;
707         memcpy(*endpoint, tower_data, pipe_floor->count_rhs);
708     }
709
710     return RPC_S_OK;
711 }
712
713 /**** ncacn_ip_tcp support ****/
714
715 typedef struct _RpcConnection_tcp
716 {
717   RpcConnection common;
718   int sock;
719   int cancel_fds[2];
720 } RpcConnection_tcp;
721
722 static RpcConnection *rpcrt4_conn_tcp_alloc(void)
723 {
724   RpcConnection_tcp *tcpc;
725   tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp));
726   if (tcpc == NULL)
727     return NULL;
728   tcpc->sock = -1;
729   if (socketpair(PF_UNIX, SOCK_STREAM, 0, tcpc->cancel_fds) < 0)
730   {
731     ERR("socketpair() failed: %s\n", strerror(errno));
732     HeapFree(GetProcessHeap(), 0, tcpc);
733     return NULL;
734   }
735   return &tcpc->common;
736 }
737
738 static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection)
739 {
740   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
741   int sock;
742   int ret;
743   struct addrinfo *ai;
744   struct addrinfo *ai_cur;
745   struct addrinfo hints;
746
747   TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint);
748
749   if (tcpc->sock != -1)
750     return RPC_S_OK;
751
752   hints.ai_flags          = 0;
753   hints.ai_family         = PF_UNSPEC;
754   hints.ai_socktype       = SOCK_STREAM;
755   hints.ai_protocol       = IPPROTO_TCP;
756   hints.ai_addrlen        = 0;
757   hints.ai_addr           = NULL;
758   hints.ai_canonname      = NULL;
759   hints.ai_next           = NULL;
760
761   ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai);
762   if (ret)
763   {
764     ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr,
765       Connection->Endpoint, gai_strerror(ret));
766     return RPC_S_SERVER_UNAVAILABLE;
767   }
768
769   for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
770   {
771     int val;
772
773     if (TRACE_ON(rpc))
774     {
775       char host[256];
776       char service[256];
777       getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
778         host, sizeof(host), service, sizeof(service),
779         NI_NUMERICHOST | NI_NUMERICSERV);
780       TRACE("trying %s:%s\n", host, service);
781     }
782
783     sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
784     if (sock == -1)
785     {
786       WARN("socket() failed: %s\n", strerror(errno));
787       continue;
788     }
789
790     if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen))
791     {
792       WARN("connect() failed: %s\n", strerror(errno));
793       close(sock);
794       continue;
795     }
796
797     /* RPC depends on having minimal latency so disable the Nagle algorithm */
798     val = 1;
799     setsockopt(sock, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
800     fcntl(sock, F_SETFL, O_NONBLOCK); /* make socket nonblocking */
801
802     tcpc->sock = sock;
803
804     freeaddrinfo(ai);
805     TRACE("connected\n");
806     return RPC_S_OK;
807   }
808
809   freeaddrinfo(ai);
810   ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint);
811   return RPC_S_SERVER_UNAVAILABLE;
812 }
813
814 static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint)
815 {
816     RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT;
817     int sock;
818     int ret;
819     struct addrinfo *ai;
820     struct addrinfo *ai_cur;
821     struct addrinfo hints;
822     RpcConnection *first_connection = NULL;
823
824     TRACE("(%p, %s)\n", protseq, endpoint);
825
826     hints.ai_flags          = AI_PASSIVE /* for non-localhost addresses */;
827     hints.ai_family         = PF_UNSPEC;
828     hints.ai_socktype       = SOCK_STREAM;
829     hints.ai_protocol       = IPPROTO_TCP;
830     hints.ai_addrlen        = 0;
831     hints.ai_addr           = NULL;
832     hints.ai_canonname      = NULL;
833     hints.ai_next           = NULL;
834
835     ret = getaddrinfo(NULL, endpoint, &hints, &ai);
836     if (ret)
837     {
838         ERR("getaddrinfo for port %s failed: %s\n", endpoint,
839             gai_strerror(ret));
840         if ((ret == EAI_SERVICE) || (ret == EAI_NONAME))
841             return RPC_S_INVALID_ENDPOINT_FORMAT;
842         return RPC_S_CANT_CREATE_ENDPOINT;
843     }
844
845     for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next)
846     {
847         RpcConnection_tcp *tcpc;
848         RPC_STATUS create_status;
849
850         if (TRACE_ON(rpc))
851         {
852             char host[256];
853             char service[256];
854             getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen,
855                         host, sizeof(host), service, sizeof(service),
856                         NI_NUMERICHOST | NI_NUMERICSERV);
857             TRACE("trying %s:%s\n", host, service);
858         }
859
860         sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol);
861         if (sock == -1)
862         {
863             WARN("socket() failed: %s\n", strerror(errno));
864             status = RPC_S_CANT_CREATE_ENDPOINT;
865             continue;
866         }
867
868         ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen);
869         if (ret < 0)
870         {
871             WARN("bind failed: %s\n", strerror(errno));
872             close(sock);
873             if (errno == EADDRINUSE)
874               status = RPC_S_DUPLICATE_ENDPOINT;
875             else
876               status = RPC_S_CANT_CREATE_ENDPOINT;
877             continue;
878         }
879         create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE,
880                                                 protseq->Protseq, NULL,
881                                                 endpoint, NULL, NULL, NULL);
882         if (create_status != RPC_S_OK)
883         {
884             close(sock);
885             status = create_status;
886             continue;
887         }
888
889         tcpc->sock = sock;
890         ret = listen(sock, protseq->MaxCalls);
891         if (ret < 0)
892         {
893             WARN("listen failed: %s\n", strerror(errno));
894             RPCRT4_DestroyConnection(&tcpc->common);
895             status = RPC_S_OUT_OF_RESOURCES;
896             continue;
897         }
898         /* need a non-blocking socket, otherwise accept() has a potential
899          * race-condition (poll() says it is readable, connection drops,
900          * and accept() blocks until the next connection comes...)
901          */
902         ret = fcntl(sock, F_SETFL, O_NONBLOCK);
903         if (ret < 0)
904         {
905             WARN("couldn't make socket non-blocking, error %d\n", ret);
906             RPCRT4_DestroyConnection(&tcpc->common);
907             status = RPC_S_OUT_OF_RESOURCES;
908             continue;
909         }
910
911         tcpc->common.Next = first_connection;
912         first_connection = &tcpc->common;
913     }
914
915     freeaddrinfo(ai);
916
917     /* if at least one connection was created for an endpoint then
918      * return success */
919     if (first_connection)
920     {
921         RpcConnection *conn;
922
923         /* find last element in list */
924         for (conn = first_connection; conn->Next; conn = conn->Next)
925             ;
926
927         EnterCriticalSection(&protseq->cs);
928         conn->Next = protseq->conn;
929         protseq->conn = first_connection;
930         LeaveCriticalSection(&protseq->cs);
931         
932         TRACE("listening on %s\n", endpoint);
933         return RPC_S_OK;
934     }
935
936     ERR("couldn't listen on port %s\n", endpoint);
937     return status;
938 }
939
940 static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn)
941 {
942   int ret;
943   struct sockaddr_in address;
944   socklen_t addrsize;
945   RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn;
946   RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn;
947
948   addrsize = sizeof(address);
949   ret = accept(server->sock, (struct sockaddr*) &address, &addrsize);
950   if (ret < 0)
951   {
952     ERR("Failed to accept a TCP connection: error %d\n", ret);
953     return RPC_S_OUT_OF_RESOURCES;
954   }
955   /* reset to blocking behaviour */
956   fcntl(ret, F_SETFL, 0);
957   client->sock = ret;
958   TRACE("Accepted a new TCP connection\n");
959   return RPC_S_OK;
960 }
961
962 static int rpcrt4_conn_tcp_read(RpcConnection *Connection,
963                                 void *buffer, unsigned int count)
964 {
965   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
966   int bytes_read = 0;
967   do
968   {
969     int r = recv(tcpc->sock, (char *)buffer + bytes_read, count - bytes_read, 0);
970     if (r >= 0)
971       bytes_read += r;
972     else if (errno != EAGAIN)
973       return -1;
974     else
975     {
976       struct pollfd pfds[2];
977       pfds[0].fd = tcpc->sock;
978       pfds[0].events = POLLIN;
979       pfds[1].fd = tcpc->cancel_fds[0];
980       pfds[1].events = POLLIN;
981       if (poll(pfds, 2, -1 /* infinite */) == -1 && errno != EINTR)
982       {
983         ERR("poll() failed: %s\n", strerror(errno));
984         return -1;
985       }
986       if (pfds[1].revents & POLLIN) /* canceled */
987       {
988         char dummy;
989         read(pfds[1].fd, &dummy, sizeof(dummy));
990         return -1;
991       }
992     }
993   } while (bytes_read != count);
994   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_read);
995   return bytes_read;
996 }
997
998 static int rpcrt4_conn_tcp_write(RpcConnection *Connection,
999                                  const void *buffer, unsigned int count)
1000 {
1001   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1002   int bytes_written = 0;
1003   do
1004   {
1005     int r = write(tcpc->sock, (const char *)buffer + bytes_written, count - bytes_written);
1006     if (r >= 0)
1007       bytes_written += r;
1008     else if (errno != EAGAIN)
1009       return -1;
1010     else
1011     {
1012       struct pollfd pfd;
1013       pfd.fd = tcpc->sock;
1014       pfd.events = POLLOUT;
1015       if (poll(&pfd, 1, -1 /* infinite */) == -1 && errno != EINTR)
1016       {
1017         ERR("poll() failed: %s\n", strerror(errno));
1018         return -1;
1019       }
1020     }
1021   } while (bytes_written != count);
1022   TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, bytes_written);
1023   return bytes_written;
1024 }
1025
1026 static int rpcrt4_conn_tcp_close(RpcConnection *Connection)
1027 {
1028   RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1029
1030   TRACE("%d\n", tcpc->sock);
1031
1032   if (tcpc->sock != -1)
1033     close(tcpc->sock);
1034   tcpc->sock = -1;
1035   close(tcpc->cancel_fds[0]);
1036   close(tcpc->cancel_fds[1]);
1037   return 0;
1038 }
1039
1040 static void rpcrt4_conn_tcp_cancel_call(RpcConnection *Connection)
1041 {
1042     RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection;
1043     char dummy = 1;
1044
1045     TRACE("%p\n", Connection);
1046
1047     write(tcpc->cancel_fds[1], &dummy, 1);
1048 }
1049
1050 static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data,
1051                                                    const char *networkaddr,
1052                                                    const char *endpoint)
1053 {
1054     twr_tcp_floor_t *tcp_floor;
1055     twr_ipv4_floor_t *ipv4_floor;
1056     struct addrinfo *ai;
1057     struct addrinfo hints;
1058     int ret;
1059     size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor);
1060
1061     TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint);
1062
1063     if (!tower_data)
1064         return size;
1065
1066     tcp_floor = (twr_tcp_floor_t *)tower_data;
1067     tower_data += sizeof(*tcp_floor);
1068
1069     ipv4_floor = (twr_ipv4_floor_t *)tower_data;
1070
1071     tcp_floor->count_lhs = sizeof(tcp_floor->protid);
1072     tcp_floor->protid = EPM_PROTOCOL_TCP;
1073     tcp_floor->count_rhs = sizeof(tcp_floor->port);
1074
1075     ipv4_floor->count_lhs = sizeof(ipv4_floor->protid);
1076     ipv4_floor->protid = EPM_PROTOCOL_IP;
1077     ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr);
1078
1079     hints.ai_flags          = AI_NUMERICHOST;
1080     /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */
1081     hints.ai_family         = PF_INET;
1082     hints.ai_socktype       = SOCK_STREAM;
1083     hints.ai_protocol       = IPPROTO_TCP;
1084     hints.ai_addrlen        = 0;
1085     hints.ai_addr           = NULL;
1086     hints.ai_canonname      = NULL;
1087     hints.ai_next           = NULL;
1088
1089     ret = getaddrinfo(networkaddr, endpoint, &hints, &ai);
1090     if (ret)
1091     {
1092         ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai);
1093         if (ret)
1094         {
1095             ERR("getaddrinfo failed: %s\n", gai_strerror(ret));
1096             return 0;
1097         }
1098     }
1099
1100     if (ai->ai_family == PF_INET)
1101     {
1102         const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr;
1103         tcp_floor->port = sin->sin_port;
1104         ipv4_floor->ipv4addr = sin->sin_addr.s_addr;
1105     }
1106     else
1107     {
1108         ERR("unexpected protocol family %d\n", ai->ai_family);
1109         return 0;
1110     }
1111
1112     freeaddrinfo(ai);
1113
1114     return size;
1115 }
1116
1117 static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data,
1118                                                          size_t tower_size,
1119                                                          char **networkaddr,
1120                                                          char **endpoint)
1121 {
1122     const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data;
1123     const twr_ipv4_floor_t *ipv4_floor;
1124     struct in_addr in_addr;
1125
1126     TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint);
1127
1128     if (tower_size < sizeof(*tcp_floor))
1129         return EPT_S_NOT_REGISTERED;
1130
1131     tower_data += sizeof(*tcp_floor);
1132     tower_size -= sizeof(*tcp_floor);
1133
1134     if (tower_size < sizeof(*ipv4_floor))
1135         return EPT_S_NOT_REGISTERED;
1136
1137     ipv4_floor = (const twr_ipv4_floor_t *)tower_data;
1138
1139     if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) ||
1140         (tcp_floor->protid != EPM_PROTOCOL_TCP) ||
1141         (tcp_floor->count_rhs != sizeof(tcp_floor->port)) ||
1142         (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) ||
1143         (ipv4_floor->protid != EPM_PROTOCOL_IP) ||
1144         (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr)))
1145         return EPT_S_NOT_REGISTERED;
1146
1147     if (endpoint)
1148     {
1149         *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */);
1150         if (!*endpoint)
1151             return RPC_S_OUT_OF_RESOURCES;
1152         sprintf(*endpoint, "%u", ntohs(tcp_floor->port));
1153     }
1154
1155     if (networkaddr)
1156     {
1157         *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN);
1158         if (!*networkaddr)
1159         {
1160             if (endpoint)
1161             {
1162                 I_RpcFree(*endpoint);
1163                 *endpoint = NULL;
1164             }
1165             return RPC_S_OUT_OF_RESOURCES;
1166         }
1167         in_addr.s_addr = ipv4_floor->ipv4addr;
1168         if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN))
1169         {
1170             ERR("inet_ntop: %s\n", strerror(errno));
1171             I_RpcFree(*networkaddr);
1172             *networkaddr = NULL;
1173             if (endpoint)
1174             {
1175                 I_RpcFree(*endpoint);
1176                 *endpoint = NULL;
1177             }
1178             return EPT_S_NOT_REGISTERED;
1179         }
1180     }
1181
1182     return RPC_S_OK;
1183 }
1184
1185 typedef struct _RpcServerProtseq_sock
1186 {
1187     RpcServerProtseq common;
1188     int mgr_event_rcv;
1189     int mgr_event_snd;
1190 } RpcServerProtseq_sock;
1191
1192 static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void)
1193 {
1194     RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps));
1195     if (ps)
1196     {
1197         int fds[2];
1198         if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds))
1199         {
1200             fcntl(fds[0], F_SETFL, O_NONBLOCK);
1201             fcntl(fds[1], F_SETFL, O_NONBLOCK);
1202             ps->mgr_event_rcv = fds[0];
1203             ps->mgr_event_snd = fds[1];
1204         }
1205         else
1206         {
1207             ERR("socketpair failed with error %s\n", strerror(errno));
1208             HeapFree(GetProcessHeap(), 0, ps);
1209             return NULL;
1210         }
1211     }
1212     return &ps->common;
1213 }
1214
1215 static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq)
1216 {
1217     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1218     char dummy = 1;
1219     write(sockps->mgr_event_snd, &dummy, sizeof(dummy));
1220 }
1221
1222 static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count)
1223 {
1224     struct pollfd *poll_info = prev_array;
1225     RpcConnection_tcp *conn;
1226     RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common);
1227
1228     EnterCriticalSection(&protseq->cs);
1229     
1230     /* open and count connections */
1231     *count = 1;
1232     conn = (RpcConnection_tcp *)protseq->conn;
1233     while (conn) {
1234         if (conn->sock != -1)
1235             (*count)++;
1236         conn = (RpcConnection_tcp *)conn->common.Next;
1237     }
1238     
1239     /* make array of connections */
1240     if (poll_info)
1241         poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info));
1242     else
1243         poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info));
1244     if (!poll_info)
1245     {
1246         ERR("couldn't allocate poll_info\n");
1247         LeaveCriticalSection(&protseq->cs);
1248         return NULL;
1249     }
1250
1251     poll_info[0].fd = sockps->mgr_event_rcv;
1252     poll_info[0].events = POLLIN;
1253     *count = 1;
1254     conn =  CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1255     while (conn) {
1256         if (conn->sock != -1)
1257         {
1258             poll_info[*count].fd = conn->sock;
1259             poll_info[*count].events = POLLIN;
1260             (*count)++;
1261         }
1262         conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1263     }
1264     LeaveCriticalSection(&protseq->cs);
1265     return poll_info;
1266 }
1267
1268 static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array)
1269 {
1270     HeapFree(GetProcessHeap(), 0, array);
1271 }
1272
1273 static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array)
1274 {
1275     struct pollfd *poll_info = wait_array;
1276     int ret, i;
1277     RpcConnection *cconn;
1278     RpcConnection_tcp *conn;
1279     
1280     if (!poll_info)
1281         return -1;
1282     
1283     ret = poll(poll_info, count, -1);
1284     if (ret < 0)
1285     {
1286         ERR("poll failed with error %d\n", ret);
1287         return -1;
1288     }
1289
1290     for (i = 0; i < count; i++)
1291         if (poll_info[i].revents & POLLIN)
1292         {
1293             /* RPC server event */
1294             if (i == 0)
1295             {
1296                 char dummy;
1297                 read(poll_info[0].fd, &dummy, sizeof(dummy));
1298                 return 0;
1299             }
1300
1301             /* find which connection got a RPC */
1302             EnterCriticalSection(&protseq->cs);
1303             conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common);
1304             while (conn) {
1305                 if (poll_info[i].fd == conn->sock) break;
1306                 conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common);
1307             }
1308             cconn = NULL;
1309             if (conn)
1310                 RPCRT4_SpawnConnection(&cconn, &conn->common);
1311             else
1312                 ERR("failed to locate connection for fd %d\n", poll_info[i].fd);
1313             LeaveCriticalSection(&protseq->cs);
1314             if (cconn)
1315                 RPCRT4_new_client(cconn);
1316             else
1317                 return -1;
1318         }
1319
1320     return 1;
1321 }
1322
1323 static const struct connection_ops conn_protseq_list[] = {
1324   { "ncacn_np",
1325     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB },
1326     rpcrt4_conn_np_alloc,
1327     rpcrt4_ncacn_np_open,
1328     rpcrt4_ncacn_np_handoff,
1329     rpcrt4_conn_np_read,
1330     rpcrt4_conn_np_write,
1331     rpcrt4_conn_np_close,
1332     rpcrt4_conn_np_cancel_call,
1333     rpcrt4_ncacn_np_get_top_of_tower,
1334     rpcrt4_ncacn_np_parse_top_of_tower,
1335   },
1336   { "ncalrpc",
1337     { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE },
1338     rpcrt4_conn_np_alloc,
1339     rpcrt4_ncalrpc_open,
1340     rpcrt4_ncalrpc_handoff,
1341     rpcrt4_conn_np_read,
1342     rpcrt4_conn_np_write,
1343     rpcrt4_conn_np_close,
1344     rpcrt4_conn_np_cancel_call,
1345     rpcrt4_ncalrpc_get_top_of_tower,
1346     rpcrt4_ncalrpc_parse_top_of_tower,
1347   },
1348   { "ncacn_ip_tcp",
1349     { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP },
1350     rpcrt4_conn_tcp_alloc,
1351     rpcrt4_ncacn_ip_tcp_open,
1352     rpcrt4_conn_tcp_handoff,
1353     rpcrt4_conn_tcp_read,
1354     rpcrt4_conn_tcp_write,
1355     rpcrt4_conn_tcp_close,
1356     rpcrt4_conn_tcp_cancel_call,
1357     rpcrt4_ncacn_ip_tcp_get_top_of_tower,
1358     rpcrt4_ncacn_ip_tcp_parse_top_of_tower,
1359   }
1360 };
1361
1362
1363 static const struct protseq_ops protseq_list[] =
1364 {
1365     {
1366         "ncacn_np",
1367         rpcrt4_protseq_np_alloc,
1368         rpcrt4_protseq_np_signal_state_changed,
1369         rpcrt4_protseq_np_get_wait_array,
1370         rpcrt4_protseq_np_free_wait_array,
1371         rpcrt4_protseq_np_wait_for_new_connection,
1372         rpcrt4_protseq_ncacn_np_open_endpoint,
1373     },
1374     {
1375         "ncalrpc",
1376         rpcrt4_protseq_np_alloc,
1377         rpcrt4_protseq_np_signal_state_changed,
1378         rpcrt4_protseq_np_get_wait_array,
1379         rpcrt4_protseq_np_free_wait_array,
1380         rpcrt4_protseq_np_wait_for_new_connection,
1381         rpcrt4_protseq_ncalrpc_open_endpoint,
1382     },
1383     {
1384         "ncacn_ip_tcp",
1385         rpcrt4_protseq_sock_alloc,
1386         rpcrt4_protseq_sock_signal_state_changed,
1387         rpcrt4_protseq_sock_get_wait_array,
1388         rpcrt4_protseq_sock_free_wait_array,
1389         rpcrt4_protseq_sock_wait_for_new_connection,
1390         rpcrt4_protseq_ncacn_ip_tcp_open_endpoint,
1391     },
1392 };
1393
1394 #define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0]))
1395
1396 const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq)
1397 {
1398   int i;
1399   for(i=0; i<ARRAYSIZE(protseq_list); i++)
1400     if (!strcmp(protseq_list[i].name, protseq))
1401       return &protseq_list[i];
1402   return NULL;
1403 }
1404
1405 static const struct connection_ops *rpcrt4_get_conn_protseq_ops(const char *protseq)
1406 {
1407     int i;
1408     for(i=0; i<ARRAYSIZE(conn_protseq_list); i++)
1409         if (!strcmp(conn_protseq_list[i].name, protseq))
1410             return &conn_protseq_list[i];
1411     return NULL;
1412 }
1413
1414 /**** interface to rest of code ****/
1415
1416 RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection)
1417 {
1418   TRACE("(Connection == ^%p)\n", Connection);
1419
1420   assert(!Connection->server);
1421   return Connection->ops->open_connection_client(Connection);
1422 }
1423
1424 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
1425 {
1426   TRACE("(Connection == ^%p)\n", Connection);
1427   if (SecIsValidHandle(&Connection->ctx))
1428   {
1429     DeleteSecurityContext(&Connection->ctx);
1430     SecInvalidateHandle(&Connection->ctx);
1431   }
1432   rpcrt4_conn_close(Connection);
1433   return RPC_S_OK;
1434 }
1435
1436 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server,
1437     LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint,
1438     LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS)
1439 {
1440   const struct connection_ops *ops;
1441   RpcConnection* NewConnection;
1442
1443   ops = rpcrt4_get_conn_protseq_ops(Protseq);
1444   if (!ops)
1445   {
1446     FIXME("not supported for protseq %s\n", Protseq);
1447     return RPC_S_PROTSEQ_NOT_SUPPORTED;
1448   }
1449
1450   NewConnection = ops->alloc();
1451   NewConnection->Next = NULL;
1452   NewConnection->server = server;
1453   NewConnection->ops = ops;
1454   NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1455   NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
1456   NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions);
1457   NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
1458   memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface));
1459   NewConnection->NextCallId = 1;
1460
1461   SecInvalidateHandle(&NewConnection->ctx);
1462   memset(&NewConnection->exp, 0, sizeof(NewConnection->exp));
1463   NewConnection->attr = 0;
1464   if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo);
1465   NewConnection->AuthInfo = AuthInfo;
1466   NewConnection->encryption_auth_len = 0;
1467   NewConnection->signature_auth_len = 0;
1468   if (QOS) RpcQualityOfService_AddRef(QOS);
1469   NewConnection->QOS = QOS;
1470
1471   list_init(&NewConnection->conn_pool_entry);
1472
1473   TRACE("connection: %p\n", NewConnection);
1474   *Connection = NewConnection;
1475
1476   return RPC_S_OK;
1477 }
1478
1479 RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr,
1480                                  LPCSTR Endpoint, LPCWSTR NetworkOptions,
1481                                  RpcAssoc **assoc_out)
1482 {
1483   RpcAssoc *assoc;
1484
1485   EnterCriticalSection(&assoc_list_cs);
1486   LIST_FOR_EACH_ENTRY(assoc, &assoc_list, RpcAssoc, entry)
1487   {
1488     if (!strcmp(Protseq, assoc->Protseq) &&
1489         !strcmp(NetworkAddr, assoc->NetworkAddr) &&
1490         !strcmp(Endpoint, assoc->Endpoint) &&
1491         ((!assoc->NetworkOptions && !NetworkOptions) || !strcmpW(NetworkOptions, assoc->NetworkOptions)))
1492     {
1493       assoc->refs++;
1494       *assoc_out = assoc;
1495       LeaveCriticalSection(&assoc_list_cs);
1496       TRACE("using existing assoc %p\n", assoc);
1497       return RPC_S_OK;
1498     }
1499   }
1500
1501   assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc));
1502   if (!assoc)
1503   {
1504     LeaveCriticalSection(&assoc_list_cs);
1505     return RPC_S_OUT_OF_RESOURCES;
1506   }
1507   assoc->refs = 1;
1508   list_init(&assoc->connection_pool);
1509   InitializeCriticalSection(&assoc->cs);
1510   assoc->Protseq = RPCRT4_strdupA(Protseq);
1511   assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
1512   assoc->Endpoint = RPCRT4_strdupA(Endpoint);
1513   assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL;
1514   assoc->assoc_group_id = 0;
1515   list_add_head(&assoc_list, &assoc->entry);
1516   *assoc_out = assoc;
1517
1518   LeaveCriticalSection(&assoc_list_cs);
1519
1520   TRACE("new assoc %p\n", assoc);
1521
1522   return RPC_S_OK;
1523 }
1524
1525 ULONG RpcAssoc_Release(RpcAssoc *assoc)
1526 {
1527   ULONG refs;
1528
1529   EnterCriticalSection(&assoc_list_cs);
1530   refs = --assoc->refs;
1531   if (!refs)
1532     list_remove(&assoc->entry);
1533   LeaveCriticalSection(&assoc_list_cs);
1534
1535   if (!refs)
1536   {
1537     RpcConnection *Connection, *cursor2;
1538
1539     TRACE("destroying assoc %p\n", assoc);
1540
1541     LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->connection_pool, RpcConnection, conn_pool_entry)
1542     {
1543       list_remove(&Connection->conn_pool_entry);
1544       RPCRT4_DestroyConnection(Connection);
1545     }
1546
1547     HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions);
1548     HeapFree(GetProcessHeap(), 0, assoc->Endpoint);
1549     HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr);
1550     HeapFree(GetProcessHeap(), 0, assoc->Protseq);
1551
1552     DeleteCriticalSection(&assoc->cs);
1553
1554     HeapFree(GetProcessHeap(), 0, assoc);
1555   }
1556
1557   return refs;
1558 }
1559
1560 #define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1))
1561
1562 static RPC_STATUS RpcAssoc_BindConnection(const RpcAssoc *assoc, RpcConnection *conn,
1563                                           const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1564                                           const RPC_SYNTAX_IDENTIFIER *TransferSyntax)
1565 {
1566   RpcPktHdr *hdr;
1567   RpcPktHdr *response_hdr;
1568   RPC_MESSAGE msg;
1569   RPC_STATUS status;
1570
1571   TRACE("sending bind request to server\n");
1572
1573   hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION,
1574                                RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE,
1575                                assoc->assoc_group_id,
1576                                InterfaceId, TransferSyntax);
1577
1578   status = RPCRT4_Send(conn, hdr, NULL, 0);
1579   RPCRT4_FreeHeader(hdr);
1580   if (status != RPC_S_OK)
1581     return status;
1582
1583   status = RPCRT4_Receive(conn, &response_hdr, &msg);
1584   if (status != RPC_S_OK)
1585   {
1586     ERR("receive failed\n");
1587     return status;
1588   }
1589
1590   switch (response_hdr->common.ptype)
1591   {
1592   case PKT_BIND_ACK:
1593   {
1594     RpcAddressString *server_address = msg.Buffer;
1595     if ((msg.BufferLength >= FIELD_OFFSET(RpcAddressString, string[0])) ||
1596         (msg.BufferLength >= ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)))
1597     {
1598         unsigned short remaining = msg.BufferLength -
1599             ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4);
1600         RpcResults *results = (RpcResults*)((ULONG_PTR)server_address +
1601             ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4));
1602         if ((results->num_results == 1) && (remaining >= sizeof(*results)))
1603         {
1604             switch (results->results[0].result)
1605             {
1606             case RESULT_ACCEPT:
1607                 conn->assoc_group_id = response_hdr->bind_ack.assoc_gid;
1608                 conn->MaxTransmissionSize = response_hdr->bind_ack.max_tsize;
1609                 conn->ActiveInterface = *InterfaceId;
1610                 break;
1611             case RESULT_PROVIDER_REJECTION:
1612                 switch (results->results[0].reason)
1613                 {
1614                 case REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1615                     ERR("syntax %s, %d.%d not supported\n",
1616                         debugstr_guid(&InterfaceId->SyntaxGUID),
1617                         InterfaceId->SyntaxVersion.MajorVersion,
1618                         InterfaceId->SyntaxVersion.MinorVersion);
1619                     status = RPC_S_UNKNOWN_IF;
1620                     break;
1621                 case REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1622                     ERR("transfer syntax not supported\n");
1623                     status = RPC_S_SERVER_UNAVAILABLE;
1624                     break;
1625                 case REASON_NONE:
1626                 default:
1627                     status = RPC_S_CALL_FAILED_DNE;
1628                 }
1629                 break;
1630             case RESULT_USER_REJECTION:
1631             default:
1632                 ERR("rejection result %d\n", results->results[0].result);
1633                 status = RPC_S_CALL_FAILED_DNE;
1634             }
1635         }
1636         else
1637         {
1638             ERR("incorrect results size\n");
1639             status = RPC_S_CALL_FAILED_DNE;
1640         }
1641     }
1642     else
1643     {
1644         ERR("bind ack packet too small (%d)\n", msg.BufferLength);
1645         status = RPC_S_PROTOCOL_ERROR;
1646     }
1647     break;
1648   }
1649   case PKT_BIND_NACK:
1650     switch (response_hdr->bind_nack.reject_reason)
1651     {
1652     case REJECT_LOCAL_LIMIT_EXCEEDED:
1653     case REJECT_TEMPORARY_CONGESTION:
1654         ERR("server too busy\n");
1655         status = RPC_S_SERVER_TOO_BUSY;
1656         break;
1657     case REJECT_PROTOCOL_VERSION_NOT_SUPPORTED:
1658         ERR("protocol version not supported\n");
1659         status = RPC_S_PROTOCOL_ERROR;
1660         break;
1661     case REJECT_UNKNOWN_AUTHN_SERVICE:
1662         ERR("unknown authentication service\n");
1663         status = RPC_S_UNKNOWN_AUTHN_SERVICE;
1664         break;
1665     case REJECT_INVALID_CHECKSUM:
1666         ERR("invalid checksum\n");
1667         status = ERROR_ACCESS_DENIED;
1668         break;
1669     default:
1670         ERR("rejected bind for reason %d\n", response_hdr->bind_nack.reject_reason);
1671         status = RPC_S_CALL_FAILED_DNE;
1672     }
1673     break;
1674   default:
1675     ERR("wrong packet type received %d\n", response_hdr->common.ptype);
1676     status = RPC_S_PROTOCOL_ERROR;
1677     break;
1678   }
1679
1680   I_RpcFreeBuffer(&msg);
1681   RPCRT4_FreeHeader(response_hdr);
1682   return status;
1683 }
1684
1685 static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc,
1686     const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1687     const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo,
1688     const RpcQualityOfService *QOS)
1689 {
1690   RpcConnection *Connection;
1691   EnterCriticalSection(&assoc->cs);
1692   /* try to find a compatible connection from the connection pool */
1693   LIST_FOR_EACH_ENTRY(Connection, &assoc->connection_pool, RpcConnection, conn_pool_entry)
1694   {
1695     if (!memcmp(&Connection->ActiveInterface, InterfaceId,
1696                 sizeof(RPC_SYNTAX_IDENTIFIER)) &&
1697         RpcAuthInfo_IsEqual(Connection->AuthInfo, AuthInfo) &&
1698         RpcQualityOfService_IsEqual(Connection->QOS, QOS))
1699     {
1700       list_remove(&Connection->conn_pool_entry);
1701       LeaveCriticalSection(&assoc->cs);
1702       TRACE("got connection from pool %p\n", Connection);
1703       return Connection;
1704     }
1705   }
1706
1707   LeaveCriticalSection(&assoc->cs);
1708   return NULL;
1709 }
1710
1711 RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc,
1712     const RPC_SYNTAX_IDENTIFIER *InterfaceId,
1713     const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo,
1714     RpcQualityOfService *QOS, RpcConnection **Connection)
1715 {
1716   RpcConnection *NewConnection;
1717   RPC_STATUS status;
1718
1719   *Connection = RpcAssoc_GetIdleConnection(assoc, InterfaceId, TransferSyntax, AuthInfo, QOS);
1720   if (*Connection)
1721     return RPC_S_OK;
1722
1723   /* create a new connection */
1724   status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */,
1725                                    assoc->Protseq, assoc->NetworkAddr,
1726                                    assoc->Endpoint, assoc->NetworkOptions,
1727                                    AuthInfo, QOS);
1728   if (status != RPC_S_OK)
1729     return status;
1730
1731   status = RPCRT4_OpenClientConnection(NewConnection);
1732   if (status != RPC_S_OK)
1733   {
1734     RPCRT4_DestroyConnection(NewConnection);
1735     return status;
1736   }
1737
1738   status = RpcAssoc_BindConnection(assoc, NewConnection, InterfaceId, TransferSyntax);
1739   if (status != RPC_S_OK)
1740   {
1741     RPCRT4_DestroyConnection(NewConnection);
1742     return status;
1743   }
1744
1745   *Connection = NewConnection;
1746
1747   return RPC_S_OK;
1748 }
1749
1750 void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection)
1751 {
1752   assert(!Connection->server);
1753   EnterCriticalSection(&assoc->cs);
1754   if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id;
1755   list_add_head(&assoc->connection_pool, &Connection->conn_pool_entry);
1756   LeaveCriticalSection(&assoc->cs);
1757 }
1758
1759
1760 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
1761 {
1762   RPC_STATUS err;
1763
1764   err = RPCRT4_CreateConnection(Connection, OldConnection->server,
1765                                 rpcrt4_conn_get_name(OldConnection),
1766                                 OldConnection->NetworkAddr,
1767                                 OldConnection->Endpoint, NULL,
1768                                 OldConnection->AuthInfo, OldConnection->QOS);
1769   if (err == RPC_S_OK)
1770     rpcrt4_conn_handoff(OldConnection, *Connection);
1771   return err;
1772 }
1773
1774 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
1775 {
1776   TRACE("connection: %p\n", Connection);
1777
1778   RPCRT4_CloseConnection(Connection);
1779   RPCRT4_strfree(Connection->Endpoint);
1780   RPCRT4_strfree(Connection->NetworkAddr);
1781   HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions);
1782   if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo);
1783   if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS);
1784   HeapFree(GetProcessHeap(), 0, Connection);
1785   return RPC_S_OK;
1786 }
1787
1788 RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data,
1789                                       size_t *tower_size,
1790                                       const char *protseq,
1791                                       const char *networkaddr,
1792                                       const char *endpoint)
1793 {
1794     twr_empty_floor_t *protocol_floor;
1795     const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq);
1796
1797     *tower_size = 0;
1798
1799     if (!protseq_ops)
1800         return RPC_S_INVALID_RPC_PROTSEQ;
1801
1802     if (!tower_data)
1803     {
1804         *tower_size = sizeof(*protocol_floor);
1805         *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint);
1806         return RPC_S_OK;
1807     }
1808
1809     protocol_floor = (twr_empty_floor_t *)tower_data;
1810     protocol_floor->count_lhs = sizeof(protocol_floor->protid);
1811     protocol_floor->protid = protseq_ops->epm_protocols[0];
1812     protocol_floor->count_rhs = 0;
1813
1814     tower_data += sizeof(*protocol_floor);
1815
1816     *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint);
1817     if (!*tower_size)
1818         return EPT_S_NOT_REGISTERED;
1819
1820     *tower_size += sizeof(*protocol_floor);
1821
1822     return RPC_S_OK;
1823 }
1824
1825 RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data,
1826                                         size_t tower_size,
1827                                         char **protseq,
1828                                         char **networkaddr,
1829                                         char **endpoint)
1830 {
1831     const twr_empty_floor_t *protocol_floor;
1832     const twr_empty_floor_t *floor4;
1833     const struct connection_ops *protseq_ops = NULL;
1834     RPC_STATUS status;
1835     int i;
1836
1837     if (tower_size < sizeof(*protocol_floor))
1838         return EPT_S_NOT_REGISTERED;
1839
1840     protocol_floor = (const twr_empty_floor_t *)tower_data;
1841     tower_data += sizeof(*protocol_floor);
1842     tower_size -= sizeof(*protocol_floor);
1843     if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) ||
1844         (protocol_floor->count_rhs > tower_size))
1845         return EPT_S_NOT_REGISTERED;
1846     tower_data += protocol_floor->count_rhs;
1847     tower_size -= protocol_floor->count_rhs;
1848
1849     floor4 = (const twr_empty_floor_t *)tower_data;
1850     if ((tower_size < sizeof(*floor4)) ||
1851         (floor4->count_lhs != sizeof(floor4->protid)))
1852         return EPT_S_NOT_REGISTERED;
1853
1854     for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++)
1855         if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) &&
1856             (floor4->protid == conn_protseq_list[i].epm_protocols[1]))
1857         {
1858             protseq_ops = &conn_protseq_list[i];
1859             break;
1860         }
1861
1862     if (!protseq_ops)
1863         return EPT_S_NOT_REGISTERED;
1864
1865     status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint);
1866
1867     if ((status == RPC_S_OK) && protseq)
1868     {
1869         *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1);
1870         strcpy(*protseq, protseq_ops->name);
1871     }
1872
1873     return status;
1874 }
1875
1876 /***********************************************************************
1877  *             RpcNetworkIsProtseqValidW (RPCRT4.@)
1878  *
1879  * Checks if the given protocol sequence is known by the RPC system.
1880  * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1881  *
1882  */
1883 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq)
1884 {
1885   char ps[0x10];
1886
1887   WideCharToMultiByte(CP_ACP, 0, protseq, -1,
1888                       ps, sizeof ps, NULL, NULL);
1889   if (rpcrt4_get_conn_protseq_ops(ps))
1890     return RPC_S_OK;
1891
1892   FIXME("Unknown protseq %s\n", debugstr_w(protseq));
1893
1894   return RPC_S_INVALID_RPC_PROTSEQ;
1895 }
1896
1897 /***********************************************************************
1898  *             RpcNetworkIsProtseqValidA (RPCRT4.@)
1899  */
1900 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq)
1901 {
1902   UNICODE_STRING protseqW;
1903
1904   if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq))
1905   {
1906     RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1907     RtlFreeUnicodeString(&protseqW);
1908     return ret;
1909   }
1910   return RPC_S_OUT_OF_MEMORY;
1911 }