1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/apputils/net-server.c - Network code for krb5 servers (kdc, kadmind) */
4 * Copyright 1990,2000,2007,2008,2009,2010 by the Massachusetts Institute of Technology.
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.
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.
27 #include "adm_proto.h"
28 #include <sys/ioctl.h>
32 #include "port-sockets.h"
33 #include "socket-utils.h"
35 #include <gssrpc/rpc.h>
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>
47 #include <sys/select.h>
49 #include <arpa/inet.h>
51 #ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */
55 #ifdef HAVE_SYS_FILIO_H
56 #include <sys/filio.h> /* FIONBIO */
59 #include "fake-addrinfo.h"
60 #include "net-server.h"
63 #define KDC5_NONET (-1779992062L)
65 volatile int signal_requests_exit = 0, signal_requests_reset = 0;
67 static void closedown_network_sockets(void);
69 /* Misc utility routines. */
71 set_sa_port(struct sockaddr *addr, int port)
73 switch (addr->sa_family) {
75 sa2sin(addr)->sin_port = port;
79 sa2sin6(addr)->sin6_port = port;
91 static int result = -1;
94 s = socket(AF_INET6, SOCK_STREAM, 0);
108 setreuseaddr(int sock, int value)
110 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
113 #if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
115 setv6only(int sock, int value)
117 return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
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
126 /* Parallel, though not standardized. */
127 #ifndef IP_RECVPKTINFO
128 #define IP_RECVPKTINFO IP_PKTINFO
132 set_pktinfo(int sock, int family)
135 int option = 0, proto = 0;
138 #if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO)
141 option = IP_RECVPKTINFO;
144 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
146 proto = IPPROTO_IPV6;
147 option = IPV6_RECVPKTINFO;
153 if (setsockopt(sock, proto, option, &sockopt, sizeof(sockopt)))
160 paddr(struct sockaddr *sa)
162 static char buf[100];
164 if (getnameinfo(sa, socklen(sa),
165 buf, sizeof(buf), portbuf, sizeof(portbuf),
166 NI_NUMERICHOST|NI_NUMERICSERV))
167 strlcpy(buf, "<unprintable>", sizeof(buf));
169 unsigned int len = sizeof(buf) - strlen(buf);
170 char *p = buf + strlen(buf);
171 if (len > 2+strlen(portbuf)) {
174 strncpy(p, portbuf, len);
183 CONN_UDP, CONN_UDP_PKTINFO, CONN_TCP_LISTENER, CONN_TCP,
184 CONN_RPC_LISTENER, CONN_RPC,
188 /* Per-connection info. */
192 void (*service)(void *handle, struct connection *, const char *, int);
194 /* Type-specific information. */
197 struct sockaddr_storage addr_s;
209 unsigned char lenbuf[4];
213 /* crude denial-of-service avoidance support */
223 #define SET(TYPE) struct { TYPE *data; size_t n, max; }
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--)
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)) \
236 : ((tmpptr = realloc(set.data, \
237 (set.max + incr) * sizeof(set.data[0]))) \
238 ? (set.data = tmpptr, set.max += incr, 1) \
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) \
247 #define DEL(set, idx) \
248 (set.data[idx] = set.data[--set.n], 0)
250 #define FREE_SET_DATA(set) \
251 (free(set.data), set.data = 0, set.max = 0, set.n = 0)
254 /* Set<struct connection *> connections; */
255 static SET(struct connection *) connections;
256 #define n_sockets connections.n
257 #define conns connections.data
259 /* Set<u_short> udp_port_data, tcp_port_data; */
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.
265 static SET(unsigned short) udp_port_data, tcp_port_data;
267 struct rpc_svc_data {
274 static SET(struct rpc_svc_data) rpc_svc_data;
278 static struct select_state sstate;
279 static fd_set rpc_listenfds;
282 add_udp_port(int port)
287 u_short s_port = port;
292 FOREACH_ELT (udp_port_data, i, val)
295 if (!ADD(udp_port_data, s_port, tmp))
301 add_tcp_port(int port)
306 u_short s_port = port;
311 FOREACH_ELT (tcp_port_data, i, val)
314 if (!ADD(tcp_port_data, s_port, tmp))
320 add_rpc_service(int port, u_long prognum, u_long versnum, void (*dispatchfn)())
324 struct rpc_svc_data svc, val;
327 if (svc.port != port)
329 svc.prognum = prognum;
330 svc.versnum = versnum;
331 svc.dispatch = dispatchfn;
333 FOREACH_ELT (rpc_svc_data, i, val) {
334 if (val.port == port)
337 if (!ADD(rpc_svc_data, svc, tmp))
343 #define USE_AF AF_INET
344 #define USE_TYPE SOCK_DGRAM
346 #define SOCKET_ERRNO errno
347 #include "foreachaddr.h"
351 krb5_error_code retval;
353 #define UDP_DO_IPV4 1
354 #define UDP_DO_IPV6 2
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))
361 struct connection *newconn;
365 if (sock >= FD_SETSIZE) {
366 data->retval = EMFILE; /* XXX */
367 com_err(data->prog, 0,
368 "file descriptor number %d too high", sock);
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");
379 if (!ADD(connections, newconn, tmp)) {
380 data->retval = ENOMEM;
381 com_err(data->prog, ENOMEM, "cannot save socket info");
386 memset(newconn, 0, sizeof(*newconn));
387 newconn->type = conntype;
389 newconn->service = service;
393 static void process_packet(void *handle, struct connection *, const char *,
395 static void accept_tcp_connection(void *handle, struct connection *,
397 static void process_tcp_connection(void *handle, struct connection *,
399 static void accept_rpc_connection(void *handle, struct connection *,
401 static void process_rpc_connection(void *handle, struct connection *,
404 static struct connection *
405 add_udp_fd(struct socksetup *data, int sock, int pktinfo)
407 return add_fd(data, sock, pktinfo ? CONN_UDP_PKTINFO : CONN_UDP,
411 static struct connection *
412 add_tcp_listener_fd(struct socksetup *data, int sock)
414 return add_fd(data, sock, CONN_TCP_LISTENER, accept_tcp_connection);
417 static struct connection *
418 add_tcp_data_fd(struct socksetup *data, int sock)
420 return add_fd(data, sock, CONN_TCP, process_tcp_connection);
424 delete_fd(struct connection *xconn)
426 struct connection *conn;
429 FOREACH_ELT(connections, i, conn)
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.
443 create_server_socket(struct socksetup *data, struct sockaddr *addr, int type)
447 sock = socket(addr->sa_family, type, 0);
449 data->retval = errno;
450 com_err(data->prog, errno, "Cannot create TCP server socket on %s",
454 set_cloexec_fd(sock);
456 #ifndef _WIN32 /* Windows FD_SETSIZE is a count. */
457 if (sock >= FD_SETSIZE) {
459 com_err(data->prog, 0, "TCP socket fd number %d (for %s) too high",
465 if (setreuseaddr(sock, 1) < 0) {
466 com_err(data->prog, errno,
467 "Cannot enable SO_REUSEADDR on fd %d", sock);
470 #ifdef KRB5_USE_INET6
471 if (addr->sa_family == AF_INET6) {
473 if (setv6only(sock, 1))
474 com_err(data->prog, errno, "setsockopt(%d,IPV6_V6ONLY,1) failed",
477 com_err(data->prog, 0, "setsockopt(%d,IPV6_V6ONLY,1) worked",
480 krb5_klog_syslog(LOG_INFO, "no IPV6_V6ONLY socket option support");
481 #endif /* IPV6_V6ONLY */
483 #endif /* KRB5_USE_INET6 */
485 if (bind(sock, addr, socklen(addr)) == -1) {
486 data->retval = errno;
487 com_err(data->prog, errno, "Cannot bind server socket on %s",
496 static struct connection *
497 add_rpc_listener_fd(struct socksetup *data, struct rpc_svc_data *svc, int sock)
499 struct connection *conn;
501 conn = add_fd(data, sock, CONN_RPC_LISTENER, accept_rpc_connection);
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",
513 if (!svc_register(conn->u.rpc.transp, svc->prognum, svc->versnum,
515 krb5_klog_syslog(LOG_ERR, "Cannot register RPC service: %s; continuing",
524 static struct connection *
525 add_rpc_data_fd(struct socksetup *data, int sock)
527 return add_fd(data, sock, CONN_RPC, process_rpc_connection);
530 static const int one = 1;
535 return ioctlsocket(sock, FIONBIO, (const void *)&one);
539 setkeepalive(int sock)
541 return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
547 static const struct linger ling = { 0, 0 };
548 return setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
551 /* Returns -1 or socket fd. */
553 setup_a_tcp_listener(struct socksetup *data, struct sockaddr *addr)
557 sock = create_server_socket(data, addr, SOCK_STREAM);
560 if (listen(sock, 5) < 0) {
561 com_err(data->prog, errno, "Cannot listen on TCP server socket on %s",
567 com_err(data->prog, errno,
568 "cannot set listening tcp socket on %s non-blocking",
573 if (setnolinger(sock)) {
574 com_err(data->prog, errno, "disabling SO_LINGER on TCP socket on %s",
583 setup_tcp_listener_ports(struct socksetup *data)
585 struct sockaddr_in sin4;
586 #ifdef KRB5_USE_INET6
587 struct sockaddr_in6 sin6;
591 memset(&sin4, 0, sizeof(sin4));
592 sin4.sin_family = AF_INET;
594 sin4.sin_len = sizeof(sin4);
596 sin4.sin_addr.s_addr = INADDR_ANY;
598 #ifdef KRB5_USE_INET6
599 memset(&sin6, 0, sizeof(sin6));
600 sin6.sin6_family = AF_INET6;
602 sin6.sin6_len = sizeof(sin6);
604 sin6.sin6_addr = in6addr_any;
607 FOREACH_ELT (tcp_port_data, i, port) {
610 set_sa_port((struct sockaddr *)&sin4, htons(port));
611 if (!ipv6_enabled()) {
612 s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
617 #ifndef KRB5_USE_INET6
622 set_sa_port((struct sockaddr *)&sin6, htons(port));
624 s6 = setup_a_tcp_listener(data, (struct sockaddr *)&sin6);
628 s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
629 #endif /* KRB5_USE_INET6 */
632 /* Sockets are created, prepare to listen on them. */
634 if (add_tcp_listener_fd(data, s4) == NULL)
637 FD_SET(s4, &sstate.rfds);
638 if (s4 >= sstate.max)
640 krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s",
641 s4, paddr((struct sockaddr *)&sin4));
644 #ifdef KRB5_USE_INET6
646 if (add_tcp_listener_fd(data, s6) == NULL) {
650 FD_SET(s6, &sstate.rfds);
651 if (s6 >= sstate.max)
653 krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s",
654 s6, paddr((struct sockaddr *)&sin6));
657 krb5_klog_syslog(LOG_INFO,
658 "assuming IPv6 socket accepts IPv4");
666 setup_rpc_listener_ports(struct socksetup *data)
668 struct sockaddr_in sin4;
669 #ifdef KRB5_USE_INET6
670 struct sockaddr_in6 sin6;
673 struct rpc_svc_data svc;
675 memset(&sin4, 0, sizeof(sin4));
676 sin4.sin_family = AF_INET;
678 sin4.sin_len = sizeof(sin4);
680 sin4.sin_addr.s_addr = INADDR_ANY;
682 #ifdef KRB5_USE_INET6
683 memset(&sin6, 0, sizeof(sin6));
684 sin6.sin6_family = AF_INET6;
686 sin6.sin6_len = sizeof(sin6);
688 sin6.sin6_addr = in6addr_any;
691 FOREACH_ELT (rpc_svc_data, i, svc) {
693 #ifdef KRB5_USE_INET6
697 set_sa_port((struct sockaddr *)&sin4, htons(svc.port));
698 s4 = create_server_socket(data, (struct sockaddr *)&sin4, SOCK_STREAM);
702 if (add_rpc_listener_fd(data, &svc, s4) == NULL)
705 FD_SET(s4, &sstate.rfds);
706 if (s4 >= sstate.max)
708 krb5_klog_syslog(LOG_INFO, "listening on fd %d: rpc %s",
709 s4, paddr((struct sockaddr *)&sin4));
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,
720 if (add_rpc_listener_fd(data, &svc, s6) == NULL)
723 FD_SET(s6, &sstate.rfds);
724 if (s6 >= sstate.max)
726 krb5_klog_syslog(LOG_INFO, "listening on fd %d: rpc %s",
727 s6, paddr((struct sockaddr *)&sin6));
732 FD_ZERO(&rpc_listenfds);
733 rpc_listenfds = svc_fdset;
737 #if defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && \
738 (defined(IP_PKTINFO) || defined(IPV6_PKTINFO))
740 #ifdef HAVE_STRUCT_IN6_PKTINFO
741 struct in6_pktinfo pi6;
743 #ifdef HAVE_STRUCT_IN_PKTINFO
744 struct in_pktinfo pi4;
750 setup_udp_port_1(struct socksetup *data, struct sockaddr *addr,
751 char *haddrbuf, int pktinfo);
754 setup_udp_pktinfo_ports(struct socksetup *data)
758 struct sockaddr_in sa;
761 memset(&sa, 0, sizeof(sa));
762 sa.sin_family = AF_INET;
764 sa.sin_len = sizeof(sa);
766 r = setup_udp_port_1(data, (struct sockaddr *) &sa, "0.0.0.0", 4);
768 data->udp_flags &= ~UDP_DO_IPV4;
773 struct sockaddr_in6 sa;
776 memset(&sa, 0, sizeof(sa));
777 sa.sin6_family = AF_INET6;
779 sa.sin6_len = sizeof(sa);
781 r = setup_udp_port_1(data, (struct sockaddr *) &sa, "::", 6);
783 data->udp_flags &= ~UDP_DO_IPV6;
787 #else /* no pktinfo compile-time support */
789 setup_udp_pktinfo_ports(struct socksetup *data)
795 setup_udp_port_1(struct socksetup *data, struct sockaddr *addr,
796 char *haddrbuf, int pktinfo)
801 FOREACH_ELT (udp_port_data, i, port) {
802 set_sa_port(addr, htons(port));
803 sock = create_server_socket(data, addr, SOCK_DGRAM);
808 #if !(defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && \
809 (defined(IP_PKTINFO) || defined(IPV6_PKTINFO)))
810 assert(pktinfo == 0);
813 r = set_pktinfo(sock, addr->sa_family);
815 com_err(data->prog, r, "Cannot request packet info for "
816 "udp socket address %s port %d", haddrbuf, port);
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) {
828 FD_SET (sock, &sstate.rfds);
829 if (sock >= sstate.max)
830 sstate.max = sock + 1;
836 setup_udp_port(void *P_data, struct sockaddr *addr)
838 struct socksetup *data = P_data;
839 char haddrbuf[NI_MAXHOST];
842 if (addr->sa_family == AF_INET && !(data->udp_flags & UDP_DO_IPV4))
845 if (addr->sa_family == AF_INET6 && !(data->udp_flags & UDP_DO_IPV6))
848 err = getnameinfo(addr, socklen(addr), haddrbuf, sizeof(haddrbuf),
849 0, 0, NI_NUMERICHOST);
851 strlcpy(haddrbuf, "<unprintable>", sizeof(haddrbuf));
853 switch (addr->sa_family) {
858 #ifdef KRB5_USE_INET6
862 static int first = 1;
864 krb5_klog_syslog (LOG_INFO, "skipping local ipv6 addresses");
871 #ifdef AF_LINK /* some BSD systems, AIX */
875 #ifdef AF_DLI /* Direct Link Interface - DEC Ultrix/OSF1 link layer? */
884 krb5_klog_syslog (LOG_INFO,
885 "skipping unrecognized local address family %d",
889 return setup_udp_port_1(data, addr, haddrbuf, 0);
894 klog_handler(const void *data, size_t len)
896 static char buf[BUFSIZ];
897 static int bufoffset;
900 #define flush_buf() \
902 ? (((buf[0] == 0 || buf[0] == '\n') \
903 ? (fork()==0?abort():(void)0) \
905 krb5_klog_syslog(LOG_INFO, "%s", buf), \
906 memset(buf, 0, sizeof(buf)), \
910 p = memchr(data, 0, len);
912 len = (const char *)p - (const char *)data;
916 p = memchr(data, '\n', len);
919 klog_handler(data, (size_t)((const char *)p - (const char *)data));
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);
929 data = (const char *)data + x;
930 goto scan_for_newlines;
932 memcpy(buf + bufoffset, data, len);
938 static int network_reconfiguration_needed = 0;
940 #ifdef HAVE_STRUCT_RT_MSGHDR
941 #include <net/route.h>
944 rtm_type_name(int 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";
956 case RTM_NEWMADDR: return "RTM_NEWMADDR";
957 case RTM_DELMADDR: return "RTM_DELMADDR";
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";
968 process_routing_update(void *handle, struct connection *conn, const char *prog,
972 struct rt_msghdr rtm;
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.
979 A short read seems to be normal for some message types.
980 Only complain if we don't have the critical initial
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));
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),
998 if (rtm.rtm_msglen > sizeof(rtm)) {
999 /* It appears we get a partial message and the rest is
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);
1006 switch (rtm.rtm_type) {
1015 * Some flags indicate routing table updates that don't
1016 * indicate local address changes. They may come from
1017 * redirects, or ARP, etc.
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
1027 if (rtm.rtm_flags & RTF_DYNAMIC)
1031 if (rtm.rtm_flags & RTF_CLONED)
1035 if (rtm.rtm_flags & RTF_LLINFO)
1039 krb5_klog_syslog(LOG_DEBUG,
1040 "network reconfiguration message (%s) received",
1041 rtm_type_name(rtm.rtm_type));
1043 network_reconfiguration_needed = 1;
1054 /* Not interesting. */
1056 krb5_klog_syslog(LOG_DEBUG, "routing msg not interesting");
1060 krb5_klog_syslog(LOG_INFO, "unhandled routing message type %d, "
1061 "will reconfigure just for the fun of it",
1063 network_reconfiguration_needed = 1;
1070 setup_routing_socket(struct socksetup *data)
1072 int sock = socket(PF_ROUTE, SOCK_RAW, 0);
1075 krb5_klog_syslog(LOG_INFO, "couldn't set up routing socket: %s",
1078 krb5_klog_syslog(LOG_INFO, "routing socket is fd %d", sock);
1079 add_fd(data, sock, CONN_ROUTING, process_routing_update);
1081 FD_SET(sock, &sstate.rfds);
1087 extern int krb5int_debug_sendto_kdc;
1088 extern void (*krb5int_sendtokdc_debug_handler)(const void*, size_t);
1091 setup_network(void *handle, const char *prog, int no_reconfig)
1093 struct socksetup setup_data;
1095 FD_ZERO(&sstate.rfds);
1096 FD_ZERO(&sstate.wfds);
1097 FD_ZERO(&sstate.xfds);
1100 /* krb5int_debug_sendto_kdc = 1; */
1101 krb5int_sendtokdc_debug_handler = klog_handler;
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
1108 setup_routing_socket(&setup_data);
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
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;
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?");
1135 init_addr(krb5_fulladdr *faddr, struct sockaddr *sa)
1137 switch (sa->sa_family) {
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);
1144 #ifdef KRB5_USE_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;
1151 faddr->address->addrtype = ADDRTYPE_INET6;
1152 faddr->address->length = 16;
1153 faddr->address->contents = (krb5_octet *) &sa2sin6(sa)->sin6_addr;
1155 faddr->port = ntohs(sa2sin6(sa)->sin6_port);
1159 faddr->address->addrtype = -1;
1160 faddr->address->length = 0;
1161 faddr->address->contents = 0;
1168 * This holds whatever additional information might be needed to
1169 * properly send back to the client from the correct local address.
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.
1176 union aux_addressing_info {
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)
1186 #if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE)
1188 /* Clobber with something recognizeable in case we try to use
1190 memset(to, 0x40, *tolen);
1194 return recvfrom(s, buf, len, flags, from, fromlen);
1198 char cmsg[CMSG_SPACE(sizeof(union pktinfo))];
1199 struct cmsghdr *cmsgptr;
1203 return recvfrom(s, buf, len, flags, from, fromlen);
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);
1211 memset(&msg, 0, sizeof(msg));
1212 msg.msg_name = from;
1213 msg.msg_namelen = *fromlen;
1216 msg.msg_control = cmsg;
1217 msg.msg_controllen = sizeof(cmsg);
1219 r = recvmsg(s, &msg, flags);
1222 *fromlen = msg.msg_namelen;
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);
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);
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;
1259 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr);
1262 /* No info about destination addr was available. */
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)
1274 #if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE)
1275 return sendto(s, buf, len, flags, to, tolen);
1279 struct cmsghdr *cmsgptr;
1280 char cbuf[CMSG_SPACE(sizeof(union pktinfo))];
1282 if (from == 0 || fromlen == 0 || from->sa_family != to->sa_family) {
1284 return sendto(s, buf, len, flags, to, tolen);
1290 if (iov.iov_len != len)
1292 memset(cbuf, 0, sizeof(cbuf));
1293 memset(&msg, 0, sizeof(msg));
1294 msg.msg_name = (void *) to;
1295 msg.msg_namelen = tolen;
1298 msg.msg_control = cbuf;
1299 /* CMSG_FIRSTHDR needs a non-zero controllen, or it'll return NULL
1301 msg.msg_controllen = sizeof(cbuf);
1302 cmsgptr = CMSG_FIRSTHDR(&msg);
1303 msg.msg_controllen = 0;
1305 switch (from->sa_family) {
1306 #if defined(IP_PKTINFO)
1308 if (fromlen != sizeof(struct sockaddr_in))
1310 cmsgptr->cmsg_level = IPPROTO_IP;
1311 cmsgptr->cmsg_type = IP_PKTINFO;
1312 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
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;
1318 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
1321 #if defined(KRB5_USE_INET6) && defined(IPV6_PKTINFO) && \
1322 defined(HAVE_STRUCT_IN6_PKTINFO)
1324 if (fromlen != sizeof(struct sockaddr_in6))
1326 cmsgptr->cmsg_level = IPPROTO_IPV6;
1327 cmsgptr->cmsg_type = IPV6_PKTINFO;
1328 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
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;
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
1342 if (IN6_IS_ADDR_LINKLOCAL(&from6->sin6_addr))
1343 p->ipi6_ifindex = auxaddr->ipv6_ifindex;
1344 /* otherwise, already zero */
1346 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1352 return sendmsg(s, &msg, flags);
1357 process_packet(void *handle, struct connection *conn, const char *prog,
1361 socklen_t saddr_len, daddr_len;
1362 krb5_fulladdr faddr;
1363 krb5_error_code retval;
1364 struct sockaddr_storage saddr, daddr;
1367 krb5_data *response;
1368 char pktbuf[MAX_DGRAM_SIZE];
1369 int port_fd = conn->fd;
1370 union aux_addressing_info auxaddr;
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,
1381 if (errno != EINTR && errno != EAGAIN
1383 * This is how Linux indicates that a previous transmission was
1384 * refused, e.g., if the client timed out before getting the
1387 && errno != ECONNREFUSED
1389 com_err(prog, errno, "while receiving from network");
1393 return; /* zero-length packet? */
1396 if (daddr_len > 0) {
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);
1405 if (daddr_len == 0 && conn->type == CONN_UDP) {
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.
1411 daddr_len = sizeof(daddr);
1412 if (getsockname(port_fd, (struct sockaddr *)&daddr, &daddr_len) != 0)
1414 /* On failure, keep going anyways. */
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);
1424 com_err(prog, retval, "while dispatching (udp)");
1427 if (response == NULL)
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,
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];
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));
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));
1451 com_err(prog, e, "while sending reply to %s/%s from %s",
1452 saddrbuf, sportbuf, daddrbuf);
1455 if ((size_t)cc != response->length) {
1456 com_err(prog, 0, "short reply write %d vs %d\n",
1457 response->length, cc);
1459 krb5_free_data(get_context(handle), response);
1463 static int tcp_or_rpc_data_counter;
1464 static int max_tcp_or_rpc_data_connections = 45;
1466 static void kill_tcp_or_rpc_connection(void *, struct connection *,
1470 kill_lru_tcp_or_rpc_connection(void *handle, struct connection *newconn)
1472 struct connection *oldest_tcp = NULL;
1473 struct connection *c;
1476 krb5_klog_syslog(LOG_INFO, "too many connections");
1478 FOREACH_ELT (connections, i, c) {
1479 if (c->type != CONN_TCP && c->type != CONN_RPC)
1484 krb5_klog_syslog(LOG_INFO, "fd %d started at %ld", c->fd,
1485 c->u.tcp.start_time);
1487 if (oldest_tcp == NULL
1488 || oldest_tcp->u.tcp.start_time > c->u.tcp.start_time)
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);
1502 accept_tcp_connection(void *handle, struct connection *conn, const char *prog,
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;
1513 s = accept(conn->fd, addr, &addrlen);
1518 if (s >= FD_SETSIZE) {
1523 setnbio(s), setnolinger(s), setkeepalive(s);
1525 sockdata.prog = prog;
1526 sockdata.retval = 0;
1528 newconn = add_tcp_data_fd(&sockdata, s);
1529 if (newconn == NULL)
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));
1539 p = newconn->u.tcp.addrbuf;
1540 end = p + sizeof(newconn->u.tcp.addrbuf);
1542 if ((size_t)(end - p) > 2 + strlen(tmpbuf)) {
1544 strlcpy(p, tmpbuf, end - p);
1548 krb5_klog_syslog(LOG_INFO, "accepted TCP connection on socket %d from %s",
1549 s, newconn->u.tcp.addrbuf);
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);
1558 if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
1559 kill_lru_tcp_or_rpc_connection(handle, newconn);
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);
1566 tcp_or_rpc_data_counter--;
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);
1575 FD_SET(s, &sstate.rfds);
1576 if (sstate.max <= s)
1581 kill_tcp_or_rpc_connection(void *handle, struct connection *conn,
1584 assert(conn->type == CONN_TCP || conn->type == CONN_RPC);
1585 assert(conn->fd != -1);
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) */
1601 /* In the non-forced case, the RPC runtime will close the descriptor for
1603 if (conn->type == CONN_TCP || isForcedClose) {
1607 /* For RPC connections, call into RPC runtime to flush out any internal
1609 if (conn->type == CONN_RPC && isForcedClose) {
1613 FD_SET(conn->fd, &fds);
1615 svc_getreqset(&fds);
1617 if (FD_ISSET(conn->fd, &svc_fdset)) {
1618 krb5_klog_syslog(LOG_ERR,
1619 "descriptor %d closed but still in svc_fdset",
1626 tcp_or_rpc_data_counter--;
1630 queue_tcp_outgoing_response(struct connection *conn)
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);
1641 process_tcp_connection(void *handle, struct connection *conn, const char *prog,
1644 int isForcedClose = 1; /* not used now, but for completeness */
1646 if (selflags & SSF_WRITE) {
1648 SOCKET_WRITEV_TEMP tmp;
1650 nwrote = SOCKET_WRITEV(conn->fd, conn->u.tcp.sgp, conn->u.tcp.sgnum,
1653 goto kill_tcp_connection;
1658 goto kill_tcp_connection;
1661 sg_buf *sgp = conn->u.tcp.sgp;
1662 if ((size_t)nwrote < SG_LEN(sgp)) {
1663 SG_ADVANCE(sgp, (size_t)nwrote);
1666 nwrote -= SG_LEN(sgp);
1668 conn->u.tcp.sgnum--;
1669 if (conn->u.tcp.sgnum == 0 && nwrote != 0)
1673 if (conn->u.tcp.sgnum == 0) {
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.
1680 goto kill_tcp_connection;
1682 } else if (selflags & SSF_READ) {
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.
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);
1699 goto kill_tcp_connection;
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);
1717 krb5_klog_syslog(LOG_ERR, "error constructing "
1718 "KRB_ERR_FIELD_TOOLONG error! %s",
1719 error_message(err));
1720 goto kill_tcp_connection;
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;
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)
1743 /* Have a complete message, and exactly one message. */
1744 request.length = conn->u.tcp.msglen;
1745 request.data = conn->u.tcp.buffer + 4;
1747 if (getsockname(conn->fd, ss2sa(&local_saddr),
1748 &local_saddrlen) == 0)
1749 local_saddrp = ss2sa(&local_saddr);
1751 err = dispatch(handle, local_saddrp, &conn->u.tcp.faddr,
1752 &request, &conn->u.tcp.response, 1);
1754 com_err(prog, err, "while dispatching (tcp)");
1755 goto kill_tcp_connection;
1757 if (conn->u.tcp.response == NULL)
1758 goto kill_tcp_connection;
1760 queue_tcp_outgoing_response(conn);
1761 FD_CLR(conn->fd, &sstate.rfds);
1768 kill_tcp_connection:
1769 kill_tcp_or_rpc_connection(handle, conn, isForcedClose);
1773 service_conn(void *handle, struct connection *conn, const char *prog,
1776 conn->service(handle, conn, prog, selflags);
1780 getcurtime(struct timeval *tvp)
1785 tvp->tv_sec = tb.time;
1786 tvp->tv_usec = tb.millitm * 1000;
1789 return gettimeofday(tvp, 0) ? errno : 0;
1794 listen_and_process(void *handle, const char *prog, void (*reset)(void))
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;
1802 int sret, netchanged = 0;
1803 krb5_error_code err;
1805 if (conns == (struct connection **) NULL)
1808 while (!signal_requests_exit) {
1809 if (signal_requests_reset) {
1810 krb5_klog_reopen(get_context(handle));
1812 signal_requests_reset = 0;
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);
1823 com_err(prog, err, "while getting the time");
1826 sstate.end_time.tv_sec += 3;
1829 sstate.end_time.tv_sec = sstate.end_time.tv_usec = 0;
1831 err = krb5int_cm_call_select(&sstate, &sout, &sret);
1834 com_err(prog, err, "while selecting for network input(1)");
1837 if (sret == 0 && netchanged) {
1838 network_reconfiguration_needed = 0;
1839 closedown_network_sockets();
1840 err = setup_network(handle, prog, 0);
1842 com_err(prog, err, "while reinitializing network");
1849 com_err(prog, errno, "while selecting for network input(2)");
1853 for (i=0; i<n_sockets && nfound > 0; i++) {
1855 if (conns[i]->fd < 0)
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--;
1862 service_conn(handle, conns[i], prog, sflags);
1865 krb5_klog_syslog(LOG_INFO, "shutdown signal received");
1870 closedown_network_sockets()
1873 struct connection *conn;
1875 if (conns == (struct connection **) NULL)
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) {
1886 FD_SET(conn->fd, &fds);
1888 svc_getreqset(&fds);
1891 if (conn->type == CONN_RPC_LISTENER) {
1892 if (conn->u.rpc.transp != NULL)
1893 svc_destroy(conn->u.rpc.transp);
1895 DEL (connections, i);
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.
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);
1916 accept_rpc_connection(void *handle, struct connection *conn, const char *prog,
1919 struct socksetup sockdata;
1923 assert(selflags & SSF_READ);
1925 if ((selflags & SSF_READ) == 0)
1928 sockdata.prog = prog;
1929 sockdata.retval = 0;
1931 /* Service the woken RPC listener descriptor. */
1933 FD_SET(conn->fd, &fds);
1935 svc_getreqset(&fds);
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);
1948 newconn = add_rpc_data_fd(&sockdata, s);
1949 if (newconn == NULL)
1954 setnbio(s), setnolinger(s), setkeepalive(s);
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));
1967 p = newconn->u.tcp.addrbuf;
1968 end = p + sizeof(newconn->u.tcp.addrbuf);
1970 if ((size_t)(end - p) > 2 + strlen(tmpbuf)) {
1972 strlcpy(p, tmpbuf, end - p);
1976 krb5_klog_syslog(LOG_INFO, "accepted RPC connection on socket %d "
1977 "from %s", s, newconn->u.tcp.addrbuf);
1980 newconn->u.tcp.addr_s = addr_s;
1981 newconn->u.tcp.addrlen = addrlen;
1982 newconn->u.tcp.start_time = time(0);
1984 if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
1985 kill_lru_tcp_or_rpc_connection(handle, newconn);
1987 newconn->u.tcp.faddr.address = &newconn->u.tcp.kaddr;
1988 init_addr(&newconn->u.tcp.faddr, ss2sa(&newconn->u.tcp.addr_s));
1990 FD_SET(s, &sstate.rfds);
1991 if (sstate.max <= s)
1998 process_rpc_connection(void *handle, struct connection *conn, const char *prog,
2003 assert(selflags & SSF_READ);
2005 if ((selflags & SSF_READ) == 0)
2009 FD_SET(conn->fd, &fds);
2011 svc_getreqset(&fds);
2013 if (!FD_ISSET(conn->fd, &svc_fdset))
2014 kill_tcp_or_rpc_connection(handle, conn, 0);