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