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