Eliminate union in net-server.c struct connection
[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 convert_event(verto_ctx *ctx, verto_ev *ev, verto_ev_flag flags,
519               verto_callback callback)
520 {
521     struct connection *conn;
522     verto_ev *newev;
523     int sock;
524
525     conn = verto_get_private(ev);
526     sock = verto_get_fd(ev);
527     if (sock < 0)
528         return NULL;
529
530     newev = make_event(ctx, flags, callback, sock, conn, 1);
531
532     /* Delete the read event without closing the socket
533      * or freeing the connection struct. */
534     if (newev) {
535         verto_set_private(ev, NULL, NULL); /* Reset the destructor. */
536         remove_event_from_set(ev); /* Remove it from the set. */
537         verto_del(ev);
538     }
539
540     return newev;
541 }
542
543 static verto_ev *
544 add_fd(struct socksetup *data, int sock, enum conn_type conntype,
545        verto_ev_flag flags, verto_callback callback, int addevent)
546 {
547     struct connection *newconn;
548
549 #ifndef _WIN32
550     if (sock >= FD_SETSIZE) {
551         data->retval = EMFILE;  /* XXX */
552         com_err(data->prog, 0,
553                 _("file descriptor number %d too high"), sock);
554         return 0;
555     }
556 #endif
557     newconn = malloc(sizeof(*newconn));
558     if (newconn == NULL) {
559         data->retval = ENOMEM;
560         com_err(data->prog, ENOMEM,
561                 _("cannot allocate storage for connection info"));
562         return 0;
563     }
564     memset(newconn, 0, sizeof(*newconn));
565     newconn->handle = data->handle;
566     newconn->prog = data->prog;
567     newconn->type = conntype;
568
569     return make_event(data->ctx, flags, callback, sock, newconn, addevent);
570 }
571
572 static void process_packet(verto_ctx *ctx, verto_ev *ev);
573 static void accept_tcp_connection(verto_ctx *ctx, verto_ev *ev);
574 static void process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev);
575 static void process_tcp_connection_write(verto_ctx *ctx, verto_ev *ev);
576 static void accept_rpc_connection(verto_ctx *ctx, verto_ev *ev);
577 static void process_rpc_connection(verto_ctx *ctx, verto_ev *ev);
578
579 static verto_ev *
580 add_udp_fd(struct socksetup *data, int sock, int pktinfo)
581 {
582     return add_fd(data, sock, pktinfo ? CONN_UDP_PKTINFO : CONN_UDP,
583                   VERTO_EV_FLAG_IO_READ |
584                   VERTO_EV_FLAG_PERSIST |
585                   VERTO_EV_FLAG_REINITIABLE,
586                   process_packet, 1);
587 }
588
589 static verto_ev *
590 add_tcp_listener_fd(struct socksetup *data, int sock)
591 {
592     return add_fd(data, sock, CONN_TCP_LISTENER,
593                   VERTO_EV_FLAG_IO_READ |
594                   VERTO_EV_FLAG_PERSIST |
595                   VERTO_EV_FLAG_REINITIABLE,
596                   accept_tcp_connection, 1);
597 }
598
599 static verto_ev *
600 add_tcp_read_fd(struct socksetup *data, int sock)
601 {
602     return add_fd(data, sock, CONN_TCP,
603                   VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
604                   process_tcp_connection_read, 1);
605 }
606
607 /*
608  * Create a socket and bind it to addr.  Ensure the socket will work with
609  * select().  Set the socket cloexec, reuseaddr, and if applicable v6-only.
610  * Does not call listen().  Returns -1 on failure after logging an error.
611  */
612 static int
613 create_server_socket(struct socksetup *data, struct sockaddr *addr, int type)
614 {
615     int sock;
616
617     sock = socket(addr->sa_family, type, 0);
618     if (sock == -1) {
619         data->retval = errno;
620         com_err(data->prog, errno, _("Cannot create TCP server socket on %s"),
621                 paddr(addr));
622         return -1;
623     }
624     set_cloexec_fd(sock);
625
626 #ifndef _WIN32                  /* Windows FD_SETSIZE is a count. */
627     if (sock >= FD_SETSIZE) {
628         close(sock);
629         com_err(data->prog, 0, _("TCP socket fd number %d (for %s) too high"),
630                 sock, paddr(addr));
631         return -1;
632     }
633 #endif
634
635     if (setreuseaddr(sock, 1) < 0) {
636         com_err(data->prog, errno,
637                 _("Cannot enable SO_REUSEADDR on fd %d"), sock);
638     }
639
640 #ifdef KRB5_USE_INET6
641     if (addr->sa_family == AF_INET6) {
642 #ifdef IPV6_V6ONLY
643         if (setv6only(sock, 1))
644             com_err(data->prog, errno,
645                     _("setsockopt(%d,IPV6_V6ONLY,1) failed"), sock);
646         else
647             com_err(data->prog, 0, _("setsockopt(%d,IPV6_V6ONLY,1) worked"),
648                     sock);
649 #else
650         krb5_klog_syslog(LOG_INFO, _("no IPV6_V6ONLY socket option support"));
651 #endif /* IPV6_V6ONLY */
652     }
653 #endif /* KRB5_USE_INET6 */
654
655     if (bind(sock, addr, socklen(addr)) == -1) {
656         data->retval = errno;
657         com_err(data->prog, errno, _("Cannot bind server socket on %s"),
658                 paddr(addr));
659         close(sock);
660         return -1;
661     }
662
663     return sock;
664 }
665
666 static verto_ev *
667 add_rpc_listener_fd(struct socksetup *data, struct rpc_svc_data *svc, int sock)
668 {
669     struct connection *conn;
670     verto_ev *ev;
671
672     ev = add_fd(data, sock, CONN_RPC_LISTENER,
673                 VERTO_EV_FLAG_IO_READ |
674                 VERTO_EV_FLAG_PERSIST |
675                 VERTO_EV_FLAG_REINITIABLE,
676                 accept_rpc_connection, 1);
677     if (ev == NULL)
678         return NULL;
679
680     conn = verto_get_private(ev);
681     conn->transp = svctcp_create(sock, 0, 0);
682     if (conn->transp == NULL) {
683         krb5_klog_syslog(LOG_ERR,
684                          _("Cannot create RPC service: %s; continuing"),
685                          strerror(errno));
686         verto_del(ev);
687         return NULL;
688     }
689
690     if (!svc_register(conn->transp, svc->prognum, svc->versnum,
691                       svc->dispatch, 0)) {
692         krb5_klog_syslog(LOG_ERR,
693                          _("Cannot register RPC service: %s; continuing"),
694                          strerror(errno));
695         verto_del(ev);
696         return NULL;
697     }
698
699     return ev;
700 }
701
702 static verto_ev *
703 add_rpc_data_fd(struct socksetup *data, int sock)
704 {
705     return add_fd(data, sock, CONN_RPC,
706                   VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
707                   process_rpc_connection, 1);
708 }
709
710 static const int one = 1;
711
712 static int
713 setnbio(int sock)
714 {
715     return ioctlsocket(sock, FIONBIO, (const void *)&one);
716 }
717
718 static int
719 setkeepalive(int sock)
720 {
721     return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
722 }
723 \f
724 static int
725 setnolinger(int s)
726 {
727     static const struct linger ling = { 0, 0 };
728     return setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
729 }
730
731 /* Returns -1 or socket fd.  */
732 static int
733 setup_a_tcp_listener(struct socksetup *data, struct sockaddr *addr)
734 {
735     int sock;
736
737     sock = create_server_socket(data, addr, SOCK_STREAM);
738     if (sock == -1)
739         return -1;
740     if (listen(sock, 5) < 0) {
741         com_err(data->prog, errno,
742                 _("Cannot listen on TCP server socket on %s"), paddr(addr));
743         close(sock);
744         return -1;
745     }
746     if (setnbio(sock)) {
747         com_err(data->prog, errno,
748                 _("cannot set listening tcp socket on %s non-blocking"),
749                 paddr(addr));
750         close(sock);
751         return -1;
752     }
753     if (setnolinger(sock)) {
754         com_err(data->prog, errno,
755                 _("disabling SO_LINGER on TCP socket on %s"), paddr(addr));
756         close(sock);
757         return -1;
758     }
759     return sock;
760 }
761
762 static int
763 setup_tcp_listener_ports(struct socksetup *data)
764 {
765     struct sockaddr_in sin4;
766 #ifdef KRB5_USE_INET6
767     struct sockaddr_in6 sin6;
768 #endif
769     int i, port;
770
771     memset(&sin4, 0, sizeof(sin4));
772     sin4.sin_family = AF_INET;
773 #ifdef HAVE_SA_LEN
774     sin4.sin_len = sizeof(sin4);
775 #endif
776     sin4.sin_addr.s_addr = INADDR_ANY;
777
778 #ifdef KRB5_USE_INET6
779     memset(&sin6, 0, sizeof(sin6));
780     sin6.sin6_family = AF_INET6;
781 #ifdef SIN6_LEN
782     sin6.sin6_len = sizeof(sin6);
783 #endif
784     sin6.sin6_addr = in6addr_any;
785 #endif
786
787     FOREACH_ELT (tcp_port_data, i, port) {
788         int s4, s6;
789
790         set_sa_port((struct sockaddr *)&sin4, htons(port));
791         if (!ipv6_enabled()) {
792             s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
793             if (s4 < 0)
794                 return -1;
795             s6 = -1;
796         } else {
797 #ifndef KRB5_USE_INET6
798             abort();
799 #else
800             s4 = s6 = -1;
801
802             set_sa_port((struct sockaddr *)&sin6, htons(port));
803
804             s6 = setup_a_tcp_listener(data, (struct sockaddr *)&sin6);
805             if (s6 < 0)
806                 return -1;
807
808             s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
809 #endif /* KRB5_USE_INET6 */
810         }
811
812         /* Sockets are created, prepare to listen on them. */
813         if (s4 >= 0) {
814             if (add_tcp_listener_fd(data, s4) == NULL)
815                 close(s4);
816             else {
817                 krb5_klog_syslog(LOG_INFO, _("listening on fd %d: tcp %s"),
818                                  s4, paddr((struct sockaddr *)&sin4));
819             }
820         }
821 #ifdef KRB5_USE_INET6
822         if (s6 >= 0) {
823             if (add_tcp_listener_fd(data, s6) == NULL) {
824                 close(s6);
825                 s6 = -1;
826             } else {
827                 krb5_klog_syslog(LOG_INFO, _("listening on fd %d: tcp %s"),
828                                  s6, paddr((struct sockaddr *)&sin6));
829             }
830             if (s4 < 0)
831                 krb5_klog_syslog(LOG_INFO,
832                                  _("assuming IPv6 socket accepts IPv4"));
833         }
834 #endif
835     }
836     return 0;
837 }
838
839 static int
840 setup_rpc_listener_ports(struct socksetup *data)
841 {
842     struct sockaddr_in sin4;
843 #ifdef KRB5_USE_INET6
844     struct sockaddr_in6 sin6;
845 #endif
846     int i;
847     struct rpc_svc_data svc;
848
849     memset(&sin4, 0, sizeof(sin4));
850     sin4.sin_family = AF_INET;
851 #ifdef HAVE_SA_LEN
852     sin4.sin_len = sizeof(sin4);
853 #endif
854     sin4.sin_addr.s_addr = INADDR_ANY;
855
856 #ifdef KRB5_USE_INET6
857     memset(&sin6, 0, sizeof(sin6));
858     sin6.sin6_family = AF_INET6;
859 #ifdef HAVE_SA_LEN
860     sin6.sin6_len = sizeof(sin6);
861 #endif
862     sin6.sin6_addr = in6addr_any;
863 #endif
864
865     FOREACH_ELT (rpc_svc_data, i, svc) {
866         int s4;
867 #ifdef KRB5_USE_INET6
868         int s6;
869 #endif
870
871         set_sa_port((struct sockaddr *)&sin4, htons(svc.port));
872         s4 = create_server_socket(data, (struct sockaddr *)&sin4, SOCK_STREAM);
873         if (s4 < 0)
874             return -1;
875
876         if (add_rpc_listener_fd(data, &svc, s4) == NULL)
877             close(s4);
878         else
879             krb5_klog_syslog(LOG_INFO, _("listening on fd %d: rpc %s"),
880                              s4, paddr((struct sockaddr *)&sin4));
881
882 #ifdef KRB5_USE_INET6
883         if (ipv6_enabled()) {
884             set_sa_port((struct sockaddr *)&sin6, htons(svc.port));
885             s6 = create_server_socket(data, (struct sockaddr *)&sin6,
886                                       SOCK_STREAM);
887             if (s6 < 0)
888                 return -1;
889
890             if (add_rpc_listener_fd(data, &svc, s6) == NULL)
891                 close(s6);
892             else
893                 krb5_klog_syslog(LOG_INFO, _("listening on fd %d: rpc %s"),
894                                  s6, paddr((struct sockaddr *)&sin6));
895         }
896 #endif
897     }
898
899     return 0;
900 }
901
902 #if defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && \
903     (defined(IP_PKTINFO) || defined(IPV6_PKTINFO))
904 union pktinfo {
905 #ifdef HAVE_STRUCT_IN6_PKTINFO
906     struct in6_pktinfo pi6;
907 #endif
908 #ifdef HAVE_STRUCT_IN_PKTINFO
909     struct in_pktinfo pi4;
910 #endif
911     char c;
912 };
913
914 static int
915 setup_udp_port_1(struct socksetup *data, struct sockaddr *addr,
916                  char *haddrbuf, int pktinfo);
917
918 static void
919 setup_udp_pktinfo_ports(struct socksetup *data)
920 {
921 #ifdef IP_PKTINFO
922     {
923         struct sockaddr_in sa;
924         int r;
925
926         memset(&sa, 0, sizeof(sa));
927         sa.sin_family = AF_INET;
928 #ifdef HAVE_SA_LEN
929         sa.sin_len = sizeof(sa);
930 #endif
931         r = setup_udp_port_1(data, (struct sockaddr *) &sa, "0.0.0.0", 4);
932         if (r == 0)
933             data->udp_flags &= ~UDP_DO_IPV4;
934     }
935 #endif
936 #ifdef IPV6_PKTINFO
937     {
938         struct sockaddr_in6 sa;
939         int r;
940
941         memset(&sa, 0, sizeof(sa));
942         sa.sin6_family = AF_INET6;
943 #ifdef HAVE_SA_LEN
944         sa.sin6_len = sizeof(sa);
945 #endif
946         r = setup_udp_port_1(data, (struct sockaddr *) &sa, "::", 6);
947         if (r == 0)
948             data->udp_flags &= ~UDP_DO_IPV6;
949     }
950 #endif
951 }
952 #else /* no pktinfo compile-time support */
953 static void
954 setup_udp_pktinfo_ports(struct socksetup *data)
955 {
956 }
957 #endif
958
959 static int
960 setup_udp_port_1(struct socksetup *data, struct sockaddr *addr,
961                  char *haddrbuf, int pktinfo)
962 {
963     int sock = -1, i, r;
964     u_short port;
965
966     FOREACH_ELT (udp_port_data, i, port) {
967         set_sa_port(addr, htons(port));
968         sock = create_server_socket(data, addr, SOCK_DGRAM);
969         if (sock == -1)
970             return 1;
971         setnbio(sock);
972
973 #if !(defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && \
974       (defined(IP_PKTINFO) || defined(IPV6_PKTINFO)))
975         assert(pktinfo == 0);
976 #endif
977         if (pktinfo) {
978             r = set_pktinfo(sock, addr->sa_family);
979             if (r) {
980                 com_err(data->prog, r,
981                         _("Cannot request packet info for udp socket address "
982                           "%s port %d"), haddrbuf, port);
983                 close(sock);
984                 return 1;
985             }
986         }
987         krb5_klog_syslog(LOG_INFO, _("listening on fd %d: udp %s%s"), sock,
988                          paddr((struct sockaddr *)addr),
989                          pktinfo ? " (pktinfo)" : "");
990         if (add_udp_fd (data, sock, pktinfo) == 0) {
991             close(sock);
992             return 1;
993         }
994     }
995     return 0;
996 }
997
998 static int
999 setup_udp_port(void *P_data, struct sockaddr *addr)
1000 {
1001     struct socksetup *data = P_data;
1002     char haddrbuf[NI_MAXHOST];
1003     int err;
1004
1005     if (addr->sa_family == AF_INET && !(data->udp_flags & UDP_DO_IPV4))
1006         return 0;
1007 #ifdef AF_INET6
1008     if (addr->sa_family == AF_INET6 && !(data->udp_flags & UDP_DO_IPV6))
1009         return 0;
1010 #endif
1011     err = getnameinfo(addr, socklen(addr), haddrbuf, sizeof(haddrbuf),
1012                       0, 0, NI_NUMERICHOST);
1013     if (err)
1014         strlcpy(haddrbuf, "<unprintable>", sizeof(haddrbuf));
1015
1016     switch (addr->sa_family) {
1017     case AF_INET:
1018         break;
1019 #ifdef AF_INET6
1020     case AF_INET6:
1021 #ifdef KRB5_USE_INET6
1022         break;
1023 #else
1024         {
1025             static int first = 1;
1026             if (first) {
1027                 krb5_klog_syslog(LOG_INFO, _("skipping local ipv6 addresses"));
1028                 first = 0;
1029             }
1030             return 0;
1031         }
1032 #endif
1033 #endif
1034 #ifdef AF_LINK /* some BSD systems, AIX */
1035     case AF_LINK:
1036         return 0;
1037 #endif
1038 #ifdef AF_DLI /* Direct Link Interface - DEC Ultrix/OSF1 link layer? */
1039     case AF_DLI:
1040         return 0;
1041 #endif
1042 #ifdef AF_APPLETALK
1043     case AF_APPLETALK:
1044         return 0;
1045 #endif
1046     default:
1047         krb5_klog_syslog(LOG_INFO,
1048                          _("skipping unrecognized local address family %d"),
1049                          addr->sa_family);
1050         return 0;
1051     }
1052     return setup_udp_port_1(data, addr, haddrbuf, 0);
1053 }
1054
1055 #if 1
1056 static void
1057 klog_handler(const void *data, size_t len)
1058 {
1059     static char buf[BUFSIZ];
1060     static int bufoffset;
1061     void *p;
1062
1063 #define flush_buf()                             \
1064     (bufoffset                                  \
1065      ? (((buf[0] == 0 || buf[0] == '\n')        \
1066          ? (fork()==0?abort():(void)0)          \
1067          : (void)0),                            \
1068         krb5_klog_syslog(LOG_INFO, "%s", buf),  \
1069         memset(buf, 0, sizeof(buf)),            \
1070         bufoffset = 0)                          \
1071      : 0)
1072
1073     p = memchr(data, 0, len);
1074     if (p)
1075         len = (const char *)p - (const char *)data;
1076 scan_for_newlines:
1077     if (len == 0)
1078         return;
1079     p = memchr(data, '\n', len);
1080     if (p) {
1081         if (p != data)
1082             klog_handler(data, (size_t)((const char *)p - (const char *)data));
1083         flush_buf();
1084         len -= ((const char *)p - (const char *)data) + 1;
1085         data = 1 + (const char *)p;
1086         goto scan_for_newlines;
1087     } else if (len > sizeof(buf) - 1 || len + bufoffset > sizeof(buf) - 1) {
1088         size_t x = sizeof(buf) - len - 1;
1089         klog_handler(data, x);
1090         flush_buf();
1091         len -= x;
1092         data = (const char *)data + x;
1093         goto scan_for_newlines;
1094     } else {
1095         memcpy(buf + bufoffset, data, len);
1096         bufoffset += len;
1097     }
1098 }
1099 #endif
1100
1101 #ifdef HAVE_STRUCT_RT_MSGHDR
1102 #include <net/route.h>
1103
1104 static char *
1105 rtm_type_name(int type)
1106 {
1107     switch (type) {
1108     case RTM_ADD: return "RTM_ADD";
1109     case RTM_DELETE: return "RTM_DELETE";
1110     case RTM_NEWADDR: return "RTM_NEWADDR";
1111     case RTM_DELADDR: return "RTM_DELADDR";
1112     case RTM_IFINFO: return "RTM_IFINFO";
1113     case RTM_OLDADD: return "RTM_OLDADD";
1114     case RTM_OLDDEL: return "RTM_OLDDEL";
1115     case RTM_RESOLVE: return "RTM_RESOLVE";
1116 #ifdef RTM_NEWMADDR
1117     case RTM_NEWMADDR: return "RTM_NEWMADDR";
1118     case RTM_DELMADDR: return "RTM_DELMADDR";
1119 #endif
1120     case RTM_MISS: return "RTM_MISS";
1121     case RTM_REDIRECT: return "RTM_REDIRECT";
1122     case RTM_LOSING: return "RTM_LOSING";
1123     case RTM_GET: return "RTM_GET";
1124     default: return "?";
1125     }
1126 }
1127
1128 static void
1129 do_network_reconfig(verto_ctx *ctx, verto_ev *ev)
1130 {
1131     struct connection *conn = verto_get_private(ev);
1132     assert(loop_setup_network(ctx, conn->handle, conn->prog) == 0);
1133 }
1134
1135 static int
1136 routing_update_needed(struct rt_msghdr *rtm)
1137 {
1138     switch (rtm->rtm_type) {
1139     case RTM_ADD:
1140     case RTM_DELETE:
1141     case RTM_NEWADDR:
1142     case RTM_DELADDR:
1143     case RTM_IFINFO:
1144     case RTM_OLDADD:
1145     case RTM_OLDDEL:
1146         /*
1147          * Some flags indicate routing table updates that don't
1148          * indicate local address changes.  They may come from
1149          * redirects, or ARP, etc.
1150          *
1151          * This set of symbols is just an initial guess based on
1152          * some messages observed in real life; working out which
1153          * other flags also indicate messages we should ignore,
1154          * and which flags are portable to all system and thus
1155          * don't need to be conditionalized, is left as a future
1156          * exercise.
1157          */
1158 #ifdef RTF_DYNAMIC
1159         if (rtm->rtm_flags & RTF_DYNAMIC)
1160             break;
1161 #endif
1162 #ifdef RTF_CLONED
1163         if (rtm->rtm_flags & RTF_CLONED)
1164             break;
1165 #endif
1166 #ifdef RTF_LLINFO
1167         if (rtm->rtm_flags & RTF_LLINFO)
1168             break;
1169 #endif
1170 #if 0
1171         krb5_klog_syslog(LOG_DEBUG,
1172                          "network reconfiguration message (%s) received",
1173                          rtm_type_name(rtm->rtm_type));
1174 #endif
1175         return 1;
1176     case RTM_RESOLVE:
1177 #ifdef RTM_NEWMADDR
1178     case RTM_NEWMADDR:
1179     case RTM_DELMADDR:
1180 #endif
1181     case RTM_MISS:
1182     case RTM_REDIRECT:
1183     case RTM_LOSING:
1184     case RTM_GET:
1185         /* Not interesting.  */
1186 #if 0
1187         krb5_klog_syslog(LOG_DEBUG, "routing msg not interesting");
1188 #endif
1189         break;
1190     default:
1191         krb5_klog_syslog(LOG_INFO,
1192                          _("unhandled routing message type %d, "
1193                            "will reconfigure just for the fun of it"),
1194                          rtm->rtm_type);
1195         return 1;
1196     }
1197
1198     return 0;
1199 }
1200
1201 static void
1202 process_routing_update(verto_ctx *ctx, verto_ev *ev)
1203 {
1204     int n_read, fd;
1205     struct rt_msghdr rtm;
1206     struct connection *conn;
1207
1208     fd = verto_get_fd(ev);
1209     conn = verto_get_private(ev);
1210     while ((n_read = read(fd, &rtm, sizeof(rtm))) > 0) {
1211         if (n_read < sizeof(rtm)) {
1212             /* Quick hack to figure out if the interesting
1213                fields are present in a short read.
1214
1215                A short read seems to be normal for some message types.
1216                Only complain if we don't have the critical initial
1217                header fields.  */
1218 #define RS(FIELD) (offsetof(struct rt_msghdr, FIELD) + sizeof(rtm.FIELD))
1219             if (n_read < RS(rtm_type) ||
1220                 n_read < RS(rtm_version) ||
1221                 n_read < RS(rtm_msglen)) {
1222                 krb5_klog_syslog(LOG_ERR,
1223                                  _("short read (%d/%d) from routing socket"),
1224                                  n_read, (int) sizeof(rtm));
1225                 return;
1226             }
1227         }
1228 #if 0
1229         krb5_klog_syslog(LOG_INFO,
1230                          _("got routing msg type %d(%s) v%d"),
1231                          rtm.rtm_type, rtm_type_name(rtm.rtm_type),
1232                          rtm.rtm_version);
1233 #endif
1234         if (rtm.rtm_msglen > sizeof(rtm)) {
1235             /* It appears we get a partial message and the rest is
1236                thrown away?  */
1237         } else if (rtm.rtm_msglen != n_read) {
1238             krb5_klog_syslog(LOG_ERR,
1239                              _("read %d from routing socket but msglen is %d"),
1240                              n_read, rtm.rtm_msglen);
1241         }
1242
1243         if (routing_update_needed(&rtm)) {
1244             /* Ideally we would use idle here instead of timeout. However, idle
1245              * is not universally supported yet in all backends. So let's just
1246              * use timeout for now to avoid locking into a loop. */
1247             ev = verto_add_timeout(ctx, VERTO_EV_FLAG_NONE,
1248                                    do_network_reconfig, 0);
1249             verto_set_private(ev, conn, NULL);
1250             assert(ev);
1251         }
1252     }
1253 }
1254 #endif
1255
1256 krb5_error_code
1257 loop_setup_routing_socket(verto_ctx *ctx, void *handle, const char *progname)
1258 {
1259 #ifdef HAVE_STRUCT_RT_MSGHDR
1260     struct socksetup data;
1261     int sock;
1262
1263     data.ctx = ctx;
1264     data.handle = handle;
1265     data.prog = progname;
1266     data.retval = 0;
1267
1268     sock = socket(PF_ROUTE, SOCK_RAW, 0);
1269     if (sock < 0) {
1270         int e = errno;
1271         krb5_klog_syslog(LOG_INFO, _("couldn't set up routing socket: %s"),
1272                          strerror(e));
1273     } else {
1274         krb5_klog_syslog(LOG_INFO, _("routing socket is fd %d"), sock);
1275         setnbio(sock);
1276         add_fd(&data, sock, CONN_ROUTING,
1277                VERTO_EV_FLAG_IO_READ | VERTO_EV_FLAG_PERSIST,
1278                process_routing_update, 0);
1279     }
1280 #endif
1281     return 0;
1282 }
1283
1284 /* XXX */
1285 extern void (*krb5int_sendtokdc_debug_handler)(const void*, size_t);
1286
1287 krb5_error_code
1288 loop_setup_network(verto_ctx *ctx, void *handle, const char *prog)
1289 {
1290     struct socksetup setup_data;
1291     verto_ev *ev;
1292     int i;
1293
1294     krb5int_sendtokdc_debug_handler = klog_handler;
1295
1296     /* Close any open connections. */
1297     FOREACH_ELT(events, i, ev)
1298         verto_del(ev);
1299     events.n = 0;
1300
1301     setup_data.ctx = ctx;
1302     setup_data.handle = handle;
1303     setup_data.prog = prog;
1304     setup_data.retval = 0;
1305     krb5_klog_syslog(LOG_INFO, _("setting up network..."));
1306
1307     /*
1308      * To do: Use RFC 2292 interface (or follow-on) and IPV6_PKTINFO,
1309      * so we might need only one UDP socket; fall back to binding
1310      * sockets on each address only if IPV6_PKTINFO isn't
1311      * supported.
1312      */
1313     setup_data.udp_flags = UDP_DO_IPV4 | UDP_DO_IPV6;
1314     setup_udp_pktinfo_ports(&setup_data);
1315     if (setup_data.udp_flags) {
1316         if (foreach_localaddr (&setup_data, setup_udp_port, 0, 0)) {
1317             return setup_data.retval;
1318         }
1319     }
1320     setup_tcp_listener_ports(&setup_data);
1321     setup_rpc_listener_ports(&setup_data);
1322     krb5_klog_syslog (LOG_INFO, _("set up %d sockets"), (int) events.n);
1323     if (events.n == 0) {
1324         com_err(prog, 0, _("no sockets set up?"));
1325         exit (1);
1326     }
1327
1328     return 0;
1329 }
1330
1331 void
1332 init_addr(krb5_fulladdr *faddr, struct sockaddr *sa)
1333 {
1334     switch (sa->sa_family) {
1335     case AF_INET:
1336         faddr->address->addrtype = ADDRTYPE_INET;
1337         faddr->address->length = 4;
1338         faddr->address->contents = (krb5_octet *) &sa2sin(sa)->sin_addr;
1339         faddr->port = ntohs(sa2sin(sa)->sin_port);
1340         break;
1341 #ifdef KRB5_USE_INET6
1342     case AF_INET6:
1343         if (IN6_IS_ADDR_V4MAPPED(&sa2sin6(sa)->sin6_addr)) {
1344             faddr->address->addrtype = ADDRTYPE_INET;
1345             faddr->address->length = 4;
1346             faddr->address->contents = 12 + (krb5_octet *) &sa2sin6(sa)->sin6_addr;
1347         } else {
1348             faddr->address->addrtype = ADDRTYPE_INET6;
1349             faddr->address->length = 16;
1350             faddr->address->contents = (krb5_octet *) &sa2sin6(sa)->sin6_addr;
1351         }
1352         faddr->port = ntohs(sa2sin6(sa)->sin6_port);
1353         break;
1354 #endif
1355     default:
1356         faddr->address->addrtype = -1;
1357         faddr->address->length = 0;
1358         faddr->address->contents = 0;
1359         faddr->port = 0;
1360         break;
1361     }
1362 }
1363
1364 /*
1365  * This holds whatever additional information might be needed to
1366  * properly send back to the client from the correct local address.
1367  *
1368  * In this case, we only need one datum so far: On Mac OS X, the
1369  * kernel doesn't seem to like sending from link-local addresses
1370  * unless we specify the correct interface.
1371  */
1372
1373 union aux_addressing_info {
1374     int ipv6_ifindex;
1375 };
1376
1377 static int
1378 recv_from_to(int s, void *buf, size_t len, int flags,
1379              struct sockaddr *from, socklen_t *fromlen,
1380              struct sockaddr *to, socklen_t *tolen,
1381              union aux_addressing_info *auxaddr)
1382 {
1383 #if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE)
1384     if (to && tolen) {
1385         /* Clobber with something recognizeable in case we try to use
1386            the address.  */
1387         memset(to, 0x40, *tolen);
1388         *tolen = 0;
1389     }
1390
1391     return recvfrom(s, buf, len, flags, from, fromlen);
1392 #else
1393     int r;
1394     struct iovec iov;
1395     char cmsg[CMSG_SPACE(sizeof(union pktinfo))];
1396     struct cmsghdr *cmsgptr;
1397     struct msghdr msg;
1398
1399     if (!to || !tolen)
1400         return recvfrom(s, buf, len, flags, from, fromlen);
1401
1402     /* Clobber with something recognizeable in case we can't extract
1403        the address but try to use it anyways.  */
1404     memset(to, 0x40, *tolen);
1405
1406     iov.iov_base = buf;
1407     iov.iov_len = len;
1408     memset(&msg, 0, sizeof(msg));
1409     msg.msg_name = from;
1410     msg.msg_namelen = *fromlen;
1411     msg.msg_iov = &iov;
1412     msg.msg_iovlen = 1;
1413     msg.msg_control = cmsg;
1414     msg.msg_controllen = sizeof(cmsg);
1415
1416     r = recvmsg(s, &msg, flags);
1417     if (r < 0)
1418         return r;
1419     *fromlen = msg.msg_namelen;
1420
1421     /* On Darwin (and presumably all *BSD with KAME stacks),
1422        CMSG_FIRSTHDR doesn't check for a non-zero controllen.  RFC
1423        3542 recommends making this check, even though the (new) spec
1424        for CMSG_FIRSTHDR says it's supposed to do the check.  */
1425     if (msg.msg_controllen) {
1426         cmsgptr = CMSG_FIRSTHDR(&msg);
1427         while (cmsgptr) {
1428 #ifdef IP_PKTINFO
1429             if (cmsgptr->cmsg_level == IPPROTO_IP
1430                 && cmsgptr->cmsg_type == IP_PKTINFO
1431                 && *tolen >= sizeof(struct sockaddr_in)) {
1432                 struct in_pktinfo *pktinfo;
1433                 memset(to, 0, sizeof(struct sockaddr_in));
1434                 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
1435                 ((struct sockaddr_in *)to)->sin_addr = pktinfo->ipi_addr;
1436                 ((struct sockaddr_in *)to)->sin_family = AF_INET;
1437                 *tolen = sizeof(struct sockaddr_in);
1438                 return r;
1439             }
1440 #endif
1441 #if defined(KRB5_USE_INET6) && defined(IPV6_PKTINFO) && \
1442     defined(HAVE_STRUCT_IN6_PKTINFO)
1443             if (cmsgptr->cmsg_level == IPPROTO_IPV6
1444                 && cmsgptr->cmsg_type == IPV6_PKTINFO
1445                 && *tolen >= sizeof(struct sockaddr_in6)) {
1446                 struct in6_pktinfo *pktinfo;
1447                 memset(to, 0, sizeof(struct sockaddr_in6));
1448                 pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
1449                 ((struct sockaddr_in6 *)to)->sin6_addr = pktinfo->ipi6_addr;
1450                 ((struct sockaddr_in6 *)to)->sin6_family = AF_INET6;
1451                 *tolen = sizeof(struct sockaddr_in6);
1452                 auxaddr->ipv6_ifindex = pktinfo->ipi6_ifindex;
1453                 return r;
1454             }
1455 #endif
1456             cmsgptr = CMSG_NXTHDR(&msg, cmsgptr);
1457         }
1458     }
1459     /* No info about destination addr was available.  */
1460     *tolen = 0;
1461     return r;
1462 #endif
1463 }
1464
1465 static int
1466 send_to_from(int s, void *buf, size_t len, int flags,
1467              const struct sockaddr *to, socklen_t tolen,
1468              const struct sockaddr *from, socklen_t fromlen,
1469              union aux_addressing_info *auxaddr)
1470 {
1471 #if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE)
1472     return sendto(s, buf, len, flags, to, tolen);
1473 #else
1474     struct iovec iov;
1475     struct msghdr msg;
1476     struct cmsghdr *cmsgptr;
1477     char cbuf[CMSG_SPACE(sizeof(union pktinfo))];
1478
1479     if (from == 0 || fromlen == 0 || from->sa_family != to->sa_family) {
1480     use_sendto:
1481         return sendto(s, buf, len, flags, to, tolen);
1482     }
1483
1484     iov.iov_base = buf;
1485     iov.iov_len = len;
1486     /* Truncation?  */
1487     if (iov.iov_len != len)
1488         return EINVAL;
1489     memset(cbuf, 0, sizeof(cbuf));
1490     memset(&msg, 0, sizeof(msg));
1491     msg.msg_name = (void *) to;
1492     msg.msg_namelen = tolen;
1493     msg.msg_iov = &iov;
1494     msg.msg_iovlen = 1;
1495     msg.msg_control = cbuf;
1496     /* CMSG_FIRSTHDR needs a non-zero controllen, or it'll return NULL
1497        on Linux.  */
1498     msg.msg_controllen = sizeof(cbuf);
1499     cmsgptr = CMSG_FIRSTHDR(&msg);
1500     msg.msg_controllen = 0;
1501
1502     switch (from->sa_family) {
1503 #if defined(IP_PKTINFO)
1504     case AF_INET:
1505         if (fromlen != sizeof(struct sockaddr_in))
1506             goto use_sendto;
1507         cmsgptr->cmsg_level = IPPROTO_IP;
1508         cmsgptr->cmsg_type = IP_PKTINFO;
1509         cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
1510         {
1511             struct in_pktinfo *p = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
1512             const struct sockaddr_in *from4 = (const struct sockaddr_in *)from;
1513             p->ipi_spec_dst = from4->sin_addr;
1514         }
1515         msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
1516         break;
1517 #endif
1518 #if defined(KRB5_USE_INET6) && defined(IPV6_PKTINFO) && \
1519     defined(HAVE_STRUCT_IN6_PKTINFO)
1520     case AF_INET6:
1521         if (fromlen != sizeof(struct sockaddr_in6))
1522             goto use_sendto;
1523         cmsgptr->cmsg_level = IPPROTO_IPV6;
1524         cmsgptr->cmsg_type = IPV6_PKTINFO;
1525         cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1526         {
1527             struct in6_pktinfo *p = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
1528             const struct sockaddr_in6 *from6 =
1529                 (const struct sockaddr_in6 *)from;
1530             p->ipi6_addr = from6->sin6_addr;
1531             /*
1532              * Because of the possibility of asymmetric routing, we
1533              * normally don't want to specify an interface.  However,
1534              * Mac OS X doesn't like sending from a link-local address
1535              * (which can come up in testing at least, if you wind up
1536              * with a "foo.local" name) unless we do specify the
1537              * interface.
1538              */
1539             if (IN6_IS_ADDR_LINKLOCAL(&from6->sin6_addr))
1540                 p->ipi6_ifindex = auxaddr->ipv6_ifindex;
1541             /* otherwise, already zero */
1542         }
1543         msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1544         break;
1545 #endif
1546     default:
1547         goto use_sendto;
1548     }
1549     return sendmsg(s, &msg, flags);
1550 #endif
1551 }
1552
1553 static void
1554 process_packet(verto_ctx *ctx, verto_ev *ev)
1555 {
1556     int cc;
1557     socklen_t saddr_len, daddr_len;
1558     krb5_fulladdr faddr;
1559     krb5_error_code retval;
1560     struct sockaddr_storage saddr, daddr;
1561     krb5_address addr;
1562     krb5_data request;
1563     krb5_data *response;
1564     char pktbuf[MAX_DGRAM_SIZE];
1565     int port_fd;
1566     union aux_addressing_info auxaddr;
1567     struct connection *conn;
1568
1569     port_fd = verto_get_fd(ev);
1570     conn = verto_get_private(ev);
1571     assert(port_fd >= 0);
1572
1573     response = NULL;
1574     saddr_len = sizeof(saddr);
1575     daddr_len = sizeof(daddr);
1576     memset(&auxaddr, 0, sizeof(auxaddr));
1577     cc = recv_from_to(port_fd, pktbuf, sizeof(pktbuf), 0,
1578                       (struct sockaddr *)&saddr, &saddr_len,
1579                       (struct sockaddr *)&daddr, &daddr_len,
1580                       &auxaddr);
1581     if (cc == -1) {
1582         if (errno != EINTR && errno != EAGAIN
1583             /*
1584              * This is how Linux indicates that a previous transmission was
1585              * refused, e.g., if the client timed out before getting the
1586              * response packet.
1587              */
1588             && errno != ECONNREFUSED
1589         )
1590             com_err(conn->prog, errno, _("while receiving from network"));
1591         return;
1592     }
1593     if (!cc)
1594         return;         /* zero-length packet? */
1595
1596 #if 0
1597     if (daddr_len > 0) {
1598         char addrbuf[100];
1599         if (getnameinfo(ss2sa(&daddr), daddr_len, addrbuf, sizeof(addrbuf),
1600                         0, 0, NI_NUMERICHOST))
1601             strlcpy(addrbuf, "?", sizeof(addrbuf));
1602         com_err(conn->prog, 0, _("pktinfo says local addr is %s"), addrbuf);
1603     }
1604 #endif
1605
1606     if (daddr_len == 0 && conn->type == CONN_UDP) {
1607         /*
1608          * If the PKTINFO option isn't set, this socket should be bound to a
1609          * specific local address.  This info probably should've been saved in
1610          * our socket data structure at setup time.
1611          */
1612         daddr_len = sizeof(daddr);
1613         if (getsockname(port_fd, (struct sockaddr *)&daddr, &daddr_len) != 0)
1614             daddr_len = 0;
1615         /* On failure, keep going anyways. */
1616     }
1617
1618     request.length = cc;
1619     request.data = pktbuf;
1620     faddr.address = &addr;
1621     init_addr(&faddr, ss2sa(&saddr));
1622     /* This address is in net order. */
1623     retval = dispatch(conn->handle, ss2sa(&daddr),
1624                       &faddr, &request, &response, 0);
1625     if (retval) {
1626         com_err(conn->prog, retval, _("while dispatching (udp)"));
1627         return;
1628     }
1629     if (response == NULL)
1630         return;
1631     cc = send_to_from(port_fd, response->data, (socklen_t) response->length, 0,
1632                       (struct sockaddr *)&saddr, saddr_len,
1633                       (struct sockaddr *)&daddr, daddr_len,
1634                       &auxaddr);
1635     if (cc == -1) {
1636         /* Note that the local address (daddr*) has no port number
1637          * info associated with it. */
1638         char saddrbuf[NI_MAXHOST], sportbuf[NI_MAXSERV];
1639         char daddrbuf[NI_MAXHOST];
1640         int e = errno;
1641         krb5_free_data(get_context(conn->handle), response);
1642         if (getnameinfo((struct sockaddr *)&daddr, daddr_len,
1643                         daddrbuf, sizeof(daddrbuf), 0, 0,
1644                         NI_NUMERICHOST) != 0) {
1645             strlcpy(daddrbuf, "?", sizeof(daddrbuf));
1646         }
1647         if (getnameinfo((struct sockaddr *)&saddr, saddr_len,
1648                         saddrbuf, sizeof(saddrbuf), sportbuf, sizeof(sportbuf),
1649                         NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
1650             strlcpy(saddrbuf, "?", sizeof(saddrbuf));
1651             strlcpy(sportbuf, "?", sizeof(sportbuf));
1652         }
1653         com_err(conn->prog, e, _("while sending reply to %s/%s from %s"),
1654                 saddrbuf, sportbuf, daddrbuf);
1655         return;
1656     }
1657     if ((size_t)cc != response->length) {
1658         com_err(conn->prog, 0, _("short reply write %d vs %d\n"),
1659                 response->length, cc);
1660     }
1661     krb5_free_data(get_context(conn->handle), response);
1662     return;
1663 }
1664
1665 static int
1666 kill_lru_tcp_or_rpc_connection(void *handle, verto_ev *newev)
1667 {
1668     struct connection *c = NULL, *oldest_c = NULL;
1669     verto_ev *ev, *oldest_ev = NULL;
1670     int i, fd = -1;
1671
1672     krb5_klog_syslog(LOG_INFO, _("too many connections"));
1673
1674     FOREACH_ELT (events, i, ev) {
1675         if (ev == newev)
1676             continue;
1677
1678         c = verto_get_private(ev);
1679         if (!c)
1680             continue;
1681         if (c->type != CONN_TCP && c->type != CONN_RPC)
1682             continue;
1683 #if 0
1684         krb5_klog_syslog(LOG_INFO, "fd %d started at %ld",
1685                          verto_get_fd(oldest_ev),
1686                          c->start_time);
1687 #endif
1688         if (oldest_c == NULL
1689             || oldest_c->start_time > c->start_time) {
1690             oldest_ev = ev;
1691             oldest_c = c;
1692         }
1693     }
1694     if (oldest_c != NULL) {
1695         krb5_klog_syslog(LOG_INFO, _("dropping %s fd %d from %s"),
1696                          c->type == CONN_RPC ? "rpc" : "tcp",
1697                          verto_get_fd(oldest_ev), oldest_c->addrbuf);
1698         if (oldest_c->type == CONN_RPC)
1699             oldest_c->rpc_force_close = 1;
1700         verto_del(oldest_ev);
1701     }
1702     return fd;
1703 }
1704
1705 static void
1706 accept_tcp_connection(verto_ctx *ctx, verto_ev *ev)
1707 {
1708     int s;
1709     struct sockaddr_storage addr_s;
1710     struct sockaddr *addr = (struct sockaddr *)&addr_s;
1711     socklen_t addrlen = sizeof(addr_s);
1712     struct socksetup sockdata;
1713     struct connection *newconn, *conn;
1714     char tmpbuf[10];
1715     verto_ev *newev;
1716
1717     conn = verto_get_private(ev);
1718     s = accept(verto_get_fd(ev), addr, &addrlen);
1719     if (s < 0)
1720         return;
1721     set_cloexec_fd(s);
1722 #ifndef _WIN32
1723     if (s >= FD_SETSIZE) {
1724         close(s);
1725         return;
1726     }
1727 #endif
1728     setnbio(s), setnolinger(s), setkeepalive(s);
1729
1730     sockdata.ctx = ctx;
1731     sockdata.handle = conn->handle;
1732     sockdata.prog = conn->prog;
1733     sockdata.retval = 0;
1734
1735     newev = add_tcp_read_fd(&sockdata, s);
1736     if (newev == NULL) {
1737         close(s);
1738         return;
1739     }
1740     newconn = verto_get_private(newev);
1741
1742     if (getnameinfo((struct sockaddr *)&addr_s, addrlen,
1743                     newconn->addrbuf, sizeof(newconn->addrbuf),
1744                     tmpbuf, sizeof(tmpbuf),
1745                     NI_NUMERICHOST | NI_NUMERICSERV))
1746         strlcpy(newconn->addrbuf, "???", sizeof(newconn->addrbuf));
1747     else {
1748         char *p, *end;
1749         p = newconn->addrbuf;
1750         end = p + sizeof(newconn->addrbuf);
1751         p += strlen(p);
1752         if ((size_t)(end - p) > 2 + strlen(tmpbuf)) {
1753             *p++ = '.';
1754             strlcpy(p, tmpbuf, end - p);
1755         }
1756     }
1757 #if 0
1758     krb5_klog_syslog(LOG_INFO, "accepted TCP connection on socket %d from %s",
1759                      s, newconn->addrbuf);
1760 #endif
1761
1762     newconn->addr_s = addr_s;
1763     newconn->addrlen = addrlen;
1764     newconn->bufsiz = 1024 * 1024;
1765     newconn->buffer = malloc(newconn->bufsiz);
1766     newconn->start_time = time(0);
1767
1768     if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
1769         kill_lru_tcp_or_rpc_connection(conn->handle, newev);
1770
1771     if (newconn->buffer == 0) {
1772         com_err(conn->prog, errno,
1773                 _("allocating buffer for new TCP session from %s"),
1774                 newconn->addrbuf);
1775         verto_del(newev);
1776         return;
1777     }
1778     newconn->offset = 0;
1779     newconn->faddr.address = &newconn->kaddr;
1780     init_addr(&newconn->faddr, ss2sa(&newconn->addr_s));
1781     SG_SET(&newconn->sgbuf[0], newconn->lenbuf, 4);
1782     SG_SET(&newconn->sgbuf[1], 0, 0);
1783 }
1784
1785 static void
1786 process_tcp_connection_read(verto_ctx *ctx, verto_ev *ev)
1787 {
1788     struct connection *conn;
1789     ssize_t nread;
1790     size_t len;
1791     int sock;
1792
1793     conn = verto_get_private(ev);
1794     sock = verto_get_fd(ev);
1795
1796     /*
1797      * Read message length and data into one big buffer, already allocated
1798      * at connect time.  If we have a complete message, we stop reading, so
1799      * we should only be here if there is no data in the buffer, or only an
1800      * incomplete message.
1801      */
1802     if (conn->offset < 4) {
1803         /* msglen has not been computed.  XXX Doing at least two reads
1804          * here, letting the kernel worry about buffering. */
1805         len = 4 - conn->offset;
1806         nread = SOCKET_READ(sock,
1807                             conn->buffer + conn->offset, len);
1808         if (nread < 0) /* error */
1809             goto kill_tcp_connection;
1810         if (nread == 0) /* eof */
1811             goto kill_tcp_connection;
1812         conn->offset += nread;
1813         if (conn->offset == 4) {
1814             unsigned char *p = (unsigned char *)conn->buffer;
1815             conn->msglen = load_32_be(p);
1816             if (conn->msglen > conn->bufsiz - 4) {
1817                 krb5_error_code err;
1818                 /* Message too big. */
1819                 krb5_klog_syslog(LOG_ERR, _("TCP client %s wants %lu bytes, "
1820                                  "cap is %lu"), conn->addrbuf,
1821                                  (unsigned long) conn->msglen,
1822                                  (unsigned long) conn->bufsiz - 4);
1823                 /* XXX Should return an error.  */
1824                 err = make_toolong_error (conn->handle,
1825                                           &conn->response);
1826                 if (err) {
1827                     krb5_klog_syslog(LOG_ERR, _("error constructing "
1828                                      "KRB_ERR_FIELD_TOOLONG error! %s"),
1829                                      error_message(err));
1830                     goto kill_tcp_connection;
1831                 }
1832                 goto have_response;
1833             }
1834         }
1835     } else {
1836         /* msglen known. */
1837         krb5_data request;
1838         krb5_error_code err;
1839         struct sockaddr_storage local_saddr;
1840         socklen_t local_saddrlen = sizeof(local_saddr);
1841         struct sockaddr *local_saddrp = NULL;
1842
1843         len = conn->msglen - (conn->offset - 4);
1844         nread = SOCKET_READ(sock,
1845                             conn->buffer + conn->offset, len);
1846         if (nread < 0) /* error */
1847             goto kill_tcp_connection;
1848         if (nread == 0) /* eof */
1849             goto kill_tcp_connection;
1850         conn->offset += nread;
1851         if (conn->offset < conn->msglen + 4)
1852             return;
1853         /* Have a complete message, and exactly one message. */
1854         request.length = conn->msglen;
1855         request.data = conn->buffer + 4;
1856
1857         if (getsockname(sock, ss2sa(&local_saddr),
1858                         &local_saddrlen) == 0)
1859             local_saddrp = ss2sa(&local_saddr);
1860
1861         err = dispatch(conn->handle, local_saddrp, &conn->faddr,
1862                        &request, &conn->response, 1);
1863         if (err) {
1864             com_err(conn->prog, err, _("while dispatching (tcp)"));
1865             goto kill_tcp_connection;
1866         }
1867         if (conn->response == NULL)
1868             goto kill_tcp_connection;
1869     have_response:
1870         /* Queue outgoing response. */
1871         store_32_be(conn->response->length, conn->lenbuf);
1872         SG_SET(&conn->sgbuf[1], conn->response->data,
1873                conn->response->length);
1874         conn->sgp = conn->sgbuf;
1875         conn->sgnum = 2;
1876
1877         if (convert_event(ctx, ev,
1878                           VERTO_EV_FLAG_IO_WRITE | VERTO_EV_FLAG_PERSIST,
1879                           process_tcp_connection_write))
1880             return;
1881     }
1882
1883     return;
1884
1885 kill_tcp_connection:
1886     verto_del(ev);
1887 }
1888
1889 static void
1890 process_tcp_connection_write(verto_ctx *ctx, verto_ev *ev)
1891 {
1892     struct connection *conn;
1893     SOCKET_WRITEV_TEMP tmp;
1894     ssize_t nwrote;
1895     int sock;
1896
1897     conn = verto_get_private(ev);
1898     sock = verto_get_fd(ev);
1899
1900     nwrote = SOCKET_WRITEV(sock, conn->sgp,
1901                            conn->sgnum, tmp);
1902     if (nwrote > 0) { /* non-error and non-eof */
1903         while (nwrote) {
1904             sg_buf *sgp = conn->sgp;
1905             if ((size_t)nwrote < SG_LEN(sgp)) {
1906                 SG_ADVANCE(sgp, (size_t)nwrote);
1907                 nwrote = 0;
1908             } else {
1909                 nwrote -= SG_LEN(sgp);
1910                 conn->sgp++;
1911                 conn->sgnum--;
1912                 if (conn->sgnum == 0 && nwrote != 0)
1913                     abort();
1914             }
1915         }
1916
1917         /* If we still have more data to send, just return so that
1918          * the main loop can call this function again when the socket
1919          * is ready for more writing. */
1920         if (conn->sgnum > 0)
1921             return;
1922     }
1923
1924     /* Finished sending.  We should go back to reading, though if we
1925      * sent a FIELD_TOOLONG error in reply to a length with the high
1926      * bit set, RFC 4120 says we have to close the TCP stream. */
1927     verto_del(ev);
1928 }
1929
1930 void
1931 loop_free(verto_ctx *ctx)
1932 {
1933     verto_free(ctx);
1934     FREE_SET_DATA(events);
1935     FREE_SET_DATA(udp_port_data);
1936     FREE_SET_DATA(tcp_port_data);
1937     FREE_SET_DATA(rpc_svc_data);
1938 }
1939
1940 static int
1941 have_event_for_fd(int fd)
1942 {
1943     verto_ev *ev;
1944     int i;
1945
1946     FOREACH_ELT(events, i, ev) {
1947         if (verto_get_fd(ev) == fd)
1948             return 1;
1949     }
1950
1951     return 0;
1952 }
1953
1954 static void
1955 accept_rpc_connection(verto_ctx *ctx, verto_ev *ev)
1956 {
1957     struct socksetup sockdata;
1958     struct connection *conn;
1959     fd_set fds;
1960     register int s;
1961
1962     conn = verto_get_private(ev);
1963
1964     sockdata.ctx = ctx;
1965     sockdata.handle = conn->handle;
1966     sockdata.prog = conn->prog;
1967     sockdata.retval = 0;
1968
1969     /* Service the woken RPC listener descriptor. */
1970     FD_ZERO(&fds);
1971     FD_SET(verto_get_fd(ev), &fds);
1972     svc_getreqset(&fds);
1973
1974     /* Scan svc_fdset for any new connections. */
1975     for (s = 0; s < FD_SETSIZE; s++) {
1976         struct sockaddr_storage addr_s;
1977         struct sockaddr *addr = (struct sockaddr *) &addr_s;
1978         socklen_t addrlen = sizeof(addr_s);
1979         struct connection *newconn;
1980         char tmpbuf[10];
1981         verto_ev *newev;
1982
1983         /* If we already have this fd, continue. */
1984         if (!FD_ISSET(s, &svc_fdset) || have_event_for_fd(s))
1985             continue;
1986
1987         newev = add_rpc_data_fd(&sockdata, s);
1988         if (newev == NULL)
1989             continue;
1990         newconn = verto_get_private(newev);
1991
1992         set_cloexec_fd(s);
1993 #if 0
1994         setnbio(s), setnolinger(s), setkeepalive(s);
1995 #endif
1996
1997         if (getpeername(s, addr, &addrlen) ||
1998             getnameinfo(addr, addrlen,
1999                         newconn->addrbuf,
2000                         sizeof(newconn->addrbuf),
2001                         tmpbuf, sizeof(tmpbuf),
2002                         NI_NUMERICHOST | NI_NUMERICSERV)) {
2003             strlcpy(newconn->addrbuf, "???",
2004                     sizeof(newconn->addrbuf));
2005         } else {
2006             char *p, *end;
2007             p = newconn->addrbuf;
2008             end = p + sizeof(newconn->addrbuf);
2009             p += strlen(p);
2010             if ((size_t)(end - p) > 2 + strlen(tmpbuf)) {
2011                 *p++ = '.';
2012                 strlcpy(p, tmpbuf, end - p);
2013             }
2014         }
2015 #if 0
2016         krb5_klog_syslog(LOG_INFO, _("accepted RPC connection on socket %d "
2017                          "from %s"), s, newconn->addrbuf);
2018 #endif
2019
2020         newconn->addr_s = addr_s;
2021         newconn->addrlen = addrlen;
2022         newconn->start_time = time(0);
2023
2024         if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
2025             kill_lru_tcp_or_rpc_connection(newconn->handle, newev);
2026
2027         newconn->faddr.address = &newconn->kaddr;
2028         init_addr(&newconn->faddr, ss2sa(&newconn->addr_s));
2029     }
2030 }
2031
2032 static void
2033 process_rpc_connection(verto_ctx *ctx, verto_ev *ev)
2034 {
2035     fd_set fds;
2036
2037     FD_ZERO(&fds);
2038     FD_SET(verto_get_fd(ev), &fds);
2039     svc_getreqset(&fds);
2040
2041     if (!FD_ISSET(verto_get_fd(ev), &svc_fdset))
2042         verto_del(ev);
2043 }
2044
2045 #endif /* INET */