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