Silence various "may be used uninitialized" warnings from GCC caused
[krb5.git] / src / lib / apputils / net-server.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/apputils/net-server.c - Network code for krb5 servers (kdc, kadmind) */
3 /*
4  * Copyright 1990,2000,2007,2008,2009,2010 by the Massachusetts Institute of Technology.
5  *
6  * Export of this software from the United States of America may
7  *   require a specific license from the United States Government.
8  *   It is the responsibility of any person or organization contemplating
9  *   export to obtain such a license before exporting.
10  *
11  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12  * distribute this software and its documentation for any purpose and
13  * without fee is hereby granted, provided that the above copyright
14  * notice appear in all copies and that both that copyright notice and
15  * this permission notice appear in supporting documentation, and that
16  * the name of M.I.T. not be used in advertising or publicity pertaining
17  * to distribution of the software without specific, written prior
18  * permission.  Furthermore if you modify this software you must label
19  * your software as modified software and not distribute it in such a
20  * fashion that it might be confused with the original M.I.T. software.
21  * M.I.T. makes no representations about the suitability of
22  * this software for any purpose.  It is provided "as is" without express
23  * or implied warranty.
24  */
25
26 #include "k5-int.h"
27 #include "adm_proto.h"
28 #include <sys/ioctl.h>
29 #include <syslog.h>
30
31 #include <stddef.h>
32 #include "port-sockets.h"
33 #include "socket-utils.h"
34
35 #include <gssrpc/rpc.h>
36
37 #ifdef HAVE_NETINET_IN_H
38 #include <sys/types.h>
39 #include <netinet/in.h>
40 #include <sys/socket.h>
41 #ifdef HAVE_SYS_SOCKIO_H
42 /* for SIOCGIFCONF, etc. */
43 #include <sys/sockio.h>
44 #endif
45 #include <sys/time.h>
46 #if HAVE_SYS_SELECT_H
47 #include <sys/select.h>
48 #endif
49 #include <arpa/inet.h>
50
51 #ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */
52 #include <net/if.h>
53 #endif
54
55 #ifdef HAVE_SYS_FILIO_H
56 #include <sys/filio.h>          /* FIONBIO */
57 #endif
58
59 #include "fake-addrinfo.h"
60 #include "net-server.h"
61
62 #include <signal.h>
63
64 /* XXX */
65 #define KDC5_NONET                               (-1779992062L)
66
67 static int tcp_or_rpc_data_counter;
68 static int max_tcp_or_rpc_data_connections = 45;
69
70 /* Misc utility routines.  */
71 static void
72 set_sa_port(struct sockaddr *addr, int port)
73 {
74     switch (addr->sa_family) {
75     case AF_INET:
76         sa2sin(addr)->sin_port = port;
77         break;
78 #ifdef KRB5_USE_INET6
79     case AF_INET6:
80         sa2sin6(addr)->sin6_port = port;
81         break;
82 #endif
83     default:
84         break;
85     }
86 }
87
88 static int
89 ipv6_enabled()
90 {
91 #ifdef KRB5_USE_INET6
92     static int result = -1;
93     if (result == -1) {
94         int s;
95         s = socket(AF_INET6, SOCK_STREAM, 0);
96         if (s >= 0) {
97             result = 1;
98             close(s);
99         } else
100             result = 0;
101     }
102     return result;
103 #else
104     return 0;
105 #endif
106 }
107
108 static int
109 setreuseaddr(int sock, int value)
110 {
111     return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
112 }
113
114 #if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
115 static int
116 setv6only(int sock, int value)
117 {
118     return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
119 }
120 #endif
121
122 /* Use RFC 3542 API below, but fall back from IPV6_RECVPKTINFO to
123    IPV6_PKTINFO for RFC 2292 implementations.  */
124 #ifndef IPV6_RECVPKTINFO
125 #define IPV6_RECVPKTINFO IPV6_PKTINFO
126 #endif
127 /* Parallel, though not standardized.  */
128 #ifndef IP_RECVPKTINFO
129 #define IP_RECVPKTINFO IP_PKTINFO
130 #endif
131
132 static int
133 set_pktinfo(int sock, int family)
134 {
135     int sockopt = 1;
136     int option = 0, proto = 0;
137
138     switch (family) {
139 #if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO)
140     case AF_INET:
141         proto = IPPROTO_IP;
142         option = IP_RECVPKTINFO;
143         break;
144 #endif
145 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
146     case AF_INET6:
147         proto = IPPROTO_IPV6;
148         option = IPV6_RECVPKTINFO;
149         break;
150 #endif
151     default:
152         return EINVAL;
153     }
154     if (setsockopt(sock, proto, option, &sockopt, sizeof(sockopt)))
155         return errno;
156     return 0;
157 }
158
159 \f
160 static const char *
161 paddr(struct sockaddr *sa)
162 {
163     static char buf[100];
164     char portbuf[10];
165     if (getnameinfo(sa, socklen(sa),
166                     buf, sizeof(buf), portbuf, sizeof(portbuf),
167                     NI_NUMERICHOST|NI_NUMERICSERV))
168         strlcpy(buf, "<unprintable>", sizeof(buf));
169     else {
170         unsigned int len = sizeof(buf) - strlen(buf);
171         char *p = buf + strlen(buf);
172         if (len > 2+strlen(portbuf)) {
173             *p++ = '.';
174             len--;
175             strncpy(p, portbuf, len);
176         }
177     }
178     return buf;
179 }
180
181 /* KDC data.  */
182
183 enum conn_type {
184     CONN_UDP, CONN_UDP_PKTINFO, CONN_TCP_LISTENER, CONN_TCP,
185     CONN_RPC_LISTENER, CONN_RPC,
186     CONN_ROUTING
187 };
188
189 /* Per-connection info.  */
190 struct connection {
191     void *handle;
192     const char *prog;
193     enum conn_type type;
194     union {
195         /* Type-specific information.  */
196         struct {
197             /* connection */
198             struct sockaddr_storage addr_s;
199             socklen_t addrlen;
200             char addrbuf[56];
201             krb5_fulladdr faddr;
202             krb5_address kaddr;
203             /* incoming */
204             size_t bufsiz;
205             size_t offset;
206             char *buffer;
207             size_t msglen;
208             /* outgoing */
209             krb5_data *response;
210             unsigned char lenbuf[4];
211             sg_buf sgbuf[2];
212             sg_buf *sgp;
213             int sgnum;
214             /* crude denial-of-service avoidance support */
215             time_t start_time;
216         } tcp;
217         struct {
218             SVCXPRT *transp;
219             int closed;
220         } rpc;
221     } u;
222 };
223
224 \f
225 #define SET(TYPE) struct { TYPE *data; size_t n, max; }
226
227 /* Start at the top and work down -- this should allow for deletions
228    without disrupting the iteration, since we delete by overwriting
229    the element to be removed with the last element.  */
230 #define FOREACH_ELT(set,idx,vvar)                                       \
231     for (idx = set.n-1; idx >= 0 && (vvar = set.data[idx], 1); idx--)
232
233 #define GROW_SET(set, incr, tmpptr)                                     \
234     ((set.max + incr < set.max                                          \
235       || ((set.max + incr) * sizeof(set.data[0]) / sizeof(set.data[0])  \
236           != set.max + incr))                                           \
237      ? 0                         /* overflow */                         \
238      : ((tmpptr = realloc(set.data,                                     \
239                           (set.max + incr) * sizeof(set.data[0])))      \
240         ? (set.data = tmpptr, set.max += incr, 1)                       \
241         : 0))
242
243 /* 1 = success, 0 = failure */
244 #define ADD(set, val, tmpptr)                           \
245     ((set.n < set.max || GROW_SET(set, 10, tmpptr))     \
246      ? (set.data[set.n++] = val, 1)                     \
247      : 0)
248
249 #define DEL(set, idx)                           \
250     (set.data[idx] = set.data[--set.n], 0)
251
252 #define FREE_SET_DATA(set)                                      \
253     (free(set.data), set.data = 0, set.max = 0, set.n = 0)
254
255 /*
256  * N.B.: The Emacs cc-mode indentation code seems to get confused if
257  * the macro argument here is one word only.  So use "unsigned short"
258  * instead of the "u_short" we were using before.
259  */
260 struct rpc_svc_data {
261     u_short port;
262     u_long prognum;
263     u_long versnum;
264     void (*dispatch)();
265 };
266 static SET(unsigned short) udp_port_data, tcp_port_data;
267 static SET(struct rpc_svc_data) rpc_svc_data;
268 static SET(verto_ev *) events;
269
270 static void
271 do_break(verto_ctx *ctx, verto_ev *ev)
272 {
273     krb5_klog_syslog(LOG_DEBUG, _("Got signal to request exit"));
274     verto_break(ctx);
275 }
276
277 struct sighup_context {
278     void *handle;
279     void (*reset)();
280 };
281
282 static void
283 do_reset(verto_ctx *ctx, verto_ev *ev)
284 {
285     struct sighup_context *sc = (struct sighup_context*) verto_get_private(ev);
286
287     krb5_klog_syslog(LOG_DEBUG, _("Got signal to reset"));
288     krb5_klog_reopen(get_context(sc->handle));
289     if (sc->reset)
290         sc->reset();
291 }
292
293 static void
294 free_sighup_context(verto_ctx *ctx, verto_ev *ev)
295 {
296     free(verto_get_private(ev));
297 }
298
299 verto_ctx *
300 loop_init(verto_ev_type types, void *handle, void (*reset)())
301 {
302     struct sighup_context *sc;
303     verto_ctx *ctx;
304     verto_ev  *ev;
305
306     types |= VERTO_EV_TYPE_IO;
307     types |= VERTO_EV_TYPE_SIGNAL;
308     types |= VERTO_EV_TYPE_TIMEOUT;
309     ctx = verto_default(NULL, types);
310     if (!verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, do_break, SIGINT)  ||
311         !verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, do_break, SIGTERM) ||
312         !verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, do_break, SIGQUIT) ||
313         !verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, VERTO_SIG_IGN, SIGPIPE))
314         goto error;
315
316     ev = verto_add_signal(ctx, VERTO_EV_FLAG_PERSIST, do_reset, SIGHUP);
317     if (!ev)
318         goto error;
319
320     sc = malloc(sizeof(*sc));
321     if (!sc)
322         goto error;
323     sc->handle = handle;
324     sc->reset = reset;
325
326     verto_set_private(ev, sc, free_sighup_context);
327     return ctx;
328
329 error:
330     verto_free(ctx);
331     return NULL;
332 }
333
334 krb5_error_code
335 loop_add_udp_port(int port)
336 {
337     int i;
338     void *tmp;
339     u_short val;
340     u_short s_port = port;
341
342     if (s_port != port)
343         return EINVAL;
344
345     FOREACH_ELT (udp_port_data, i, val)
346         if (s_port == val)
347             return 0;
348     if (!ADD(udp_port_data, s_port, tmp))
349         return ENOMEM;
350     return 0;
351 }
352
353 krb5_error_code
354 loop_add_tcp_port(int port)
355 {
356     int i;
357     void *tmp;
358     u_short val;
359     u_short s_port = port;
360
361     if (s_port != port)
362         return EINVAL;
363
364     FOREACH_ELT (tcp_port_data, i, val)
365         if (s_port == val)
366             return 0;
367     if (!ADD(tcp_port_data, s_port, tmp))
368         return ENOMEM;
369     return 0;
370 }
371
372 krb5_error_code
373 loop_add_rpc_service(int port, u_long prognum,
374                      u_long versnum, void (*dispatchfn)())
375 {
376     int i;
377     void *tmp;
378     struct rpc_svc_data svc, val;
379
380     svc.port = port;
381     if (svc.port != port)
382         return EINVAL;
383     svc.prognum = prognum;
384     svc.versnum = versnum;
385     svc.dispatch = dispatchfn;
386
387     FOREACH_ELT (rpc_svc_data, i, val) {
388         if (val.port == port)
389             return 0;
390     }
391     if (!ADD(rpc_svc_data, svc, tmp))
392         return ENOMEM;
393     return 0;
394 }
395
396 \f
397 #define USE_AF AF_INET
398 #define USE_TYPE SOCK_DGRAM
399 #define USE_PROTO 0
400 #define SOCKET_ERRNO errno
401 #include "foreachaddr.h"
402
403 struct socksetup {
404     verto_ctx *ctx;
405     void *handle;
406     const char *prog;
407     krb5_error_code retval;
408     int udp_flags;
409 #define UDP_DO_IPV4 1
410 #define UDP_DO_IPV6 2
411 };
412
413 static void
414 free_connection(struct connection *conn)
415 {
416     if (!conn)
417         return;
418     if (conn->u.tcp.response)
419         krb5_free_data(get_context(conn->handle), conn->u.tcp.response);
420     if (conn->u.tcp.buffer)
421         free(conn->u.tcp.buffer);
422     if (conn->type == CONN_RPC_LISTENER && conn->u.rpc.transp != NULL)
423         svc_destroy(conn->u.rpc.transp);
424     free(conn);
425 }
426
427 static void
428 remove_event_from_set(verto_ev *ev)
429 {
430     verto_ev *tmp;
431     int i;
432
433     /* Remove the event from the events. */
434     FOREACH_ELT(events, i, tmp)
435         if (tmp == ev) {
436             DEL(events, i);
437             break;
438         }
439 }
440
441 static void
442 free_socket(verto_ctx *ctx, verto_ev *ev)
443 {
444     struct connection *conn = NULL;
445     fd_set fds;
446     int fd;
447
448     remove_event_from_set(ev);
449
450     fd = verto_get_fd(ev);
451     conn = verto_get_private(ev);
452
453     /* Close the file descriptor. */
454     krb5_klog_syslog(LOG_INFO, _("closing down fd %d"), fd);
455     if (fd >= 0 && (!conn || conn->type != CONN_RPC || conn->u.rpc.closed))
456         close(fd);
457
458     /* Free the connection struct. */
459     if (conn) {
460         switch (conn->type) {
461             case CONN_RPC:
462                 if (conn->u.rpc.closed) {
463                     FD_ZERO(&fds);
464                     FD_SET(fd, &fds);
465                     svc_getreqset(&fds);
466                     if (FD_ISSET(fd, &svc_fdset)) {
467                         krb5_klog_syslog(LOG_ERR,
468                                          _("descriptor %d closed but still "
469                                            "in svc_fdset"),
470                                          fd);
471                     }
472                 }
473                 /* Fall through. */
474             case CONN_TCP:
475                 tcp_or_rpc_data_counter--;
476                 break;
477             default:
478                 break;
479         }
480
481         free_connection(conn);
482     }
483 }
484
485 static verto_ev *
486 make_event(verto_ctx *ctx, verto_ev_flag flags, verto_callback callback,
487            int sock, struct connection *conn, int addevent)
488 {
489     verto_ev *ev;
490     void *tmp;
491
492     ev = verto_add_io(ctx, flags, callback, sock);
493     if (!ev) {
494         com_err(conn->prog, ENOMEM, _("cannot create io event"));
495         return NULL;
496     }
497
498     if (addevent) {
499         if (!ADD(events, ev, tmp)) {
500             com_err(conn->prog, ENOMEM, _("cannot save event"));
501             verto_del(ev);
502             return NULL;
503         }
504     }
505
506     verto_set_private(ev, conn, free_socket);
507     return ev;
508 }
509
510 static verto_ev *
511 convert_event(verto_ctx *ctx, verto_ev *ev, verto_ev_flag flags,
512               verto_callback callback)
513 {
514     struct connection *conn;
515     verto_ev *newev;
516     int sock;
517
518     conn = verto_get_private(ev);
519     sock = verto_get_fd(ev);
520     if (sock < 0)
521         return NULL;
522
523     newev = make_event(ctx, flags, callback, sock, conn, 1);
524
525     /* Delete the read event without closing the socket
526      * or freeing the connection struct. */
527     if (newev) {
528         verto_set_private(ev, NULL, NULL); /* Reset the destructor. */
529         remove_event_from_set(ev); /* Remove it from the set. */
530         verto_del(ev);
531     }
532
533     return newev;
534 }
535
536 static verto_ev *
537 add_fd(struct socksetup *data, int sock, enum conn_type conntype,
538        verto_ev_flag flags, verto_callback callback, int addevent)
539 {
540     struct connection *newconn;
541
542 #ifndef _WIN32
543     if (sock >= FD_SETSIZE) {
544         data->retval = EMFILE;  /* XXX */
545         com_err(data->prog, 0,
546                 _("file descriptor number %d too high"), sock);
547         return 0;
548     }
549 #endif
550     newconn = malloc(sizeof(*newconn));
551     if (newconn == NULL) {
552         data->retval = ENOMEM;
553         com_err(data->prog, ENOMEM,
554                 _("cannot allocate storage for connection info"));
555         return 0;
556     }
557     memset(newconn, 0, sizeof(*newconn));
558     newconn->handle = data->handle;
559     newconn->prog = data->prog;
560     newconn->type = conntype;
561
562     return make_event(data->ctx, flags, callback, sock, newconn, addevent);
563 }
564
565 static void process_packet(verto_ctx *ctx, verto_ev *ev);
566 static void accept_tcp_connection(verto_ctx *ctx, verto_ev *ev);
567 static void process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev);
568 static void process_tcp_connection_write(verto_ctx *ctx, verto_ev *ev);
569 static void accept_rpc_connection(verto_ctx *ctx, verto_ev *ev);
570 static void process_rpc_connection(verto_ctx *ctx, verto_ev *ev);
571
572 static verto_ev *
573 add_udp_fd(struct socksetup *data, int sock, int pktinfo)
574 {
575     return add_fd(data, sock, pktinfo ? CONN_UDP_PKTINFO : CONN_UDP,
576                   VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
577                   process_packet, 1);
578 }
579
580 static verto_ev *
581 add_tcp_listener_fd(struct socksetup *data, int sock)
582 {
583     return add_fd(data, sock, CONN_TCP_LISTENER,
584                   VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
585                   accept_tcp_connection, 1);
586 }
587
588 static verto_ev *
589 add_tcp_read_fd(struct socksetup *data, int sock)
590 {
591     return add_fd(data, sock, CONN_TCP,
592                   VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
593                   process_tcp_connection_read, 1);
594 }
595
596 /*
597  * Create a socket and bind it to addr.  Ensure the socket will work with
598  * select().  Set the socket cloexec, reuseaddr, and if applicable v6-only.
599  * Does not call listen().  Returns -1 on failure after logging an error.
600  */
601 static int
602 create_server_socket(struct socksetup *data, struct sockaddr *addr, int type)
603 {
604     int sock;
605
606     sock = socket(addr->sa_family, type, 0);
607     if (sock == -1) {
608         data->retval = errno;
609         com_err(data->prog, errno, _("Cannot create TCP server socket on %s"),
610                 paddr(addr));
611         return -1;
612     }
613     set_cloexec_fd(sock);
614
615 #ifndef _WIN32                  /* Windows FD_SETSIZE is a count. */
616     if (sock >= FD_SETSIZE) {
617         close(sock);
618         com_err(data->prog, 0, _("TCP socket fd number %d (for %s) too high"),
619                 sock, paddr(addr));
620         return -1;
621     }
622 #endif
623
624     if (setreuseaddr(sock, 1) < 0) {
625         com_err(data->prog, errno,
626                 _("Cannot enable SO_REUSEADDR on fd %d"), sock);
627     }
628
629 #ifdef KRB5_USE_INET6
630     if (addr->sa_family == AF_INET6) {
631 #ifdef IPV6_V6ONLY
632         if (setv6only(sock, 1))
633             com_err(data->prog, errno,
634                     _("setsockopt(%d,IPV6_V6ONLY,1) failed"), sock);
635         else
636             com_err(data->prog, 0, _("setsockopt(%d,IPV6_V6ONLY,1) worked"),
637                     sock);
638 #else
639         krb5_klog_syslog(LOG_INFO, _("no IPV6_V6ONLY socket option support"));
640 #endif /* IPV6_V6ONLY */
641     }
642 #endif /* KRB5_USE_INET6 */
643
644     if (bind(sock, addr, socklen(addr)) == -1) {
645         data->retval = errno;
646         com_err(data->prog, errno, _("Cannot bind server socket on %s"),
647                 paddr(addr));
648         close(sock);
649         return -1;
650     }
651
652     return sock;
653 }
654
655 static verto_ev *
656 add_rpc_listener_fd(struct socksetup *data, struct rpc_svc_data *svc, int sock)
657 {
658     struct connection *conn;
659     verto_ev *ev;
660
661     ev = add_fd(data, sock, CONN_RPC_LISTENER,
662                 VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
663                 accept_rpc_connection, 1);
664     if (ev == NULL)
665         return NULL;
666
667     conn = verto_get_private(ev);
668     conn->u.rpc.transp = svctcp_create(sock, 0, 0);
669     if (conn->u.rpc.transp == NULL) {
670         krb5_klog_syslog(LOG_ERR,
671                          _("Cannot create RPC service: %s; continuing"),
672                          strerror(errno));
673         verto_del(ev);
674         return NULL;
675     }
676
677     if (!svc_register(conn->u.rpc.transp, svc->prognum, svc->versnum,
678                       svc->dispatch, 0)) {
679         krb5_klog_syslog(LOG_ERR,
680                          _("Cannot register RPC service: %s; continuing"),
681                          strerror(errno));
682         verto_del(ev);
683         return NULL;
684     }
685
686     return ev;
687 }
688
689 static verto_ev *
690 add_rpc_data_fd(struct socksetup *data, int sock)
691 {
692     return add_fd(data, sock, CONN_RPC,
693                   VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
694                   process_rpc_connection, 1);
695 }
696
697 static const int one = 1;
698
699 static int
700 setnbio(int sock)
701 {
702     return ioctlsocket(sock, FIONBIO, (const void *)&one);
703 }
704
705 static int
706 setkeepalive(int sock)
707 {
708     return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
709 }
710 \f
711 static int
712 setnolinger(int s)
713 {
714     static const struct linger ling = { 0, 0 };
715     return setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
716 }
717
718 /* Returns -1 or socket fd.  */
719 static int
720 setup_a_tcp_listener(struct socksetup *data, struct sockaddr *addr)
721 {
722     int sock;
723
724     sock = create_server_socket(data, addr, SOCK_STREAM);
725     if (sock == -1)
726         return -1;
727     if (listen(sock, 5) < 0) {
728         com_err(data->prog, errno,
729                 _("Cannot listen on TCP server socket on %s"), paddr(addr));
730         close(sock);
731         return -1;
732     }
733     if (setnbio(sock)) {
734         com_err(data->prog, errno,
735                 _("cannot set listening tcp socket on %s non-blocking"),
736                 paddr(addr));
737         close(sock);
738         return -1;
739     }
740     if (setnolinger(sock)) {
741         com_err(data->prog, errno,
742                 _("disabling SO_LINGER on TCP socket on %s"), paddr(addr));
743         close(sock);
744         return -1;
745     }
746     return sock;
747 }
748
749 static int
750 setup_tcp_listener_ports(struct socksetup *data)
751 {
752     struct sockaddr_in sin4;
753 #ifdef KRB5_USE_INET6
754     struct sockaddr_in6 sin6;
755 #endif
756     int i, port;
757
758     memset(&sin4, 0, sizeof(sin4));
759     sin4.sin_family = AF_INET;
760 #ifdef HAVE_SA_LEN
761     sin4.sin_len = sizeof(sin4);
762 #endif
763     sin4.sin_addr.s_addr = INADDR_ANY;
764
765 #ifdef KRB5_USE_INET6
766     memset(&sin6, 0, sizeof(sin6));
767     sin6.sin6_family = AF_INET6;
768 #ifdef SIN6_LEN
769     sin6.sin6_len = sizeof(sin6);
770 #endif
771     sin6.sin6_addr = in6addr_any;
772 #endif
773
774     FOREACH_ELT (tcp_port_data, i, port) {
775         int s4, s6;
776
777         set_sa_port((struct sockaddr *)&sin4, htons(port));
778         if (!ipv6_enabled()) {
779             s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
780             if (s4 < 0)
781                 return -1;
782             s6 = -1;
783         } else {
784 #ifndef KRB5_USE_INET6
785             abort();
786 #else
787             s4 = s6 = -1;
788
789             set_sa_port((struct sockaddr *)&sin6, htons(port));
790
791             s6 = setup_a_tcp_listener(data, (struct sockaddr *)&sin6);
792             if (s6 < 0)
793                 return -1;
794
795             s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
796 #endif /* KRB5_USE_INET6 */
797         }
798
799         /* Sockets are created, prepare to listen on them. */
800         if (s4 >= 0) {
801             if (add_tcp_listener_fd(data, s4) == NULL)
802                 close(s4);
803             else {
804                 krb5_klog_syslog(LOG_INFO, _("listening on fd %d: tcp %s"),
805                                  s4, paddr((struct sockaddr *)&sin4));
806             }
807         }
808 #ifdef KRB5_USE_INET6
809         if (s6 >= 0) {
810             if (add_tcp_listener_fd(data, s6) == NULL) {
811                 close(s6);
812                 s6 = -1;
813             } else {
814                 krb5_klog_syslog(LOG_INFO, _("listening on fd %d: tcp %s"),
815                                  s6, paddr((struct sockaddr *)&sin6));
816             }
817             if (s4 < 0)
818                 krb5_klog_syslog(LOG_INFO,
819                                  _("assuming IPv6 socket accepts IPv4"));
820         }
821 #endif
822     }
823     return 0;
824 }
825
826 static int
827 setup_rpc_listener_ports(struct socksetup *data)
828 {
829     struct sockaddr_in sin4;
830 #ifdef KRB5_USE_INET6
831     struct sockaddr_in6 sin6;
832 #endif
833     int i;
834     struct rpc_svc_data svc;
835
836     memset(&sin4, 0, sizeof(sin4));
837     sin4.sin_family = AF_INET;
838 #ifdef HAVE_SA_LEN
839     sin4.sin_len = sizeof(sin4);
840 #endif
841     sin4.sin_addr.s_addr = INADDR_ANY;
842
843 #ifdef KRB5_USE_INET6
844     memset(&sin6, 0, sizeof(sin6));
845     sin6.sin6_family = AF_INET6;
846 #ifdef HAVE_SA_LEN
847     sin6.sin6_len = sizeof(sin6);
848 #endif
849     sin6.sin6_addr = in6addr_any;
850 #endif
851
852     FOREACH_ELT (rpc_svc_data, i, svc) {
853         int s4;
854 #ifdef KRB5_USE_INET6
855         int s6;
856 #endif
857
858         set_sa_port((struct sockaddr *)&sin4, htons(svc.port));
859         s4 = create_server_socket(data, (struct sockaddr *)&sin4, SOCK_STREAM);
860         if (s4 < 0)
861             return -1;
862
863         if (add_rpc_listener_fd(data, &svc, s4) == NULL)
864             close(s4);
865         else
866             krb5_klog_syslog(LOG_INFO, _("listening on fd %d: rpc %s"),
867                              s4, paddr((struct sockaddr *)&sin4));
868
869 #ifdef KRB5_USE_INET6
870         if (ipv6_enabled()) {
871             set_sa_port((struct sockaddr *)&sin6, htons(svc.port));
872             s6 = create_server_socket(data, (struct sockaddr *)&sin6,
873                                       SOCK_STREAM);
874             if (s6 < 0)
875                 return -1;
876
877             if (add_rpc_listener_fd(data, &svc, s6) == NULL)
878                 close(s6);
879             else
880                 krb5_klog_syslog(LOG_INFO, _("listening on fd %d: rpc %s"),
881                                  s6, paddr((struct sockaddr *)&sin6));
882         }
883 #endif
884     }
885
886     return 0;
887 }
888
889 #if defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && \
890     (defined(IP_PKTINFO) || defined(IPV6_PKTINFO))
891 union pktinfo {
892 #ifdef HAVE_STRUCT_IN6_PKTINFO
893     struct in6_pktinfo pi6;
894 #endif
895 #ifdef HAVE_STRUCT_IN_PKTINFO
896     struct in_pktinfo pi4;
897 #endif
898     char c;
899 };
900
901 static int
902 setup_udp_port_1(struct socksetup *data, struct sockaddr *addr,
903                  char *haddrbuf, int pktinfo);
904
905 static void
906 setup_udp_pktinfo_ports(struct socksetup *data)
907 {
908 #ifdef IP_PKTINFO
909     {
910         struct sockaddr_in sa;
911         int r;
912
913         memset(&sa, 0, sizeof(sa));
914         sa.sin_family = AF_INET;
915 #ifdef HAVE_SA_LEN
916         sa.sin_len = sizeof(sa);
917 #endif
918         r = setup_udp_port_1(data, (struct sockaddr *) &sa, "0.0.0.0", 4);
919         if (r == 0)
920             data->udp_flags &= ~UDP_DO_IPV4;
921     }
922 #endif
923 #ifdef IPV6_PKTINFO
924     {
925         struct sockaddr_in6 sa;
926         int r;
927
928         memset(&sa, 0, sizeof(sa));
929         sa.sin6_family = AF_INET6;
930 #ifdef HAVE_SA_LEN
931         sa.sin6_len = sizeof(sa);
932 #endif
933         r = setup_udp_port_1(data, (struct sockaddr *) &sa, "::", 6);
934         if (r == 0)
935             data->udp_flags &= ~UDP_DO_IPV6;
936     }
937 #endif
938 }
939 #else /* no pktinfo compile-time support */
940 static void
941 setup_udp_pktinfo_ports(struct socksetup *data)
942 {
943 }
944 #endif
945
946 static int
947 setup_udp_port_1(struct socksetup *data, struct sockaddr *addr,
948                  char *haddrbuf, int pktinfo)
949 {
950     int sock = -1, i, r;
951     u_short port;
952
953     FOREACH_ELT (udp_port_data, i, port) {
954         set_sa_port(addr, htons(port));
955         sock = create_server_socket(data, addr, SOCK_DGRAM);
956         if (sock == -1)
957             return 1;
958         setnbio(sock);
959
960 #if !(defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && \
961       (defined(IP_PKTINFO) || defined(IPV6_PKTINFO)))
962         assert(pktinfo == 0);
963 #endif
964         if (pktinfo) {
965             r = set_pktinfo(sock, addr->sa_family);
966             if (r) {
967                 com_err(data->prog, r,
968                         _("Cannot request packet info for udp socket address "
969                           "%s port %d"), haddrbuf, port);
970                 close(sock);
971                 return 1;
972             }
973         }
974         krb5_klog_syslog(LOG_INFO, _("listening on fd %d: udp %s%s"), sock,
975                          paddr((struct sockaddr *)addr),
976                          pktinfo ? " (pktinfo)" : "");
977         if (add_udp_fd (data, sock, pktinfo) == 0) {
978             close(sock);
979             return 1;
980         }
981     }
982     return 0;
983 }
984
985 static int
986 setup_udp_port(void *P_data, struct sockaddr *addr)
987 {
988     struct socksetup *data = P_data;
989     char haddrbuf[NI_MAXHOST];
990     int err;
991
992     if (addr->sa_family == AF_INET && !(data->udp_flags & UDP_DO_IPV4))
993         return 0;
994 #ifdef AF_INET6
995     if (addr->sa_family == AF_INET6 && !(data->udp_flags & UDP_DO_IPV6))
996         return 0;
997 #endif
998     err = getnameinfo(addr, socklen(addr), haddrbuf, sizeof(haddrbuf),
999                       0, 0, NI_NUMERICHOST);
1000     if (err)
1001         strlcpy(haddrbuf, "<unprintable>", sizeof(haddrbuf));
1002
1003     switch (addr->sa_family) {
1004     case AF_INET:
1005         break;
1006 #ifdef AF_INET6
1007     case AF_INET6:
1008 #ifdef KRB5_USE_INET6
1009         break;
1010 #else
1011         {
1012             static int first = 1;
1013             if (first) {
1014                 krb5_klog_syslog(LOG_INFO, _("skipping local ipv6 addresses"));
1015                 first = 0;
1016             }
1017             return 0;
1018         }
1019 #endif
1020 #endif
1021 #ifdef AF_LINK /* some BSD systems, AIX */
1022     case AF_LINK:
1023         return 0;
1024 #endif
1025 #ifdef AF_DLI /* Direct Link Interface - DEC Ultrix/OSF1 link layer? */
1026     case AF_DLI:
1027         return 0;
1028 #endif
1029 #ifdef AF_APPLETALK
1030     case AF_APPLETALK:
1031         return 0;
1032 #endif
1033     default:
1034         krb5_klog_syslog(LOG_INFO,
1035                          _("skipping unrecognized local address family %d"),
1036                          addr->sa_family);
1037         return 0;
1038     }
1039     return setup_udp_port_1(data, addr, haddrbuf, 0);
1040 }
1041
1042 #if 1
1043 static void
1044 klog_handler(const void *data, size_t len)
1045 {
1046     static char buf[BUFSIZ];
1047     static int bufoffset;
1048     void *p;
1049
1050 #define flush_buf()                             \
1051     (bufoffset                                  \
1052      ? (((buf[0] == 0 || buf[0] == '\n')        \
1053          ? (fork()==0?abort():(void)0)          \
1054          : (void)0),                            \
1055         krb5_klog_syslog(LOG_INFO, "%s", buf),  \
1056         memset(buf, 0, sizeof(buf)),            \
1057         bufoffset = 0)                          \
1058      : 0)
1059
1060     p = memchr(data, 0, len);
1061     if (p)
1062         len = (const char *)p - (const char *)data;
1063 scan_for_newlines:
1064     if (len == 0)
1065         return;
1066     p = memchr(data, '\n', len);
1067     if (p) {
1068         if (p != data)
1069             klog_handler(data, (size_t)((const char *)p - (const char *)data));
1070         flush_buf();
1071         len -= ((const char *)p - (const char *)data) + 1;
1072         data = 1 + (const char *)p;
1073         goto scan_for_newlines;
1074     } else if (len > sizeof(buf) - 1 || len + bufoffset > sizeof(buf) - 1) {
1075         size_t x = sizeof(buf) - len - 1;
1076         klog_handler(data, x);
1077         flush_buf();
1078         len -= x;
1079         data = (const char *)data + x;
1080         goto scan_for_newlines;
1081     } else {
1082         memcpy(buf + bufoffset, data, len);
1083         bufoffset += len;
1084     }
1085 }
1086 #endif
1087
1088 #ifdef HAVE_STRUCT_RT_MSGHDR
1089 #include <net/route.h>
1090
1091 static char *
1092 rtm_type_name(int type)
1093 {
1094     switch (type) {
1095     case RTM_ADD: return "RTM_ADD";
1096     case RTM_DELETE: return "RTM_DELETE";
1097     case RTM_NEWADDR: return "RTM_NEWADDR";
1098     case RTM_DELADDR: return "RTM_DELADDR";
1099     case RTM_IFINFO: return "RTM_IFINFO";
1100     case RTM_OLDADD: return "RTM_OLDADD";
1101     case RTM_OLDDEL: return "RTM_OLDDEL";
1102     case RTM_RESOLVE: return "RTM_RESOLVE";
1103 #ifdef RTM_NEWMADDR
1104     case RTM_NEWMADDR: return "RTM_NEWMADDR";
1105     case RTM_DELMADDR: return "RTM_DELMADDR";
1106 #endif
1107     case RTM_MISS: return "RTM_MISS";
1108     case RTM_REDIRECT: return "RTM_REDIRECT";
1109     case RTM_LOSING: return "RTM_LOSING";
1110     case RTM_GET: return "RTM_GET";
1111     default: return "?";
1112     }
1113 }
1114
1115 static void
1116 do_network_reconfig(verto_ctx *ctx, verto_ev *ev)
1117 {
1118     struct connection *conn = verto_get_private(ev);
1119     assert(loop_setup_network(ctx, conn->handle, conn->prog) == 0);
1120 }
1121
1122 static int
1123 routing_update_needed(struct rt_msghdr *rtm)
1124 {
1125     switch (rtm->rtm_type) {
1126     case RTM_ADD:
1127     case RTM_DELETE:
1128     case RTM_NEWADDR:
1129     case RTM_DELADDR:
1130     case RTM_IFINFO:
1131     case RTM_OLDADD:
1132     case RTM_OLDDEL:
1133         /*
1134          * Some flags indicate routing table updates that don't
1135          * indicate local address changes.  They may come from
1136          * redirects, or ARP, etc.
1137          *
1138          * This set of symbols is just an initial guess based on
1139          * some messages observed in real life; working out which
1140          * other flags also indicate messages we should ignore,
1141          * and which flags are portable to all system and thus
1142          * don't need to be conditionalized, is left as a future
1143          * exercise.
1144          */
1145 #ifdef RTF_DYNAMIC
1146         if (rtm->rtm_flags & RTF_DYNAMIC)
1147             break;
1148 #endif
1149 #ifdef RTF_CLONED
1150         if (rtm->rtm_flags & RTF_CLONED)
1151             break;
1152 #endif
1153 #ifdef RTF_LLINFO
1154         if (rtm->rtm_flags & RTF_LLINFO)
1155             break;
1156 #endif
1157 #if 0
1158         krb5_klog_syslog(LOG_DEBUG,
1159                          "network reconfiguration message (%s) received",
1160                          rtm_type_name(rtm->rtm_type));
1161 #endif
1162         return 1;
1163     case RTM_RESOLVE:
1164 #ifdef RTM_NEWMADDR
1165     case RTM_NEWMADDR:
1166     case RTM_DELMADDR:
1167 #endif
1168     case RTM_MISS:
1169     case RTM_REDIRECT:
1170     case RTM_LOSING:
1171     case RTM_GET:
1172         /* Not interesting.  */
1173 #if 0
1174         krb5_klog_syslog(LOG_DEBUG, "routing msg not interesting");
1175 #endif
1176         break;
1177     default:
1178         krb5_klog_syslog(LOG_INFO,
1179                          _("unhandled routing message type %d, "
1180                            "will reconfigure just for the fun of it"),
1181                          rtm->rtm_type);
1182         return 1;
1183     }
1184
1185     return 0;
1186 }
1187
1188 static void
1189 process_routing_update(verto_ctx *ctx, verto_ev *ev)
1190 {
1191     int n_read, fd;
1192     struct rt_msghdr rtm;
1193     struct connection *conn;
1194
1195     fd = verto_get_fd(ev);
1196     conn = verto_get_private(ev);
1197     while ((n_read = read(fd, &rtm, sizeof(rtm))) > 0) {
1198         if (n_read < sizeof(rtm)) {
1199             /* Quick hack to figure out if the interesting
1200                fields are present in a short read.
1201
1202                A short read seems to be normal for some message types.
1203                Only complain if we don't have the critical initial
1204                header fields.  */
1205 #define RS(FIELD) (offsetof(struct rt_msghdr, FIELD) + sizeof(rtm.FIELD))
1206             if (n_read < RS(rtm_type) ||
1207                 n_read < RS(rtm_version) ||
1208                 n_read < RS(rtm_msglen)) {
1209                 krb5_klog_syslog(LOG_ERR,
1210                                  _("short read (%d/%d) from routing socket"),
1211                                  n_read, (int) sizeof(rtm));
1212                 return;
1213             }
1214         }
1215 #if 0
1216         krb5_klog_syslog(LOG_INFO,
1217                          _("got routing msg type %d(%s) v%d"),
1218                          rtm.rtm_type, rtm_type_name(rtm.rtm_type),
1219                          rtm.rtm_version);
1220 #endif
1221         if (rtm.rtm_msglen > sizeof(rtm)) {
1222             /* It appears we get a partial message and the rest is
1223                thrown away?  */
1224         } else if (rtm.rtm_msglen != n_read) {
1225             krb5_klog_syslog(LOG_ERR,
1226                              _("read %d from routing socket but msglen is %d"),
1227                              n_read, rtm.rtm_msglen);
1228         }
1229
1230         if (routing_update_needed(&rtm)) {
1231             /* Ideally we would use idle here instead of timeout. However, idle
1232              * is not universally supported yet in all backends. So let's just
1233              * use timeout for now to avoid locking into a loop. */
1234             ev = verto_add_timeout(ctx, VERTO_EV_FLAG_NONE,
1235                                    do_network_reconfig, 0);
1236             verto_set_private(ev, conn, NULL);
1237             assert(ev);
1238         }
1239     }
1240 }
1241 #endif
1242
1243 krb5_error_code
1244 loop_setup_routing_socket(verto_ctx *ctx, void *handle, const char *progname)
1245 {
1246 #ifdef HAVE_STRUCT_RT_MSGHDR
1247     struct socksetup data;
1248     int sock;
1249
1250     data.ctx = ctx;
1251     data.handle = handle;
1252     data.prog = progname;
1253     data.retval = 0;
1254
1255     sock = socket(PF_ROUTE, SOCK_RAW, 0);
1256     if (sock < 0) {
1257         int e = errno;
1258         krb5_klog_syslog(LOG_INFO, _("couldn't set up routing socket: %s"),
1259                          strerror(e));
1260     } else {
1261         krb5_klog_syslog(LOG_INFO, _("routing socket is fd %d"), sock);
1262         setnbio(sock);
1263         add_fd(&data, sock, CONN_ROUTING,
1264                VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
1265                process_routing_update, 0);
1266     }
1267 #endif
1268     return 0;
1269 }
1270
1271 /* XXX */
1272 extern void (*krb5int_sendtokdc_debug_handler)(const void*, size_t);
1273
1274 krb5_error_code
1275 loop_setup_network(verto_ctx *ctx, void *handle, const char *prog)
1276 {
1277     struct socksetup setup_data;
1278     verto_ev *ev;
1279     int i;
1280
1281     krb5int_sendtokdc_debug_handler = klog_handler;
1282
1283     /* Close any open connections. */
1284     FOREACH_ELT(events, i, ev)
1285         verto_del(ev);
1286     events.n = 0;
1287
1288     setup_data.ctx = ctx;
1289     setup_data.handle = handle;
1290     setup_data.prog = prog;
1291     setup_data.retval = 0;
1292     krb5_klog_syslog(LOG_INFO, _("setting up network..."));
1293
1294     /*
1295      * To do: Use RFC 2292 interface (or follow-on) and IPV6_PKTINFO,
1296      * so we might need only one UDP socket; fall back to binding
1297      * sockets on each address only if IPV6_PKTINFO isn't
1298      * supported.
1299      */
1300     setup_data.udp_flags = UDP_DO_IPV4 | UDP_DO_IPV6;
1301     setup_udp_pktinfo_ports(&setup_data);
1302     if (setup_data.udp_flags) {
1303         if (foreach_localaddr (&setup_data, setup_udp_port, 0, 0)) {
1304             return setup_data.retval;
1305         }
1306     }
1307     setup_tcp_listener_ports(&setup_data);
1308     setup_rpc_listener_ports(&setup_data);
1309     krb5_klog_syslog (LOG_INFO, _("set up %d sockets"), (int) events.n);
1310     if (events.n == 0) {
1311         com_err(prog, 0, _("no sockets set up?"));
1312         exit (1);
1313     }
1314
1315     return 0;
1316 }
1317
1318 void
1319 init_addr(krb5_fulladdr *faddr, struct sockaddr *sa)
1320 {
1321     switch (sa->sa_family) {
1322     case AF_INET:
1323         faddr->address->addrtype = ADDRTYPE_INET;
1324         faddr->address->length = 4;
1325         faddr->address->contents = (krb5_octet *) &sa2sin(sa)->sin_addr;
1326         faddr->port = ntohs(sa2sin(sa)->sin_port);
1327         break;
1328 #ifdef KRB5_USE_INET6
1329     case AF_INET6:
1330         if (IN6_IS_ADDR_V4MAPPED(&sa2sin6(sa)->sin6_addr)) {
1331             faddr->address->addrtype = ADDRTYPE_INET;
1332             faddr->address->length = 4;
1333             faddr->address->contents = 12 + (krb5_octet *) &sa2sin6(sa)->sin6_addr;
1334         } else {
1335             faddr->address->addrtype = ADDRTYPE_INET6;
1336             faddr->address->length = 16;
1337             faddr->address->contents = (krb5_octet *) &sa2sin6(sa)->sin6_addr;
1338         }
1339         faddr->port = ntohs(sa2sin6(sa)->sin6_port);
1340         break;
1341 #endif
1342     default:
1343         faddr->address->addrtype = -1;
1344         faddr->address->length = 0;
1345         faddr->address->contents = 0;
1346         faddr->port = 0;
1347         break;
1348     }
1349 }
1350
1351 /*
1352  * This holds whatever additional information might be needed to
1353  * properly send back to the client from the correct local address.
1354  *
1355  * In this case, we only need one datum so far: On Mac OS X, the
1356  * kernel doesn't seem to like sending from link-local addresses
1357  * unless we specify the correct interface.
1358  */
1359
1360 union aux_addressing_info {
1361     int ipv6_ifindex;
1362 };
1363
1364 static int
1365 recv_from_to(int s, void *buf, size_t len, int flags,
1366              struct sockaddr *from, socklen_t *fromlen,
1367              struct sockaddr *to, socklen_t *tolen,
1368              union aux_addressing_info *auxaddr)
1369 {
1370 #if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE)
1371     if (to && tolen) {
1372         /* Clobber with something recognizeable in case we try to use
1373            the address.  */
1374         memset(to, 0x40, *tolen);
1375         *tolen = 0;
1376     }
1377
1378     return recvfrom(s, buf, len, flags, from, fromlen);
1379 #else
1380     int r;
1381     struct iovec iov;
1382     char cmsg[CMSG_SPACE(sizeof(union pktinfo))];
1383     struct cmsghdr *cmsgptr;
1384     struct msghdr msg;
1385
1386     if (!to || !tolen)
1387         return recvfrom(s, buf, len, flags, from, fromlen);
1388
1389     /* Clobber with something recognizeable in case we can't extract
1390        the address but try to use it anyways.  */
1391     memset(to, 0x40, *tolen);
1392
1393     iov.iov_base = buf;
1394     iov.iov_len = len;
1395     memset(&msg, 0, sizeof(msg));
1396     msg.msg_name = from;
1397     msg.msg_namelen = *fromlen;
1398     msg.msg_iov = &iov;
1399     msg.msg_iovlen = 1;
1400     msg.msg_control = cmsg;
1401     msg.msg_controllen = sizeof(cmsg);
1402
1403     r = recvmsg(s, &msg, flags);
1404     if (r < 0)
1405         return r;
1406     *fromlen = msg.msg_namelen;
1407
1408     /* On Darwin (and presumably all *BSD with KAME stacks),
1409        CMSG_FIRSTHDR doesn't check for a non-zero controllen.  RFC
1410        3542 recommends making this check, even though the (new) spec
1411        for CMSG_FIRSTHDR says it's supposed to do the check.  */
1412     if (msg.msg_controllen) {
1413         cmsgptr = CMSG_FIRSTHDR(&msg);
1414         while (cmsgptr) {
1415 #ifdef IP_PKTINFO
1416             if (cmsgptr->cmsg_level == IPPROTO_IP
1417                 && cmsgptr->cmsg_type == IP_PKTINFO
1418                 && *tolen >= sizeof(struct sockaddr_in)) {
1419                 struct in_pktinfo *pktinfo;
1420                 memset(to, 0, sizeof(struct sockaddr_in));
1421                 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
1422                 ((struct sockaddr_in *)to)->sin_addr = pktinfo->ipi_addr;
1423                 ((struct sockaddr_in *)to)->sin_family = AF_INET;
1424                 *tolen = sizeof(struct sockaddr_in);
1425                 return r;
1426             }
1427 #endif
1428 #if defined(KRB5_USE_INET6) && defined(IPV6_PKTINFO) && \
1429     defined(HAVE_STRUCT_IN6_PKTINFO)
1430             if (cmsgptr->cmsg_level == IPPROTO_IPV6
1431                 && cmsgptr->cmsg_type == IPV6_PKTINFO
1432                 && *tolen >= sizeof(struct sockaddr_in6)) {
1433                 struct in6_pktinfo *pktinfo;
1434                 memset(to, 0, sizeof(struct sockaddr_in6));
1435                 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
1436                 ((struct sockaddr_in6 *)to)->sin6_addr = pktinfo->ipi6_addr;
1437                 ((struct sockaddr_in6 *)to)->sin6_family = AF_INET6;
1438                 *tolen = sizeof(struct sockaddr_in6);
1439                 auxaddr->ipv6_ifindex = pktinfo->ipi6_ifindex;
1440                 return r;
1441             }
1442 #endif
1443             cmsgptr = CMSG_NXTHDR(&msg, cmsgptr);
1444         }
1445     }
1446     /* No info about destination addr was available.  */
1447     *tolen = 0;
1448     return r;
1449 #endif
1450 }
1451
1452 static int
1453 send_to_from(int s, void *buf, size_t len, int flags,
1454              const struct sockaddr *to, socklen_t tolen,
1455              const struct sockaddr *from, socklen_t fromlen,
1456              union aux_addressing_info *auxaddr)
1457 {
1458 #if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE)
1459     return sendto(s, buf, len, flags, to, tolen);
1460 #else
1461     struct iovec iov;
1462     struct msghdr msg;
1463     struct cmsghdr *cmsgptr;
1464     char cbuf[CMSG_SPACE(sizeof(union pktinfo))];
1465
1466     if (from == 0 || fromlen == 0 || from->sa_family != to->sa_family) {
1467     use_sendto:
1468         return sendto(s, buf, len, flags, to, tolen);
1469     }
1470
1471     iov.iov_base = buf;
1472     iov.iov_len = len;
1473     /* Truncation?  */
1474     if (iov.iov_len != len)
1475         return EINVAL;
1476     memset(cbuf, 0, sizeof(cbuf));
1477     memset(&msg, 0, sizeof(msg));
1478     msg.msg_name = (void *) to;
1479     msg.msg_namelen = tolen;
1480     msg.msg_iov = &iov;
1481     msg.msg_iovlen = 1;
1482     msg.msg_control = cbuf;
1483     /* CMSG_FIRSTHDR needs a non-zero controllen, or it'll return NULL
1484        on Linux.  */
1485     msg.msg_controllen = sizeof(cbuf);
1486     cmsgptr = CMSG_FIRSTHDR(&msg);
1487     msg.msg_controllen = 0;
1488
1489     switch (from->sa_family) {
1490 #if defined(IP_PKTINFO)
1491     case AF_INET:
1492         if (fromlen != sizeof(struct sockaddr_in))
1493             goto use_sendto;
1494         cmsgptr->cmsg_level = IPPROTO_IP;
1495         cmsgptr->cmsg_type = IP_PKTINFO;
1496         cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
1497         {
1498             struct in_pktinfo *p = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
1499             const struct sockaddr_in *from4 = (const struct sockaddr_in *)from;
1500             p->ipi_spec_dst = from4->sin_addr;
1501         }
1502         msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
1503         break;
1504 #endif
1505 #if defined(KRB5_USE_INET6) && defined(IPV6_PKTINFO) && \
1506     defined(HAVE_STRUCT_IN6_PKTINFO)
1507     case AF_INET6:
1508         if (fromlen != sizeof(struct sockaddr_in6))
1509             goto use_sendto;
1510         cmsgptr->cmsg_level = IPPROTO_IPV6;
1511         cmsgptr->cmsg_type = IPV6_PKTINFO;
1512         cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1513         {
1514             struct in6_pktinfo *p = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
1515             const struct sockaddr_in6 *from6 =
1516                 (const struct sockaddr_in6 *)from;
1517             p->ipi6_addr = from6->sin6_addr;
1518             /*
1519              * Because of the possibility of asymmetric routing, we
1520              * normally don't want to specify an interface.  However,
1521              * Mac OS X doesn't like sending from a link-local address
1522              * (which can come up in testing at least, if you wind up
1523              * with a "foo.local" name) unless we do specify the
1524              * interface.
1525              */
1526             if (IN6_IS_ADDR_LINKLOCAL(&from6->sin6_addr))
1527                 p->ipi6_ifindex = auxaddr->ipv6_ifindex;
1528             /* otherwise, already zero */
1529         }
1530         msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1531         break;
1532 #endif
1533     default:
1534         goto use_sendto;
1535     }
1536     return sendmsg(s, &msg, flags);
1537 #endif
1538 }
1539
1540 static void
1541 process_packet(verto_ctx *ctx, verto_ev *ev)
1542 {
1543     int cc;
1544     socklen_t saddr_len, daddr_len;
1545     krb5_fulladdr faddr;
1546     krb5_error_code retval;
1547     struct sockaddr_storage saddr, daddr;
1548     krb5_address addr;
1549     krb5_data request;
1550     krb5_data *response;
1551     char pktbuf[MAX_DGRAM_SIZE];
1552     int port_fd;
1553     union aux_addressing_info auxaddr;
1554     struct connection *conn;
1555
1556     port_fd = verto_get_fd(ev);
1557     conn = verto_get_private(ev);
1558     assert(port_fd >= 0);
1559
1560     response = NULL;
1561     saddr_len = sizeof(saddr);
1562     daddr_len = sizeof(daddr);
1563     memset(&auxaddr, 0, sizeof(auxaddr));
1564     cc = recv_from_to(port_fd, pktbuf, sizeof(pktbuf), 0,
1565                       (struct sockaddr *)&saddr, &saddr_len,
1566                       (struct sockaddr *)&daddr, &daddr_len,
1567                       &auxaddr);
1568     if (cc == -1) {
1569         if (errno != EINTR && errno != EAGAIN
1570             /*
1571              * This is how Linux indicates that a previous transmission was
1572              * refused, e.g., if the client timed out before getting the
1573              * response packet.
1574              */
1575             && errno != ECONNREFUSED
1576         )
1577             com_err(conn->prog, errno, _("while receiving from network"));
1578         return;
1579     }
1580     if (!cc)
1581         return;         /* zero-length packet? */
1582
1583 #if 0
1584     if (daddr_len > 0) {
1585         char addrbuf[100];
1586         if (getnameinfo(ss2sa(&daddr), daddr_len, addrbuf, sizeof(addrbuf),
1587                         0, 0, NI_NUMERICHOST))
1588             strlcpy(addrbuf, "?", sizeof(addrbuf));
1589         com_err(conn->prog, 0, _("pktinfo says local addr is %s"), addrbuf);
1590     }
1591 #endif
1592
1593     if (daddr_len == 0 && conn->type == CONN_UDP) {
1594         /*
1595          * If the PKTINFO option isn't set, this socket should be bound to a
1596          * specific local address.  This info probably should've been saved in
1597          * our socket data structure at setup time.
1598          */
1599         daddr_len = sizeof(daddr);
1600         if (getsockname(port_fd, (struct sockaddr *)&daddr, &daddr_len) != 0)
1601             daddr_len = 0;
1602         /* On failure, keep going anyways. */
1603     }
1604
1605     request.length = cc;
1606     request.data = pktbuf;
1607     faddr.address = &addr;
1608     init_addr(&faddr, ss2sa(&saddr));
1609     /* This address is in net order. */
1610     retval = dispatch(conn->handle, ss2sa(&daddr),
1611                       &faddr, &request, &response, 0);
1612     if (retval) {
1613         com_err(conn->prog, retval, _("while dispatching (udp)"));
1614         return;
1615     }
1616     if (response == NULL)
1617         return;
1618     cc = send_to_from(port_fd, response->data, (socklen_t) response->length, 0,
1619                       (struct sockaddr *)&saddr, saddr_len,
1620                       (struct sockaddr *)&daddr, daddr_len,
1621                       &auxaddr);
1622     if (cc == -1) {
1623         /* Note that the local address (daddr*) has no port number
1624          * info associated with it. */
1625         char saddrbuf[NI_MAXHOST], sportbuf[NI_MAXSERV];
1626         char daddrbuf[NI_MAXHOST];
1627         int e = errno;
1628         krb5_free_data(get_context(conn->handle), response);
1629         if (getnameinfo((struct sockaddr *)&daddr, daddr_len,
1630                         daddrbuf, sizeof(daddrbuf), 0, 0,
1631                         NI_NUMERICHOST) != 0) {
1632             strlcpy(daddrbuf, "?", sizeof(daddrbuf));
1633         }
1634         if (getnameinfo((struct sockaddr *)&saddr, saddr_len,
1635                         saddrbuf, sizeof(saddrbuf), sportbuf, sizeof(sportbuf),
1636                         NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
1637             strlcpy(saddrbuf, "?", sizeof(saddrbuf));
1638             strlcpy(sportbuf, "?", sizeof(sportbuf));
1639         }
1640         com_err(conn->prog, e, _("while sending reply to %s/%s from %s"),
1641                 saddrbuf, sportbuf, daddrbuf);
1642         return;
1643     }
1644     if ((size_t)cc != response->length) {
1645         com_err(conn->prog, 0, _("short reply write %d vs %d\n"),
1646                 response->length, cc);
1647     }
1648     krb5_free_data(get_context(conn->handle), response);
1649     return;
1650 }
1651
1652 static int
1653 kill_lru_tcp_or_rpc_connection(void *handle, verto_ev *newev)
1654 {
1655     struct connection *c = NULL, *oldest_c = NULL;
1656     verto_ev *ev, *oldest_ev = NULL;
1657     int i, fd = -1;
1658
1659     krb5_klog_syslog(LOG_INFO, _("too many connections"));
1660
1661     FOREACH_ELT (events, i, ev) {
1662         if (ev == newev)
1663             continue;
1664
1665         c = verto_get_private(ev);
1666         if (!c)
1667             continue;
1668         if (c->type != CONN_TCP && c->type != CONN_RPC)
1669             continue;
1670 #if 0
1671         krb5_klog_syslog(LOG_INFO, "fd %d started at %ld",
1672                          verto_get_fd(oldest_ev),
1673                          c->u.tcp.start_time);
1674 #endif
1675         if (oldest_c == NULL
1676             || oldest_c->u.tcp.start_time > c->u.tcp.start_time) {
1677             oldest_ev = ev;
1678             oldest_c = c;
1679         }
1680     }
1681     if (oldest_c != NULL) {
1682         krb5_klog_syslog(LOG_INFO, _("dropping %s fd %d from %s"),
1683                          c->type == CONN_RPC ? "rpc" : "tcp",
1684                          verto_get_fd(oldest_ev), oldest_c->u.tcp.addrbuf);
1685         if (oldest_c->type == CONN_RPC)
1686             oldest_c->u.rpc.closed = 1;
1687         verto_del(oldest_ev);
1688     }
1689     return fd;
1690 }
1691
1692 static void
1693 accept_tcp_connection(verto_ctx *ctx, verto_ev *ev)
1694 {
1695     int s;
1696     struct sockaddr_storage addr_s;
1697     struct sockaddr *addr = (struct sockaddr *)&addr_s;
1698     socklen_t addrlen = sizeof(addr_s);
1699     struct socksetup sockdata;
1700     struct connection *newconn, *conn;
1701     char tmpbuf[10];
1702     verto_ev *newev;
1703
1704     conn = verto_get_private(ev);
1705     s = accept(verto_get_fd(ev), addr, &addrlen);
1706     if (s < 0)
1707         return;
1708     set_cloexec_fd(s);
1709 #ifndef _WIN32
1710     if (s >= FD_SETSIZE) {
1711         close(s);
1712         return;
1713     }
1714 #endif
1715     setnbio(s), setnolinger(s), setkeepalive(s);
1716
1717     sockdata.ctx = ctx;
1718     sockdata.handle = conn->handle;
1719     sockdata.prog = conn->prog;
1720     sockdata.retval = 0;
1721
1722     newev = add_tcp_read_fd(&sockdata, s);
1723     if (newev == NULL) {
1724         close(s);
1725         return;
1726     }
1727     newconn = verto_get_private(newev);
1728
1729     if (getnameinfo((struct sockaddr *)&addr_s, addrlen,
1730                     newconn->u.tcp.addrbuf, sizeof(newconn->u.tcp.addrbuf),
1731                     tmpbuf, sizeof(tmpbuf),
1732                     NI_NUMERICHOST | NI_NUMERICSERV))
1733         strlcpy(newconn->u.tcp.addrbuf, "???", sizeof(newconn->u.tcp.addrbuf));
1734     else {
1735         char *p, *end;
1736         p = newconn->u.tcp.addrbuf;
1737         end = p + sizeof(newconn->u.tcp.addrbuf);
1738         p += strlen(p);
1739         if ((size_t)(end - p) > 2 + strlen(tmpbuf)) {
1740             *p++ = '.';
1741             strlcpy(p, tmpbuf, end - p);
1742         }
1743     }
1744 #if 0
1745     krb5_klog_syslog(LOG_INFO, "accepted TCP connection on socket %d from %s",
1746                      s, newconn->u.tcp.addrbuf);
1747 #endif
1748
1749     newconn->u.tcp.addr_s = addr_s;
1750     newconn->u.tcp.addrlen = addrlen;
1751     newconn->u.tcp.bufsiz = 1024 * 1024;
1752     newconn->u.tcp.buffer = malloc(newconn->u.tcp.bufsiz);
1753     newconn->u.tcp.start_time = time(0);
1754
1755     if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
1756         kill_lru_tcp_or_rpc_connection(conn->handle, newev);
1757
1758     if (newconn->u.tcp.buffer == 0) {
1759         com_err(conn->prog, errno,
1760                 _("allocating buffer for new TCP session from %s"),
1761                 newconn->u.tcp.addrbuf);
1762         verto_del(newev);
1763         return;
1764     }
1765     newconn->u.tcp.offset = 0;
1766     newconn->u.tcp.faddr.address = &newconn->u.tcp.kaddr;
1767     init_addr(&newconn->u.tcp.faddr, ss2sa(&newconn->u.tcp.addr_s));
1768     SG_SET(&newconn->u.tcp.sgbuf[0], newconn->u.tcp.lenbuf, 4);
1769     SG_SET(&newconn->u.tcp.sgbuf[1], 0, 0);
1770 }
1771
1772 static void
1773 process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
1774 {
1775     struct connection *conn;
1776     ssize_t nread;
1777     size_t len;
1778     int sock;
1779
1780     conn = verto_get_private(ev);
1781     sock = verto_get_fd(ev);
1782
1783     /*
1784      * Read message length and data into one big buffer, already allocated
1785      * at connect time.  If we have a complete message, we stop reading, so
1786      * we should only be here if there is no data in the buffer, or only an
1787      * incomplete message.
1788      */
1789     if (conn->u.tcp.offset < 4) {
1790         /* msglen has not been computed.  XXX Doing at least two reads
1791          * here, letting the kernel worry about buffering. */
1792         len = 4 - conn->u.tcp.offset;
1793         nread = SOCKET_READ(sock,
1794                             conn->u.tcp.buffer + conn->u.tcp.offset, len);
1795         if (nread < 0) /* error */
1796             goto kill_tcp_connection;
1797         if (nread == 0) /* eof */
1798             goto kill_tcp_connection;
1799         conn->u.tcp.offset += nread;
1800         if (conn->u.tcp.offset == 4) {
1801             unsigned char *p = (unsigned char *)conn->u.tcp.buffer;
1802             conn->u.tcp.msglen = load_32_be(p);
1803             if (conn->u.tcp.msglen > conn->u.tcp.bufsiz - 4) {
1804                 krb5_error_code err;
1805                 /* Message too big. */
1806                 krb5_klog_syslog(LOG_ERR, _("TCP client %s wants %lu bytes, "
1807                                  "cap is %lu"), conn->u.tcp.addrbuf,
1808                                  (unsigned long) conn->u.tcp.msglen,
1809                                  (unsigned long) conn->u.tcp.bufsiz - 4);
1810                 /* XXX Should return an error.  */
1811                 err = make_toolong_error (conn->handle,
1812                                           &conn->u.tcp.response);
1813                 if (err) {
1814                     krb5_klog_syslog(LOG_ERR, _("error constructing "
1815                                      "KRB_ERR_FIELD_TOOLONG error! %s"),
1816                                      error_message(err));
1817                     goto kill_tcp_connection;
1818                 }
1819                 goto have_response;
1820             }
1821         }
1822     } else {
1823         /* msglen known. */
1824         krb5_data request;
1825         krb5_error_code err;
1826         struct sockaddr_storage local_saddr;
1827         socklen_t local_saddrlen = sizeof(local_saddr);
1828         struct sockaddr *local_saddrp = NULL;
1829
1830         len = conn->u.tcp.msglen - (conn->u.tcp.offset - 4);
1831         nread = SOCKET_READ(sock,
1832                             conn->u.tcp.buffer + conn->u.tcp.offset, len);
1833         if (nread < 0) /* error */
1834             goto kill_tcp_connection;
1835         if (nread == 0) /* eof */
1836             goto kill_tcp_connection;
1837         conn->u.tcp.offset += nread;
1838         if (conn->u.tcp.offset < conn->u.tcp.msglen + 4)
1839             return;
1840         /* Have a complete message, and exactly one message. */
1841         request.length = conn->u.tcp.msglen;
1842         request.data = conn->u.tcp.buffer + 4;
1843
1844         if (getsockname(sock, ss2sa(&local_saddr),
1845                         &local_saddrlen) == 0)
1846             local_saddrp = ss2sa(&local_saddr);
1847
1848         err = dispatch(conn->handle, local_saddrp, &conn->u.tcp.faddr,
1849                        &request, &conn->u.tcp.response, 1);
1850         if (err) {
1851             com_err(conn->prog, err, _("while dispatching (tcp)"));
1852             goto kill_tcp_connection;
1853         }
1854         if (conn->u.tcp.response == NULL)
1855             goto kill_tcp_connection;
1856     have_response:
1857         /* Queue outgoing response. */
1858         store_32_be(conn->u.tcp.response->length, conn->u.tcp.lenbuf);
1859         SG_SET(&conn->u.tcp.sgbuf[1], conn->u.tcp.response->data,
1860                conn->u.tcp.response->length);
1861         conn->u.tcp.sgp = conn->u.tcp.sgbuf;
1862         conn->u.tcp.sgnum = 2;
1863
1864         if (convert_event(ctx, ev,
1865                           VERTO_EV_FLAG_IO_WRITE | VERTO_EV_FLAG_PERSIST,
1866                           process_tcp_connection_write))
1867             return;
1868     }
1869
1870     return;
1871
1872 kill_tcp_connection:
1873     verto_del(ev);
1874 }
1875
1876 static void
1877 process_tcp_connection_write(verto_ctx *ctx, verto_ev *ev)
1878 {
1879     struct connection *conn;
1880     SOCKET_WRITEV_TEMP tmp;
1881     ssize_t nwrote;
1882     int sock;
1883
1884     conn = verto_get_private(ev);
1885     sock = verto_get_fd(ev);
1886
1887     nwrote = SOCKET_WRITEV(sock, conn->u.tcp.sgp,
1888                            conn->u.tcp.sgnum, tmp);
1889     if (nwrote > 0) { /* non-error and non-eof */
1890         while (nwrote) {
1891             sg_buf *sgp = conn->u.tcp.sgp;
1892             if ((size_t)nwrote < SG_LEN(sgp)) {
1893                 SG_ADVANCE(sgp, (size_t)nwrote);
1894                 nwrote = 0;
1895             } else {
1896                 nwrote -= SG_LEN(sgp);
1897                 conn->u.tcp.sgp++;
1898                 conn->u.tcp.sgnum--;
1899                 if (conn->u.tcp.sgnum == 0 && nwrote != 0)
1900                     abort();
1901             }
1902         }
1903
1904         /* If we still have more data to send, just return so that
1905          * the main loop can call this function again when the socket
1906          * is ready for more writing. */
1907         if (conn->u.tcp.sgnum > 0)
1908             return;
1909     }
1910
1911     /* Finished sending.  We should go back to reading, though if we
1912      * sent a FIELD_TOOLONG error in reply to a length with the high
1913      * bit set, RFC 4120 says we have to close the TCP stream. */
1914     verto_del(ev);
1915 }
1916
1917 void
1918 loop_free(verto_ctx *ctx)
1919 {
1920     verto_free(ctx);
1921     FREE_SET_DATA(events);
1922     FREE_SET_DATA(udp_port_data);
1923     FREE_SET_DATA(tcp_port_data);
1924     FREE_SET_DATA(rpc_svc_data);
1925 }
1926
1927 static int
1928 have_event_for_fd(int fd)
1929 {
1930     verto_ev *ev;
1931     int i;
1932
1933     FOREACH_ELT(events, i, ev) {
1934         if (verto_get_fd(ev) == fd)
1935             return 1;
1936     }
1937
1938     return 0;
1939 }
1940
1941 static void
1942 accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
1943 {
1944     struct socksetup sockdata;
1945     struct connection *conn;
1946     fd_set fds;
1947     register int s;
1948
1949     conn = verto_get_private(ev);
1950
1951     sockdata.ctx = ctx;
1952     sockdata.handle = conn->handle;
1953     sockdata.prog = conn->prog;
1954     sockdata.retval = 0;
1955
1956     /* Service the woken RPC listener descriptor. */
1957     FD_ZERO(&fds);
1958     FD_SET(verto_get_fd(ev), &fds);
1959     svc_getreqset(&fds);
1960
1961     /* Scan svc_fdset for any new connections. */
1962     for (s = 0; s < FD_SETSIZE; s++) {
1963         struct sockaddr_storage addr_s;
1964         struct sockaddr *addr = (struct sockaddr *) &addr_s;
1965         socklen_t addrlen = sizeof(addr_s);
1966         struct connection *newconn;
1967         char tmpbuf[10];
1968         verto_ev *newev;
1969
1970         /* If we already have this fd, continue. */
1971         if (!FD_ISSET(s, &svc_fdset) || have_event_for_fd(s))
1972             continue;
1973
1974         newev = add_rpc_data_fd(&sockdata, s);
1975         if (newev == NULL)
1976             continue;
1977         newconn = verto_get_private(newev);
1978
1979         set_cloexec_fd(s);
1980 #if 0
1981         setnbio(s), setnolinger(s), setkeepalive(s);
1982 #endif
1983
1984         if (getpeername(s, addr, &addrlen) ||
1985             getnameinfo(addr, addrlen,
1986                         newconn->u.tcp.addrbuf,
1987                         sizeof(newconn->u.tcp.addrbuf),
1988                         tmpbuf, sizeof(tmpbuf),
1989                         NI_NUMERICHOST | NI_NUMERICSERV)) {
1990             strlcpy(newconn->u.tcp.addrbuf, "???",
1991                     sizeof(newconn->u.tcp.addrbuf));
1992         } else {
1993             char *p, *end;
1994             p = newconn->u.tcp.addrbuf;
1995             end = p + sizeof(newconn->u.tcp.addrbuf);
1996             p += strlen(p);
1997             if ((size_t)(end - p) > 2 + strlen(tmpbuf)) {
1998                 *p++ = '.';
1999                 strlcpy(p, tmpbuf, end - p);
2000             }
2001         }
2002 #if 0
2003         krb5_klog_syslog(LOG_INFO, _("accepted RPC connection on socket %d "
2004                          "from %s"), s, newconn->u.tcp.addrbuf);
2005 #endif
2006
2007         newconn->u.tcp.addr_s = addr_s;
2008         newconn->u.tcp.addrlen = addrlen;
2009         newconn->u.tcp.start_time = time(0);
2010
2011         if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
2012             kill_lru_tcp_or_rpc_connection(newconn->handle, newev);
2013
2014         newconn->u.tcp.faddr.address = &newconn->u.tcp.kaddr;
2015         init_addr(&newconn->u.tcp.faddr, ss2sa(&newconn->u.tcp.addr_s));
2016     }
2017 }
2018
2019 static void
2020 process_rpc_connection(verto_ctx *ctx, verto_ev *ev)
2021 {
2022     fd_set fds;
2023
2024     FD_ZERO(&fds);
2025     FD_SET(verto_get_fd(ev), &fds);
2026     svc_getreqset(&fds);
2027
2028     if (!FD_ISSET(verto_get_fd(ev), &svc_fdset))
2029         verto_del(ev);
2030 }
2031
2032 #endif /* INET */