1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * lib/apputils/net-server.c
5 * Copyright 1990,2000,2007,2008,2009,2010 by the Massachusetts Institute of Technology.
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.
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.
27 * Network code for Kerberos v5 servers (kdc, kadmind).
31 #include "adm_proto.h"
32 #include <sys/ioctl.h>
36 #include "port-sockets.h"
37 #include "socket-utils.h"
39 #include <gssrpc/rpc.h>
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>
51 #include <sys/select.h>
53 #include <arpa/inet.h>
55 #ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */
59 #ifdef HAVE_SYS_FILIO_H
60 #include <sys/filio.h> /* FIONBIO */
63 #include "fake-addrinfo.h"
64 #include "net-server.h"
67 #define KDC5_NONET (-1779992062L)
69 volatile int signal_requests_exit = 0, signal_requests_reset = 0;
71 static void closedown_network_sockets(void);
73 /* Misc utility routines. */
75 set_sa_port(struct sockaddr *addr, int port)
77 switch (addr->sa_family) {
79 sa2sin(addr)->sin_port = port;
83 sa2sin6(addr)->sin6_port = port;
91 static int ipv6_enabled()
94 static int result = -1;
97 s = socket(AF_INET6, SOCK_STREAM, 0);
111 setreuseaddr(int sock, int value)
113 return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
116 #if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
118 setv6only(int sock, int value)
120 return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
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
129 /* Parallel, though not standardized. */
130 #ifndef IP_RECVPKTINFO
131 #define IP_RECVPKTINFO IP_PKTINFO
135 set_pktinfo(int sock, int family)
138 int option = 0, proto = 0;
141 #if defined(IP_PKTINFO) && defined(HAVE_STRUCT_IN_PKTINFO)
144 option = IP_RECVPKTINFO;
147 #if defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
149 proto = IPPROTO_IPV6;
150 option = IPV6_RECVPKTINFO;
156 if (setsockopt(sock, proto, option, &sockopt, sizeof(sockopt)))
162 static const char *paddr (struct sockaddr *sa)
164 static char buf[100];
166 if (getnameinfo(sa, socklen(sa),
167 buf, sizeof(buf), portbuf, sizeof(portbuf),
168 NI_NUMERICHOST|NI_NUMERICSERV))
169 strlcpy(buf, "<unprintable>", sizeof(buf));
171 unsigned int len = sizeof(buf) - strlen(buf);
172 char *p = buf + strlen(buf);
173 if (len > 2+strlen(portbuf)) {
176 strncpy(p, portbuf, len);
185 CONN_UDP, CONN_UDP_PKTINFO, CONN_TCP_LISTENER, CONN_TCP,
186 CONN_RPC_LISTENER, CONN_RPC,
190 /* Per-connection info. */
194 void (*service)(void *handle, struct connection *, const char *, int);
196 /* Type-specific information. */
199 struct sockaddr_storage addr_s;
211 unsigned char lenbuf[4];
215 /* crude denial-of-service avoidance support */
225 #define SET(TYPE) struct { TYPE *data; int n, max; }
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--)
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))) \
239 : ((tmpptr = realloc(set.data, \
240 (int)(set.max + incr) * sizeof(set.data[0]))) \
241 ? (set.data = tmpptr, set.max += incr, 1) \
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) \
250 #define DEL(set, idx) \
251 (set.data[idx] = set.data[--set.n], 0)
253 #define FREE_SET_DATA(set) \
254 (free(set.data), set.data = 0, set.max = 0, set.n = 0)
257 /* Set<struct connection *> connections; */
258 static SET(struct connection *) connections;
259 #define n_sockets connections.n
260 #define conns connections.data
262 /* Set<u_short> udp_port_data, tcp_port_data; */
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.
268 static SET(unsigned short) udp_port_data, tcp_port_data;
270 struct rpc_svc_data {
277 static SET(struct rpc_svc_data) rpc_svc_data;
281 static struct select_state sstate;
282 static fd_set rpc_listenfds;
284 krb5_error_code add_udp_port(int port)
289 u_short s_port = port;
294 FOREACH_ELT (udp_port_data, i, val)
297 if (!ADD(udp_port_data, s_port, tmp))
302 krb5_error_code add_tcp_port(int port)
307 u_short s_port = port;
312 FOREACH_ELT (tcp_port_data, i, val)
315 if (!ADD(tcp_port_data, s_port, tmp))
320 krb5_error_code add_rpc_service(int port, u_long prognum, u_long versnum,
325 struct rpc_svc_data svc, val;
328 if (svc.port != port)
330 svc.prognum = prognum;
331 svc.versnum = versnum;
332 svc.dispatch = dispatch;
334 FOREACH_ELT (rpc_svc_data, i, val) {
335 if (val.port == port)
338 if (!ADD(rpc_svc_data, svc, tmp))
344 #define USE_AF AF_INET
345 #define USE_TYPE SOCK_DGRAM
347 #define SOCKET_ERRNO errno
348 #include "foreachaddr.h"
352 krb5_error_code retval;
354 #define UDP_DO_IPV4 1
355 #define UDP_DO_IPV6 2
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))
362 struct connection *newconn;
366 if (sock >= FD_SETSIZE) {
367 data->retval = EMFILE; /* XXX */
368 com_err(data->prog, 0,
369 "file descriptor number %d too high", sock);
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");
380 if (!ADD(connections, newconn, tmp)) {
381 data->retval = ENOMEM;
382 com_err(data->prog, ENOMEM, "cannot save socket info");
387 memset(newconn, 0, sizeof(*newconn));
388 newconn->type = conntype;
390 newconn->service = service;
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);
400 static struct connection *
401 add_udp_fd (struct socksetup *data, int sock, int pktinfo)
403 return add_fd(data, sock, pktinfo ? CONN_UDP_PKTINFO : CONN_UDP,
407 static struct connection *
408 add_tcp_listener_fd (struct socksetup *data, int sock)
410 return add_fd(data, sock, CONN_TCP_LISTENER, accept_tcp_connection);
413 static struct connection *
414 add_tcp_data_fd (struct socksetup *data, int sock)
416 return add_fd(data, sock, CONN_TCP, process_tcp_connection);
420 delete_fd (struct connection *xconn)
422 struct connection *conn;
425 FOREACH_ELT(connections, i, conn)
433 static struct connection *
434 add_rpc_listener_fd (struct socksetup *data, struct rpc_svc_data *svc, int sock)
436 struct connection *conn;
438 conn = add_fd(data, sock, CONN_RPC_LISTENER, accept_rpc_connection);
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",
450 if (!svc_register(conn->u.rpc.transp, svc->prognum, svc->versnum,
452 krb5_klog_syslog(LOG_ERR, "Cannot register RPC service: %s; continuing",
461 static struct connection *
462 add_rpc_data_fd (struct socksetup *data, int sock)
464 return add_fd(data, sock, CONN_RPC, process_rpc_connection);
467 static const int one = 1;
472 return ioctlsocket(sock, FIONBIO, (const void *)&one);
476 setkeepalive(int sock)
478 return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one));
484 static const struct linger ling = { 0, 0 };
485 return setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
488 /* Returns -1 or socket fd. */
490 setup_a_tcp_listener(struct socksetup *data, struct sockaddr *addr)
494 sock = socket(addr->sa_family, SOCK_STREAM, 0);
496 com_err(data->prog, errno, "Cannot create TCP server socket on %s",
500 set_cloexec_fd(sock);
502 if (sock >= FD_SETSIZE) {
504 com_err(data->prog, 0, "TCP socket fd number %d (for %s) too high",
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) {
515 if (setv6only(sock, 1))
516 com_err(data->prog, errno, "setsockopt(%d,IPV6_V6ONLY,1) failed",
519 com_err(data->prog, 0, "setsockopt(%d,IPV6_V6ONLY,1) worked",
522 krb5_klog_syslog(LOG_INFO, "no IPV6_V6ONLY socket option support");
523 #endif /* IPV6_V6ONLY */
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));
532 if (listen(sock, 5) < 0) {
533 com_err(data->prog, errno, "Cannot listen on TCP server socket on %s",
539 com_err(data->prog, errno,
540 "cannot set listening tcp socket on %s non-blocking",
545 if (setnolinger(sock)) {
546 com_err(data->prog, errno, "disabling SO_LINGER on TCP socket on %s",
554 /* Returns -1 or socket fd. */
556 setup_a_rpc_listener(struct socksetup *data, struct sockaddr *addr)
560 sock = socket(addr->sa_family, SOCK_STREAM, 0);
562 com_err(data->prog, errno, "Cannot create RPC server socket on %s",
566 set_cloexec_fd(sock);
568 if (sock >= FD_SETSIZE) {
570 com_err(data->prog, 0, "RPC socket fd number %d (for %s) too high",
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));
588 setup_tcp_listener_ports(struct socksetup *data)
590 struct sockaddr_in sin4;
591 #ifdef KRB5_USE_INET6
592 struct sockaddr_in6 sin6;
596 memset(&sin4, 0, sizeof(sin4));
597 sin4.sin_family = AF_INET;
599 sin4.sin_len = sizeof(sin4);
601 sin4.sin_addr.s_addr = INADDR_ANY;
603 #ifdef KRB5_USE_INET6
604 memset(&sin6, 0, sizeof(sin6));
605 sin6.sin6_family = AF_INET6;
607 sin6.sin6_len = sizeof(sin6);
609 sin6.sin6_addr = in6addr_any;
612 FOREACH_ELT (tcp_port_data, i, port) {
615 set_sa_port((struct sockaddr *)&sin4, htons(port));
616 if (!ipv6_enabled()) {
617 s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
622 #ifndef KRB5_USE_INET6
627 set_sa_port((struct sockaddr *)&sin6, htons(port));
629 s6 = setup_a_tcp_listener(data, (struct sockaddr *)&sin6);
633 s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
634 #endif /* KRB5_USE_INET6 */
637 /* Sockets are created, prepare to listen on them. */
639 if (add_tcp_listener_fd(data, s4) == NULL)
642 FD_SET(s4, &sstate.rfds);
643 if (s4 >= sstate.max)
645 krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s",
646 s4, paddr((struct sockaddr *)&sin4));
649 #ifdef KRB5_USE_INET6
651 if (add_tcp_listener_fd(data, s6) == NULL) {
655 FD_SET(s6, &sstate.rfds);
656 if (s6 >= sstate.max)
658 krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s",
659 s6, paddr((struct sockaddr *)&sin6));
662 krb5_klog_syslog(LOG_INFO,
663 "assuming IPv6 socket accepts IPv4");
671 setup_rpc_listener_ports(struct socksetup *data)
673 struct sockaddr_in sin4;
675 struct rpc_svc_data svc;
677 memset(&sin4, 0, sizeof(sin4));
678 sin4.sin_family = AF_INET;
680 sin4.sin_len = sizeof(sin4);
682 sin4.sin_addr.s_addr = INADDR_ANY;
684 FOREACH_ELT (rpc_svc_data, i, svc) {
687 set_sa_port((struct sockaddr *)&sin4, htons(svc.port));
688 s4 = setup_a_rpc_listener(data, (struct sockaddr *)&sin4);
692 if (add_rpc_listener_fd(data, &svc, s4) == NULL)
695 FD_SET(s4, &sstate.rfds);
696 if (s4 >= sstate.max)
698 krb5_klog_syslog(LOG_INFO, "listening on fd %d: rpc %s",
699 s4, paddr((struct sockaddr *)&sin4));
703 FD_ZERO(&rpc_listenfds);
704 rpc_listenfds = svc_fdset;
708 #if defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && (defined(IP_PKTINFO) || defined(IPV6_PKTINFO))
710 #ifdef HAVE_STRUCT_IN6_PKTINFO
711 struct in6_pktinfo pi6;
713 #ifdef HAVE_STRUCT_IN_PKTINFO
714 struct in_pktinfo pi4;
720 setup_udp_port_1(struct socksetup *data, struct sockaddr *addr,
721 char *haddrbuf, int pktinfo);
724 setup_udp_pktinfo_ports(struct socksetup *data)
728 struct sockaddr_in sa;
731 memset(&sa, 0, sizeof(sa));
732 sa.sin_family = AF_INET;
734 sa.sin_len = sizeof(sa);
736 r = setup_udp_port_1(data, (struct sockaddr *) &sa, "0.0.0.0", 4);
738 data->udp_flags &= ~UDP_DO_IPV4;
743 struct sockaddr_in6 sa;
746 memset(&sa, 0, sizeof(sa));
747 sa.sin6_family = AF_INET6;
749 sa.sin6_len = sizeof(sa);
751 r = setup_udp_port_1(data, (struct sockaddr *) &sa, "::", 6);
753 data->udp_flags &= ~UDP_DO_IPV6;
757 #else /* no pktinfo compile-time support */
759 setup_udp_pktinfo_ports(struct socksetup *data)
765 setup_udp_port_1(struct socksetup *data, struct sockaddr *addr,
766 char *haddrbuf, int pktinfo)
771 FOREACH_ELT (udp_port_data, i, port) {
772 sock = socket (addr->sa_family, SOCK_DGRAM, 0);
774 data->retval = errno;
775 com_err(data->prog, data->retval,
776 "Cannot create server socket for port %d address %s",
780 set_cloexec_fd(sock);
781 #ifdef KRB5_USE_INET6
782 if (addr->sa_family == AF_INET6) {
784 if (setv6only(sock, 1))
785 com_err(data->prog, errno,
786 "setsockopt(%d,IPV6_V6ONLY,1) failed", sock);
788 com_err(data->prog, 0, "setsockopt(%d,IPV6_V6ONLY,1) worked",
791 krb5_klog_syslog(LOG_INFO, "no IPV6_V6ONLY socket option support");
792 #endif /* IPV6_V6ONLY */
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",
804 #if !(defined(CMSG_SPACE) && defined(HAVE_STRUCT_CMSGHDR) && (defined(IP_PKTINFO) || defined(IPV6_PKTINFO)))
805 assert(pktinfo == 0);
808 r = set_pktinfo(sock, addr->sa_family);
810 com_err(data->prog, r,
811 "Cannot request packet info for udp socket address %s port %d",
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) {
824 FD_SET (sock, &sstate.rfds);
825 if (sock >= sstate.max)
826 sstate.max = sock + 1;
832 setup_udp_port(void *P_data, struct sockaddr *addr)
834 struct socksetup *data = P_data;
835 char haddrbuf[NI_MAXHOST];
838 if (addr->sa_family == AF_INET && !(data->udp_flags & UDP_DO_IPV4))
841 if (addr->sa_family == AF_INET6 && !(data->udp_flags & UDP_DO_IPV6))
844 err = getnameinfo(addr, socklen(addr), haddrbuf, sizeof(haddrbuf),
845 0, 0, NI_NUMERICHOST);
847 strlcpy(haddrbuf, "<unprintable>", sizeof(haddrbuf));
849 switch (addr->sa_family) {
854 #ifdef KRB5_USE_INET6
858 static int first = 1;
860 krb5_klog_syslog (LOG_INFO, "skipping local ipv6 addresses");
867 #ifdef AF_LINK /* some BSD systems, AIX */
871 #ifdef AF_DLI /* Direct Link Interface - DEC Ultrix/OSF1 link layer? */
880 krb5_klog_syslog (LOG_INFO,
881 "skipping unrecognized local address family %d",
885 return setup_udp_port_1(data, addr, haddrbuf, 0);
889 static void klog_handler(const void *data, size_t len)
891 static char buf[BUFSIZ];
892 static int bufoffset;
895 #define flush_buf() \
897 ? (((buf[0] == 0 || buf[0] == '\n') \
898 ? (fork()==0?abort():(void)0) \
900 krb5_klog_syslog(LOG_INFO, "%s", buf), \
901 memset(buf, 0, sizeof(buf)), \
905 p = memchr(data, 0, len);
907 len = (const char *)p - (const char *)data;
911 p = memchr(data, '\n', len);
914 klog_handler(data, (size_t)((const char *)p - (const char *)data));
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);
924 data = (const char *)data + x;
925 goto scan_for_newlines;
927 memcpy(buf + bufoffset, data, len);
933 static int network_reconfiguration_needed = 0;
935 #ifdef HAVE_STRUCT_RT_MSGHDR
936 #include <net/route.h>
938 static char *rtm_type_name(int 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";
950 case RTM_NEWMADDR: return "RTM_NEWMADDR";
951 case RTM_DELMADDR: return "RTM_DELMADDR";
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";
961 static void process_routing_update(void *handle, struct connection *conn,
962 const char *prog, int selflags)
965 struct rt_msghdr rtm;
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.
972 A short read seems to be normal for some message types.
973 Only complain if we don't have the critical initial
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));
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),
991 if (rtm.rtm_msglen > sizeof(rtm)) {
992 /* It appears we get a partial message and the rest is
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);
999 switch (rtm.rtm_type) {
1008 * Some flags indicate routing table updates that don't
1009 * indicate local address changes. They may come from
1010 * redirects, or ARP, etc.
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
1020 if (rtm.rtm_flags & RTF_DYNAMIC)
1024 if (rtm.rtm_flags & RTF_CLONED)
1028 if (rtm.rtm_flags & RTF_LLINFO)
1032 krb5_klog_syslog(LOG_DEBUG,
1033 "network reconfiguration message (%s) received",
1034 rtm_type_name(rtm.rtm_type));
1036 network_reconfiguration_needed = 1;
1047 /* Not interesting. */
1049 krb5_klog_syslog(LOG_DEBUG, "routing msg not interesting");
1053 krb5_klog_syslog(LOG_INFO,
1054 "unhandled routing message type %d, will reconfigure just for the fun of it",
1056 network_reconfiguration_needed = 1;
1063 setup_routing_socket(struct socksetup *data)
1065 int sock = socket(PF_ROUTE, SOCK_RAW, 0);
1068 krb5_klog_syslog(LOG_INFO, "couldn't set up routing socket: %s",
1071 krb5_klog_syslog(LOG_INFO, "routing socket is fd %d", sock);
1072 add_fd(data, sock, CONN_ROUTING, process_routing_update);
1074 FD_SET(sock, &sstate.rfds);
1080 extern int krb5int_debug_sendto_kdc;
1081 extern void (*krb5int_sendtokdc_debug_handler)(const void*, size_t);
1084 setup_network(void *handle, const char *prog)
1086 struct socksetup setup_data;
1088 FD_ZERO(&sstate.rfds);
1089 FD_ZERO(&sstate.wfds);
1090 FD_ZERO(&sstate.xfds);
1093 /* krb5int_debug_sendto_kdc = 1; */
1094 krb5int_sendtokdc_debug_handler = klog_handler;
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);
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
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;
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?");
1124 void init_addr(krb5_fulladdr *faddr, struct sockaddr *sa)
1126 switch (sa->sa_family) {
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);
1133 #ifdef KRB5_USE_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;
1140 faddr->address->addrtype = ADDRTYPE_INET6;
1141 faddr->address->length = 16;
1142 faddr->address->contents = (krb5_octet *) &sa2sin6(sa)->sin6_addr;
1144 faddr->port = ntohs(sa2sin6(sa)->sin6_port);
1148 faddr->address->addrtype = -1;
1149 faddr->address->length = 0;
1150 faddr->address->contents = 0;
1157 * This holds whatever additional information might be needed to
1158 * properly send back to the client from the correct local address.
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.
1165 union aux_addressing_info {
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)
1175 #if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE)
1177 /* Clobber with something recognizeable in case we try to use
1179 memset(to, 0x40, *tolen);
1183 return recvfrom(s, buf, len, flags, from, fromlen);
1187 char cmsg[CMSG_SPACE(sizeof(union pktinfo))];
1188 struct cmsghdr *cmsgptr;
1192 return recvfrom(s, buf, len, flags, from, fromlen);
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);
1200 memset(&msg, 0, sizeof(msg));
1201 msg.msg_name = from;
1202 msg.msg_namelen = *fromlen;
1205 msg.msg_control = cmsg;
1206 msg.msg_controllen = sizeof(cmsg);
1208 r = recvmsg(s, &msg, flags);
1211 *fromlen = msg.msg_namelen;
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);
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);
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;
1247 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr);
1250 /* No info about destination addr was available. */
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)
1262 #if (!defined(IP_PKTINFO) && !defined(IPV6_PKTINFO)) || !defined(CMSG_SPACE)
1263 return sendto(s, buf, len, flags, to, tolen);
1267 struct cmsghdr *cmsgptr;
1268 char cbuf[CMSG_SPACE(sizeof(union pktinfo))];
1270 if (from == 0 || fromlen == 0 || from->sa_family != to->sa_family) {
1272 return sendto(s, buf, len, flags, to, tolen);
1278 if (iov.iov_len != len)
1280 memset(cbuf, 0, sizeof(cbuf));
1281 memset(&msg, 0, sizeof(msg));
1282 msg.msg_name = (void *) to;
1283 msg.msg_namelen = tolen;
1286 msg.msg_control = cbuf;
1287 /* CMSG_FIRSTHDR needs a non-zero controllen, or it'll return NULL
1289 msg.msg_controllen = sizeof(cbuf);
1290 cmsgptr = CMSG_FIRSTHDR(&msg);
1291 msg.msg_controllen = 0;
1293 switch (from->sa_family) {
1294 #if defined(IP_PKTINFO)
1296 if (fromlen != sizeof(struct sockaddr_in))
1298 cmsgptr->cmsg_level = IPPROTO_IP;
1299 cmsgptr->cmsg_type = IP_PKTINFO;
1300 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
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;
1306 msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
1309 #if defined(KRB5_USE_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_STRUCT_IN6_PKTINFO)
1311 if (fromlen != sizeof(struct sockaddr_in6))
1313 cmsgptr->cmsg_level = IPPROTO_IPV6;
1314 cmsgptr->cmsg_type = IPV6_PKTINFO;
1315 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
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;
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
1328 if (IN6_IS_ADDR_LINKLOCAL(&from6->sin6_addr))
1329 p->ipi6_ifindex = auxaddr->ipv6_ifindex;
1330 /* otherwise, already zero */
1332 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
1338 return sendmsg(s, &msg, flags);
1342 static void process_packet(void *handle,
1343 struct connection *conn, const char *prog,
1347 socklen_t saddr_len, daddr_len;
1348 krb5_fulladdr faddr;
1349 krb5_error_code retval;
1350 struct sockaddr_storage saddr, daddr;
1353 krb5_data *response;
1354 char pktbuf[MAX_DGRAM_SIZE];
1355 int port_fd = conn->fd;
1356 union aux_addressing_info auxaddr;
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,
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
1373 com_err(prog, errno, "while receiving from network");
1377 return; /* zero-length packet? */
1380 if (daddr_len > 0) {
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);
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
1394 daddr_len = sizeof(daddr);
1395 if (getsockname(port_fd, (struct sockaddr *)&daddr, &daddr_len) != 0)
1397 /* On failure, keep going anyways. */
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)");
1409 if (response == NULL)
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,
1417 * Note that the local address (daddr*) has no port number
1418 * info associated with it.
1420 char saddrbuf[NI_MAXHOST], sportbuf[NI_MAXSERV];
1421 char daddrbuf[NI_MAXHOST];
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));
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));
1435 com_err(prog, e, "while sending reply to %s/%s from %s",
1436 saddrbuf, sportbuf, daddrbuf);
1439 if (cc != response->length) {
1440 com_err(prog, 0, "short reply write %d vs %d\n",
1441 response->length, cc);
1443 krb5_free_data(get_context(handle), response);
1447 static int tcp_or_rpc_data_counter;
1448 static int max_tcp_or_rpc_data_connections = 45;
1450 static void kill_tcp_or_rpc_connection(void *, struct connection *, int isForcedClose);
1452 static int kill_lru_tcp_or_rpc_connection(void *handle, struct connection *newconn)
1454 struct connection *oldest_tcp = NULL;
1455 struct connection *c;
1458 krb5_klog_syslog(LOG_INFO, "too many connections");
1460 FOREACH_ELT (connections, i, c) {
1461 if (c->type != CONN_TCP && c->type != CONN_RPC)
1466 krb5_klog_syslog(LOG_INFO, "fd %d started at %ld", c->fd,
1467 c->u.tcp.start_time);
1469 if (oldest_tcp == NULL
1470 || oldest_tcp->u.tcp.start_time > c->u.tcp.start_time)
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);
1483 static void accept_tcp_connection(void *handle,
1484 struct connection *conn, const char *prog,
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;
1495 s = accept(conn->fd, addr, &addrlen);
1500 if (s >= FD_SETSIZE) {
1505 setnbio(s), setnolinger(s), setkeepalive(s);
1507 sockdata.prog = prog;
1508 sockdata.retval = 0;
1510 newconn = add_tcp_data_fd(&sockdata, s);
1511 if (newconn == NULL)
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));
1521 p = newconn->u.tcp.addrbuf;
1522 end = p + sizeof(newconn->u.tcp.addrbuf);
1524 if (end - p > 2 + strlen(tmpbuf)) {
1526 strlcpy(p, tmpbuf, end - p);
1530 krb5_klog_syslog(LOG_INFO, "accepted TCP connection on socket %d from %s",
1531 s, newconn->u.tcp.addrbuf);
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);
1540 if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
1541 kill_lru_tcp_or_rpc_connection(handle, newconn);
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);
1548 tcp_or_rpc_data_counter--;
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);
1557 FD_SET(s, &sstate.rfds);
1558 if (sstate.max <= s)
1563 kill_tcp_or_rpc_connection(void *handle, struct connection *conn, int isForcedClose)
1565 assert(conn->type == CONN_TCP || conn->type == CONN_RPC);
1566 assert(conn->fd != -1);
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) */
1582 /* In the non-forced case, the RPC runtime will close the descriptor for us */
1583 if (conn->type == CONN_TCP || isForcedClose) {
1587 /* For RPC connections, call into RPC runtime to flush out any internal state */
1588 if (conn->type == CONN_RPC && isForcedClose) {
1592 FD_SET(conn->fd, &fds);
1594 svc_getreqset(&fds);
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);
1604 tcp_or_rpc_data_counter--;
1608 queue_tcp_outgoing_response(struct connection *conn)
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);
1619 process_tcp_connection(void *handle,
1620 struct connection *conn, const char *prog, int selflags)
1622 int isForcedClose = 1; /* not used now, but for completeness */
1624 if (selflags & SSF_WRITE) {
1626 SOCKET_WRITEV_TEMP tmp;
1628 nwrote = SOCKET_WRITEV(conn->fd, conn->u.tcp.sgp, conn->u.tcp.sgnum,
1631 goto kill_tcp_connection;
1636 goto kill_tcp_connection;
1639 sg_buf *sgp = conn->u.tcp.sgp;
1640 if (nwrote < SG_LEN(sgp)) {
1641 SG_ADVANCE(sgp, nwrote);
1644 nwrote -= SG_LEN(sgp);
1646 conn->u.tcp.sgnum--;
1647 if (conn->u.tcp.sgnum == 0 && nwrote != 0)
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
1658 goto kill_tcp_connection;
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. */
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);
1677 goto kill_tcp_connection;
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);
1694 krb5_klog_syslog(LOG_ERR,
1695 "error constructing KRB_ERR_FIELD_TOOLONG error! %s",
1696 error_message(err));
1697 goto kill_tcp_connection;
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;
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);
1715 goto kill_tcp_connection;
1718 goto kill_tcp_connection;
1719 conn->u.tcp.offset += nread;
1720 if (conn->u.tcp.offset < conn->u.tcp.msglen + 4)
1722 /* have a complete message, and exactly one message */
1723 request.length = conn->u.tcp.msglen;
1724 request.data = conn->u.tcp.buffer + 4;
1726 if (getsockname(conn->fd, ss2sa(&local_saddr), &local_saddrlen) == 0) {
1727 local_saddrp = ss2sa(&local_saddr);
1730 err = dispatch(handle, local_saddrp, &conn->u.tcp.faddr,
1731 &request, &conn->u.tcp.response, 1);
1733 com_err(prog, err, "while dispatching (tcp)");
1734 goto kill_tcp_connection;
1737 queue_tcp_outgoing_response(conn);
1738 FD_CLR(conn->fd, &sstate.rfds);
1745 kill_tcp_connection:
1746 kill_tcp_or_rpc_connection(handle, conn, isForcedClose);
1749 static void service_conn(void *handle,
1750 struct connection *conn, const char *prog,
1753 conn->service(handle, conn, prog, selflags);
1756 static int getcurtime(struct timeval *tvp)
1761 tvp->tv_sec = tb.time;
1762 tvp->tv_usec = tb.millitm * 1000;
1765 return gettimeofday(tvp, 0) ? errno : 0;
1770 listen_and_process(void *handle, const char *prog,
1771 void (*reset)(void))
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;
1781 if (conns == (struct connection **) NULL)
1784 while (!signal_requests_exit) {
1785 if (signal_requests_reset) {
1786 krb5_klog_reopen(get_context(handle));
1788 signal_requests_reset = 0;
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
1798 err = getcurtime(&sstate.end_time);
1800 com_err(prog, err, "while getting the time");
1803 sstate.end_time.tv_sec += 3;
1806 sstate.end_time.tv_sec = sstate.end_time.tv_usec = 0;
1808 err = krb5int_cm_call_select(&sstate, &sout, &sret);
1811 com_err(prog, err, "while selecting for network input(1)");
1814 if (sret == 0 && netchanged) {
1815 network_reconfiguration_needed = 0;
1816 closedown_network_sockets();
1817 err = setup_network(handle, prog);
1819 com_err(prog, err, "while reinitializing network");
1826 com_err(prog, errno, "while selecting for network input(2)");
1830 for (i=0; i<n_sockets && nfound > 0; i++) {
1832 if (conns[i]->fd < 0)
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--;
1839 service_conn(handle, conns[i], prog, sflags);
1842 krb5_klog_syslog(LOG_INFO, "shutdown signal received");
1847 closedown_network_sockets()
1850 struct connection *conn;
1852 if (conns == (struct connection **) NULL)
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) {
1863 FD_SET(conn->fd, &fds);
1865 svc_getreqset(&fds);
1868 if (conn->type == CONN_RPC_LISTENER) {
1869 if (conn->u.rpc.transp != NULL)
1870 svc_destroy(conn->u.rpc.transp);
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
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);
1891 static void accept_rpc_connection(void *handle, struct connection *conn,
1892 const char *prog, int selflags)
1894 struct socksetup sockdata;
1898 assert(selflags & SSF_READ);
1900 if ((selflags & SSF_READ) == 0)
1903 sockdata.prog = prog;
1904 sockdata.retval = 0;
1907 * Service the woken RPC listener descriptor.
1910 FD_SET(conn->fd, &fds);
1912 svc_getreqset(&fds);
1915 * Scan svc_fdset for any new connections.
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))
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);
1929 newconn = add_rpc_data_fd(&sockdata, s);
1930 if (newconn == NULL)
1935 setnbio(s), setnolinger(s), setkeepalive(s);
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));
1946 p = newconn->u.tcp.addrbuf;
1947 end = p + sizeof(newconn->u.tcp.addrbuf);
1949 if (end - p > 2 + strlen(tmpbuf)) {
1951 strlcpy(p, tmpbuf, end - p);
1955 krb5_klog_syslog(LOG_INFO, "accepted RPC connection on socket %d from %s",
1956 s, newconn->u.tcp.addrbuf);
1959 newconn->u.tcp.addr_s = addr_s;
1960 newconn->u.tcp.addrlen = addrlen;
1961 newconn->u.tcp.start_time = time(0);
1963 if (++tcp_or_rpc_data_counter > max_tcp_or_rpc_data_connections)
1964 kill_lru_tcp_or_rpc_connection(handle, newconn);
1966 newconn->u.tcp.faddr.address = &newconn->u.tcp.kaddr;
1967 init_addr(&newconn->u.tcp.faddr, ss2sa(&newconn->u.tcp.addr_s));
1969 FD_SET(s, &sstate.rfds);
1970 if (sstate.max <= s)
1976 static void process_rpc_connection(void *handle, struct connection *conn,
1977 const char *prog, int selflags)
1981 assert(selflags & SSF_READ);
1983 if ((selflags & SSF_READ) == 0)
1987 FD_SET(conn->fd, &fds);
1989 svc_getreqset(&fds);
1991 if (!FD_ISSET(conn->fd, &svc_fdset))
1992 kill_tcp_or_rpc_connection(handle, conn, 0);