17c478bd9Sstevel@tonic-gate /*
2*159d09a2SMark Phalan * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
37c478bd9Sstevel@tonic-gate * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate */
57c478bd9Sstevel@tonic-gate
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate * kdc/network.c
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate * Copyright 1990,2000 by the Massachusetts Institute of Technology.
107c478bd9Sstevel@tonic-gate *
117c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may
127c478bd9Sstevel@tonic-gate * require a specific license from the United States Government.
137c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
147c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting.
157c478bd9Sstevel@tonic-gate *
167c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
177c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
187c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
197c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
207c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
217c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
227c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior
237c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label
247c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a
257c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
267c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
277c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
287c478bd9Sstevel@tonic-gate * or implied warranty.
297c478bd9Sstevel@tonic-gate *
307c478bd9Sstevel@tonic-gate *
317c478bd9Sstevel@tonic-gate * Network code for Kerberos v5 KDC.
327c478bd9Sstevel@tonic-gate */
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate #include "k5-int.h"
357c478bd9Sstevel@tonic-gate #include "com_err.h"
367c478bd9Sstevel@tonic-gate #include "kdc_util.h"
377c478bd9Sstevel@tonic-gate #include "extern.h"
387c478bd9Sstevel@tonic-gate #include "kdc5_err.h"
397c478bd9Sstevel@tonic-gate #include "adm_proto.h"
407c478bd9Sstevel@tonic-gate #include <sys/ioctl.h>
417c478bd9Sstevel@tonic-gate #include <syslog.h>
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate #include <stddef.h>
447c478bd9Sstevel@tonic-gate #include <ctype.h>
45*159d09a2SMark Phalan #include "port-sockets.h"
46*159d09a2SMark Phalan /* #include "socket-utils.h" */
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate #ifdef HAVE_NETINET_IN_H
497c478bd9Sstevel@tonic-gate #include <sys/types.h>
507c478bd9Sstevel@tonic-gate #include <netinet/in.h>
517c478bd9Sstevel@tonic-gate #include <sys/socket.h>
527c478bd9Sstevel@tonic-gate #ifdef HAVE_SYS_SOCKIO_H
537c478bd9Sstevel@tonic-gate /* for SIOCGIFCONF, etc. */
547c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
557c478bd9Sstevel@tonic-gate #endif
567c478bd9Sstevel@tonic-gate #include <sys/time.h>
577c478bd9Sstevel@tonic-gate #include <libintl.h>
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate #if HAVE_SYS_SELECT_H
607c478bd9Sstevel@tonic-gate #include <sys/select.h>
617c478bd9Sstevel@tonic-gate #endif
627c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
637c478bd9Sstevel@tonic-gate #include <inet/ip.h>
647c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate #ifndef ARPHRD_ETHER /* OpenBSD breaks on multiple inclusions */
677c478bd9Sstevel@tonic-gate #include <net/if.h>
687c478bd9Sstevel@tonic-gate #endif
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate #ifdef HAVE_SYS_FILIO_H
717c478bd9Sstevel@tonic-gate #include <sys/filio.h> /* FIONBIO */
727c478bd9Sstevel@tonic-gate #endif
737c478bd9Sstevel@tonic-gate
74*159d09a2SMark Phalan #include "fake-addrinfo.h"
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /* Misc utility routines. */
777c478bd9Sstevel@tonic-gate static void
set_sa_port(struct sockaddr * addr,int port)787c478bd9Sstevel@tonic-gate set_sa_port(struct sockaddr *addr, int port)
797c478bd9Sstevel@tonic-gate {
807c478bd9Sstevel@tonic-gate switch (addr->sa_family) {
817c478bd9Sstevel@tonic-gate case AF_INET:
827c478bd9Sstevel@tonic-gate sa2sin(addr)->sin_port = port;
837c478bd9Sstevel@tonic-gate break;
847c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_INET6
857c478bd9Sstevel@tonic-gate case AF_INET6:
867c478bd9Sstevel@tonic-gate sa2sin6(addr)->sin6_port = port;
877c478bd9Sstevel@tonic-gate break;
887c478bd9Sstevel@tonic-gate #endif
897c478bd9Sstevel@tonic-gate default:
907c478bd9Sstevel@tonic-gate break;
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate
ipv6_enabled()9456a424ccSmp153739 static int ipv6_enabled()
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_INET6
977c478bd9Sstevel@tonic-gate static int result = -1;
987c478bd9Sstevel@tonic-gate if (result == -1) {
997c478bd9Sstevel@tonic-gate int s;
1007c478bd9Sstevel@tonic-gate s = socket(AF_INET6, SOCK_STREAM, 0);
1017c478bd9Sstevel@tonic-gate if (s >= 0) {
1027c478bd9Sstevel@tonic-gate result = 1;
1037c478bd9Sstevel@tonic-gate close(s);
1047c478bd9Sstevel@tonic-gate } else
1057c478bd9Sstevel@tonic-gate result = 0;
1067c478bd9Sstevel@tonic-gate }
10756a424ccSmp153739 return result;
1087c478bd9Sstevel@tonic-gate #else
10956a424ccSmp153739 return 0;
1107c478bd9Sstevel@tonic-gate #endif
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate static int
setreuseaddr(int sock,int value)1147c478bd9Sstevel@tonic-gate setreuseaddr(int sock, int value)
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate return setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value));
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate
1197c478bd9Sstevel@tonic-gate #if defined(KRB5_USE_INET6) && defined(IPV6_V6ONLY)
1207c478bd9Sstevel@tonic-gate static int
setv6only(int sock,int value)1217c478bd9Sstevel@tonic-gate setv6only(int sock, int value)
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate return setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
1247c478bd9Sstevel@tonic-gate }
1257c478bd9Sstevel@tonic-gate #endif
1267c478bd9Sstevel@tonic-gate
12756a424ccSmp153739
paddr(struct sockaddr * sa)1287c478bd9Sstevel@tonic-gate static const char *paddr (struct sockaddr *sa)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate static char buf[100];
1317c478bd9Sstevel@tonic-gate char portbuf[10];
1327c478bd9Sstevel@tonic-gate if (getnameinfo(sa, socklen(sa),
1337c478bd9Sstevel@tonic-gate buf, sizeof(buf), portbuf, sizeof(portbuf),
1347c478bd9Sstevel@tonic-gate NI_NUMERICHOST|NI_NUMERICSERV))
1357c478bd9Sstevel@tonic-gate strcpy(buf, "<unprintable>");
1367c478bd9Sstevel@tonic-gate else {
13756a424ccSmp153739 unsigned int len = sizeof(buf) - strlen(buf);
1387c478bd9Sstevel@tonic-gate char *p = buf + strlen(buf);
1397c478bd9Sstevel@tonic-gate if (len > 2+strlen(portbuf)) {
1407c478bd9Sstevel@tonic-gate *p++ = '.';
1417c478bd9Sstevel@tonic-gate len--;
1427c478bd9Sstevel@tonic-gate strncpy(p, portbuf, len);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate return buf;
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate /* KDC data. */
1497c478bd9Sstevel@tonic-gate
15056a424ccSmp153739 enum kdc_conn_type { CONN_UDP, CONN_TCP_LISTENER, CONN_TCP };
15156a424ccSmp153739
1527c478bd9Sstevel@tonic-gate /* Per-connection info. */
1537c478bd9Sstevel@tonic-gate struct connection {
1547c478bd9Sstevel@tonic-gate int fd;
15556a424ccSmp153739 enum kdc_conn_type type;
1567c478bd9Sstevel@tonic-gate void (*service)(struct connection *, const char *, int);
1577c478bd9Sstevel@tonic-gate /* Solaris Kerberos: for auditing */
1587c478bd9Sstevel@tonic-gate in_port_t port; /* local port */
1597c478bd9Sstevel@tonic-gate union {
1607c478bd9Sstevel@tonic-gate /* Type-specific information. */
1617c478bd9Sstevel@tonic-gate struct {
1627c478bd9Sstevel@tonic-gate int x;
1637c478bd9Sstevel@tonic-gate } udp;
1647c478bd9Sstevel@tonic-gate struct {
1657c478bd9Sstevel@tonic-gate int x;
1667c478bd9Sstevel@tonic-gate } tcp_listener;
1677c478bd9Sstevel@tonic-gate struct {
1687c478bd9Sstevel@tonic-gate /* connection */
1697c478bd9Sstevel@tonic-gate struct sockaddr_storage addr_s;
1707c478bd9Sstevel@tonic-gate socklen_t addrlen;
1717c478bd9Sstevel@tonic-gate char addrbuf[56];
1727c478bd9Sstevel@tonic-gate krb5_fulladdr faddr;
1737c478bd9Sstevel@tonic-gate krb5_address kaddr;
1747c478bd9Sstevel@tonic-gate /* incoming */
1757c478bd9Sstevel@tonic-gate size_t bufsiz;
1767c478bd9Sstevel@tonic-gate size_t offset;
1777c478bd9Sstevel@tonic-gate char *buffer;
1787c478bd9Sstevel@tonic-gate size_t msglen;
1797c478bd9Sstevel@tonic-gate /* outgoing */
1807c478bd9Sstevel@tonic-gate krb5_data *response;
1817c478bd9Sstevel@tonic-gate unsigned char lenbuf[4];
1827c478bd9Sstevel@tonic-gate sg_buf sgbuf[2];
1837c478bd9Sstevel@tonic-gate sg_buf *sgp;
1847c478bd9Sstevel@tonic-gate int sgnum;
1857c478bd9Sstevel@tonic-gate /* crude denial-of-service avoidance support */
1867c478bd9Sstevel@tonic-gate time_t start_time;
1877c478bd9Sstevel@tonic-gate } tcp;
1887c478bd9Sstevel@tonic-gate } u;
1897c478bd9Sstevel@tonic-gate };
1907c478bd9Sstevel@tonic-gate
19156a424ccSmp153739
1927c478bd9Sstevel@tonic-gate #define SET(TYPE) struct { TYPE *data; int n, max; }
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate /* Start at the top and work down -- this should allow for deletions
1957c478bd9Sstevel@tonic-gate without disrupting the iteration, since we delete by overwriting
1967c478bd9Sstevel@tonic-gate the element to be removed with the last element. */
1977c478bd9Sstevel@tonic-gate #define FOREACH_ELT(set,idx,vvar) \
1987c478bd9Sstevel@tonic-gate for (idx = set.n-1; idx >= 0 && (vvar = set.data[idx], 1); idx--)
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate #define GROW_SET(set, incr, tmpptr) \
2017c478bd9Sstevel@tonic-gate (((int)(set.max + incr) < set.max \
2027c478bd9Sstevel@tonic-gate || (((size_t)((int)(set.max + incr) * sizeof(set.data[0])) \
2037c478bd9Sstevel@tonic-gate / sizeof(set.data[0])) \
2047c478bd9Sstevel@tonic-gate != (set.max + incr))) \
2057c478bd9Sstevel@tonic-gate ? 0 /* overflow */ \
2067c478bd9Sstevel@tonic-gate : ((tmpptr = realloc(set.data, \
2077c478bd9Sstevel@tonic-gate (int)(set.max + incr) * sizeof(set.data[0]))) \
2087c478bd9Sstevel@tonic-gate ? (set.data = tmpptr, set.max += incr, 1) \
2097c478bd9Sstevel@tonic-gate : 0))
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate /* 1 = success, 0 = failure */
2127c478bd9Sstevel@tonic-gate #define ADD(set, val, tmpptr) \
2137c478bd9Sstevel@tonic-gate ((set.n < set.max || GROW_SET(set, 10, tmpptr)) \
2147c478bd9Sstevel@tonic-gate ? (set.data[set.n++] = val, 1) \
2157c478bd9Sstevel@tonic-gate : 0)
2167c478bd9Sstevel@tonic-gate
2177c478bd9Sstevel@tonic-gate #define DEL(set, idx) \
2187c478bd9Sstevel@tonic-gate (set.data[idx] = set.data[--set.n], 0)
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate #define FREE_SET_DATA(set) if(set.data) free(set.data); \
2217c478bd9Sstevel@tonic-gate (set.data = 0, set.max = 0)
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate /* Set<struct connection *> connections; */
2257c478bd9Sstevel@tonic-gate static SET(struct connection *) connections;
2267c478bd9Sstevel@tonic-gate #define n_sockets connections.n
2277c478bd9Sstevel@tonic-gate #define conns connections.data
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate /* Set<u_short> udp_port_data, tcp_port_data; */
2307c478bd9Sstevel@tonic-gate static SET(u_short) udp_port_data, tcp_port_data;
2317c478bd9Sstevel@tonic-gate
232*159d09a2SMark Phalan #include "cm.h"
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate static struct select_state sstate;
2357c478bd9Sstevel@tonic-gate
add_udp_port(int port)2367c478bd9Sstevel@tonic-gate static krb5_error_code add_udp_port(int port)
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate int i;
2397c478bd9Sstevel@tonic-gate void *tmp;
2407c478bd9Sstevel@tonic-gate u_short val;
2417c478bd9Sstevel@tonic-gate u_short s_port = port;
2427c478bd9Sstevel@tonic-gate
2437c478bd9Sstevel@tonic-gate if (s_port != port)
2447c478bd9Sstevel@tonic-gate return EINVAL;
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate FOREACH_ELT (udp_port_data, i, val)
2477c478bd9Sstevel@tonic-gate if (s_port == val)
2487c478bd9Sstevel@tonic-gate return 0;
2497c478bd9Sstevel@tonic-gate if (!ADD(udp_port_data, s_port, tmp))
2507c478bd9Sstevel@tonic-gate return ENOMEM;
2517c478bd9Sstevel@tonic-gate return 0;
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate
add_tcp_port(int port)2547c478bd9Sstevel@tonic-gate static krb5_error_code add_tcp_port(int port)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate int i;
2577c478bd9Sstevel@tonic-gate void *tmp;
2587c478bd9Sstevel@tonic-gate u_short val;
2597c478bd9Sstevel@tonic-gate u_short s_port = port;
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate if (s_port != port)
2627c478bd9Sstevel@tonic-gate return EINVAL;
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate FOREACH_ELT (tcp_port_data, i, val)
2657c478bd9Sstevel@tonic-gate if (s_port == val)
2667c478bd9Sstevel@tonic-gate return 0;
2677c478bd9Sstevel@tonic-gate if (!ADD(tcp_port_data, s_port, tmp))
2687c478bd9Sstevel@tonic-gate return ENOMEM;
2697c478bd9Sstevel@tonic-gate return 0;
2707c478bd9Sstevel@tonic-gate }
2717c478bd9Sstevel@tonic-gate
27256a424ccSmp153739
2737c478bd9Sstevel@tonic-gate #define USE_AF AF_INET
2747c478bd9Sstevel@tonic-gate #define USE_TYPE SOCK_DGRAM
2757c478bd9Sstevel@tonic-gate #define USE_PROTO 0
2767c478bd9Sstevel@tonic-gate #define SOCKET_ERRNO errno
27756a424ccSmp153739 #include "foreachaddr.h"
2787c478bd9Sstevel@tonic-gate
2797c478bd9Sstevel@tonic-gate struct socksetup {
2807c478bd9Sstevel@tonic-gate const char *prog;
2817c478bd9Sstevel@tonic-gate krb5_error_code retval;
2827c478bd9Sstevel@tonic-gate };
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate static struct connection *
add_fd(struct socksetup * data,int sock,enum kdc_conn_type conntype,void (* service)(struct connection *,const char *,int))28556a424ccSmp153739 add_fd (struct socksetup *data, int sock, enum kdc_conn_type conntype,
2867c478bd9Sstevel@tonic-gate void (*service)(struct connection *, const char *, int))
2877c478bd9Sstevel@tonic-gate {
2887c478bd9Sstevel@tonic-gate struct connection *newconn;
2897c478bd9Sstevel@tonic-gate void *tmp;
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate newconn = malloc(sizeof(*newconn));
2927c478bd9Sstevel@tonic-gate if (newconn == 0) {
2937c478bd9Sstevel@tonic-gate data->retval = errno;
2947c478bd9Sstevel@tonic-gate com_err(data->prog, errno,
2957c478bd9Sstevel@tonic-gate gettext("cannot allocate storage for connection info"));
2967c478bd9Sstevel@tonic-gate return 0;
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate if (!ADD(connections, newconn, tmp)) {
2997c478bd9Sstevel@tonic-gate data->retval = errno;
3007c478bd9Sstevel@tonic-gate com_err(data->prog, data->retval, gettext("cannot save socket info"));
3017c478bd9Sstevel@tonic-gate free(newconn);
3027c478bd9Sstevel@tonic-gate return 0;
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate
3057c478bd9Sstevel@tonic-gate memset(newconn, 0, sizeof(*newconn));
3067c478bd9Sstevel@tonic-gate newconn->type = conntype;
3077c478bd9Sstevel@tonic-gate newconn->fd = sock;
3087c478bd9Sstevel@tonic-gate newconn->service = service;
3097c478bd9Sstevel@tonic-gate return newconn;
3107c478bd9Sstevel@tonic-gate }
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate static void process_packet(struct connection *, const char *, int);
3137c478bd9Sstevel@tonic-gate static void accept_tcp_connection(struct connection *, const char *, int);
3147c478bd9Sstevel@tonic-gate static void process_tcp_connection(struct connection *, const char *, int);
3157c478bd9Sstevel@tonic-gate
3167c478bd9Sstevel@tonic-gate static struct connection *
add_udp_fd(struct socksetup * data,int sock)3177c478bd9Sstevel@tonic-gate add_udp_fd (struct socksetup *data, int sock)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate return add_fd(data, sock, CONN_UDP, process_packet);
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate
3227c478bd9Sstevel@tonic-gate static struct connection *
add_tcp_listener_fd(struct socksetup * data,int sock)3237c478bd9Sstevel@tonic-gate add_tcp_listener_fd (struct socksetup *data, int sock)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate return add_fd(data, sock, CONN_TCP_LISTENER, accept_tcp_connection);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate static struct connection *
add_tcp_data_fd(struct socksetup * data,int sock)3297c478bd9Sstevel@tonic-gate add_tcp_data_fd (struct socksetup *data, int sock)
3307c478bd9Sstevel@tonic-gate {
3317c478bd9Sstevel@tonic-gate return add_fd(data, sock, CONN_TCP, process_tcp_connection);
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate static void
delete_fd(struct connection * xconn)3357c478bd9Sstevel@tonic-gate delete_fd (struct connection *xconn)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate struct connection *conn;
3387c478bd9Sstevel@tonic-gate int i;
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate FOREACH_ELT(connections, i, conn)
3417c478bd9Sstevel@tonic-gate if (conn == xconn) {
3427c478bd9Sstevel@tonic-gate DEL(connections, i);
34356a424ccSmp153739 break;
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate free(xconn);
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate
3487c478bd9Sstevel@tonic-gate static int
setnbio(int sock)3497c478bd9Sstevel@tonic-gate setnbio(int sock)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate static const int one = 1;
3527c478bd9Sstevel@tonic-gate return ioctlsocket(sock, FIONBIO, (const void *)&one);
3537c478bd9Sstevel@tonic-gate }
35456a424ccSmp153739
3557c478bd9Sstevel@tonic-gate static int
setnolinger(int s)3567c478bd9Sstevel@tonic-gate setnolinger(int s)
3577c478bd9Sstevel@tonic-gate {
3587c478bd9Sstevel@tonic-gate static const struct linger ling = { 0, 0 };
3597c478bd9Sstevel@tonic-gate return setsockopt(s, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate
3627c478bd9Sstevel@tonic-gate /* Returns -1 or socket fd. */
3637c478bd9Sstevel@tonic-gate static int
setup_a_tcp_listener(struct socksetup * data,struct sockaddr * addr)3647c478bd9Sstevel@tonic-gate setup_a_tcp_listener(struct socksetup *data, struct sockaddr *addr)
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate int sock;
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate sock = socket(addr->sa_family, SOCK_STREAM, 0);
3697c478bd9Sstevel@tonic-gate if (sock == -1) {
3707c478bd9Sstevel@tonic-gate com_err(data->prog, errno,
3717c478bd9Sstevel@tonic-gate gettext("Cannot create TCP server socket on %s"),
3727c478bd9Sstevel@tonic-gate paddr(addr));
3737c478bd9Sstevel@tonic-gate return -1;
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate * Solaris Kerberos: noticed that there where bind problems for tcp sockets
3777c478bd9Sstevel@tonic-gate * if kdc restarted quickly. Setting SO_REUSEADDR allowed binds to succeed.
3787c478bd9Sstevel@tonic-gate */
3797c478bd9Sstevel@tonic-gate if (setreuseaddr(sock, 1) < 0) {
3807c478bd9Sstevel@tonic-gate com_err(data->prog, errno,
3817c478bd9Sstevel@tonic-gate gettext("enabling SO_REUSEADDR on TCP socket"));
3827c478bd9Sstevel@tonic-gate close(sock);
3837c478bd9Sstevel@tonic-gate return -1;
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate if (bind(sock, addr, socklen(addr)) == -1) {
3867c478bd9Sstevel@tonic-gate com_err(data->prog, errno,
3877c478bd9Sstevel@tonic-gate gettext("Cannot bind TCP server socket on %s"), paddr(addr));
3887c478bd9Sstevel@tonic-gate close(sock);
3897c478bd9Sstevel@tonic-gate return -1;
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate if (listen(sock, 5) < 0) {
3927c478bd9Sstevel@tonic-gate com_err(data->prog, errno,
3937c478bd9Sstevel@tonic-gate gettext("Cannot listen on TCP server socket on %s"),
3947c478bd9Sstevel@tonic-gate paddr(addr));
3957c478bd9Sstevel@tonic-gate close(sock);
3967c478bd9Sstevel@tonic-gate return -1;
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate if (setnbio(sock)) {
3997c478bd9Sstevel@tonic-gate com_err(data->prog, errno,
4007c478bd9Sstevel@tonic-gate gettext("cannot set listening tcp socket on %s non-blocking"),
4017c478bd9Sstevel@tonic-gate paddr(addr));
4027c478bd9Sstevel@tonic-gate close(sock);
4037c478bd9Sstevel@tonic-gate return -1;
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate if (setnolinger(sock)) {
4067c478bd9Sstevel@tonic-gate com_err(data->prog, errno,
4077c478bd9Sstevel@tonic-gate gettext("disabling SO_LINGER on TCP socket on %s"),
4087c478bd9Sstevel@tonic-gate paddr(addr));
4097c478bd9Sstevel@tonic-gate close(sock);
4107c478bd9Sstevel@tonic-gate return -1;
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate return sock;
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate
4157c478bd9Sstevel@tonic-gate static int
setup_tcp_listener_ports(struct socksetup * data)4167c478bd9Sstevel@tonic-gate setup_tcp_listener_ports(struct socksetup *data)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate struct sockaddr_in sin4;
4197c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_INET6
4207c478bd9Sstevel@tonic-gate struct sockaddr_in6 sin6;
4217c478bd9Sstevel@tonic-gate #endif
4227c478bd9Sstevel@tonic-gate int i, port;
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate memset(&sin4, 0, sizeof(sin4));
4257c478bd9Sstevel@tonic-gate sin4.sin_family = AF_INET;
4267c478bd9Sstevel@tonic-gate #ifdef HAVE_SA_LEN
4277c478bd9Sstevel@tonic-gate sin4.sin_len = sizeof(sin4);
4287c478bd9Sstevel@tonic-gate #endif
4297c478bd9Sstevel@tonic-gate sin4.sin_addr.s_addr = INADDR_ANY;
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_INET6
4327c478bd9Sstevel@tonic-gate memset(&sin6, 0, sizeof(sin6));
4337c478bd9Sstevel@tonic-gate sin6.sin6_family = AF_INET6;
4347c478bd9Sstevel@tonic-gate #ifdef SIN6_LEN
4357c478bd9Sstevel@tonic-gate sin6.sin6_len = sizeof(sin6);
4367c478bd9Sstevel@tonic-gate #endif
4377c478bd9Sstevel@tonic-gate sin6.sin6_addr = in6addr_any;
4387c478bd9Sstevel@tonic-gate #endif
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate FOREACH_ELT (tcp_port_data, i, port) {
4417c478bd9Sstevel@tonic-gate int s4, s6;
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate set_sa_port((struct sockaddr *)&sin4, htons(port));
4447c478bd9Sstevel@tonic-gate if (!ipv6_enabled()) {
4457c478bd9Sstevel@tonic-gate s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
4467c478bd9Sstevel@tonic-gate if (s4 < 0)
4477c478bd9Sstevel@tonic-gate return -1;
4487c478bd9Sstevel@tonic-gate s6 = -1;
4497c478bd9Sstevel@tonic-gate } else {
4507c478bd9Sstevel@tonic-gate #ifndef KRB5_USE_INET6
4517c478bd9Sstevel@tonic-gate abort();
4527c478bd9Sstevel@tonic-gate #else
4537c478bd9Sstevel@tonic-gate s4 = s6 = -1;
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate set_sa_port((struct sockaddr *)&sin6, htons(port));
4567c478bd9Sstevel@tonic-gate
4577c478bd9Sstevel@tonic-gate s6 = setup_a_tcp_listener(data, (struct sockaddr *)&sin6);
4587c478bd9Sstevel@tonic-gate if (s6 < 0)
4597c478bd9Sstevel@tonic-gate return -1;
4607c478bd9Sstevel@tonic-gate #ifdef IPV6_V6ONLY
4617c478bd9Sstevel@tonic-gate if (setv6only(s6, 0))
4627c478bd9Sstevel@tonic-gate com_err(data->prog, errno,
4637c478bd9Sstevel@tonic-gate gettext("setsockopt(IPV6_V6ONLY,0) failed"));
4647c478bd9Sstevel@tonic-gate #endif
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate s4 = setup_a_tcp_listener(data, (struct sockaddr *)&sin4);
4677c478bd9Sstevel@tonic-gate #endif /* KRB5_USE_INET6 */
4687c478bd9Sstevel@tonic-gate }
4697c478bd9Sstevel@tonic-gate
4707c478bd9Sstevel@tonic-gate /* Sockets are created, prepare to listen on them. */
4717c478bd9Sstevel@tonic-gate if (s4 >= 0) {
4727c478bd9Sstevel@tonic-gate FD_SET(s4, &sstate.rfds);
4737c478bd9Sstevel@tonic-gate if (s4 >= sstate.max)
4747c478bd9Sstevel@tonic-gate sstate.max = s4 + 1;
4757c478bd9Sstevel@tonic-gate if (add_tcp_listener_fd(data, s4) == 0)
4767c478bd9Sstevel@tonic-gate close(s4);
4777c478bd9Sstevel@tonic-gate else
47856a424ccSmp153739 krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s",
47956a424ccSmp153739 s4, paddr((struct sockaddr *)&sin4));
4807c478bd9Sstevel@tonic-gate }
4817c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_INET6
4827c478bd9Sstevel@tonic-gate if (s6 >= 0) {
4837c478bd9Sstevel@tonic-gate FD_SET(s6, &sstate.rfds);
4847c478bd9Sstevel@tonic-gate if (s6 >= sstate.max)
4857c478bd9Sstevel@tonic-gate sstate.max = s6 + 1;
4867c478bd9Sstevel@tonic-gate if (add_tcp_listener_fd(data, s6) == 0) {
4877c478bd9Sstevel@tonic-gate close(s6);
4887c478bd9Sstevel@tonic-gate s6 = -1;
4897c478bd9Sstevel@tonic-gate } else
49056a424ccSmp153739 krb5_klog_syslog(LOG_INFO, "listening on fd %d: tcp %s",
49156a424ccSmp153739 s6, paddr((struct sockaddr *)&sin6));
4927c478bd9Sstevel@tonic-gate if (s4 < 0)
4937c478bd9Sstevel@tonic-gate krb5_klog_syslog(LOG_INFO,
4947c478bd9Sstevel@tonic-gate "assuming IPv6 socket accepts IPv4");
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate #endif
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate return 0;
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate static int
setup_udp_port(void * P_data,struct sockaddr * addr)5027c478bd9Sstevel@tonic-gate setup_udp_port(void *P_data, struct sockaddr *addr)
5037c478bd9Sstevel@tonic-gate {
5047c478bd9Sstevel@tonic-gate struct socksetup *data = P_data;
5057c478bd9Sstevel@tonic-gate int sock = -1, i;
5067c478bd9Sstevel@tonic-gate char haddrbuf[NI_MAXHOST];
5077c478bd9Sstevel@tonic-gate int err;
5087c478bd9Sstevel@tonic-gate u_short port;
5097c478bd9Sstevel@tonic-gate
5107c478bd9Sstevel@tonic-gate err = getnameinfo(addr, socklen(addr), haddrbuf, sizeof(haddrbuf),
5117c478bd9Sstevel@tonic-gate 0, 0, NI_NUMERICHOST);
5127c478bd9Sstevel@tonic-gate if (err)
5137c478bd9Sstevel@tonic-gate strcpy(haddrbuf, "<unprintable>");
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate switch (addr->sa_family) {
5167c478bd9Sstevel@tonic-gate case AF_INET:
5177c478bd9Sstevel@tonic-gate break;
5187c478bd9Sstevel@tonic-gate #ifdef AF_INET6
5197c478bd9Sstevel@tonic-gate case AF_INET6:
5207c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_INET6
5217c478bd9Sstevel@tonic-gate break;
5227c478bd9Sstevel@tonic-gate #else
5237c478bd9Sstevel@tonic-gate {
5247c478bd9Sstevel@tonic-gate static int first = 1;
5257c478bd9Sstevel@tonic-gate if (first) {
5267c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_INFO, "skipping local ipv6 addresses");
5277c478bd9Sstevel@tonic-gate first = 0;
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate return 0;
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate #endif
5327c478bd9Sstevel@tonic-gate #endif
5337c478bd9Sstevel@tonic-gate #ifdef AF_LINK /* some BSD systems, AIX */
5347c478bd9Sstevel@tonic-gate case AF_LINK:
5357c478bd9Sstevel@tonic-gate return 0;
5367c478bd9Sstevel@tonic-gate #endif
53756a424ccSmp153739 #ifdef AF_DLI /* Direct Link Interface - DEC Ultrix/OSF1 link layer? */
53856a424ccSmp153739 case AF_DLI:
53956a424ccSmp153739 return 0;
54056a424ccSmp153739 #endif
5417c478bd9Sstevel@tonic-gate default:
5427c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_INFO,
5437c478bd9Sstevel@tonic-gate "skipping unrecognized local address family %d",
5447c478bd9Sstevel@tonic-gate addr->sa_family);
5457c478bd9Sstevel@tonic-gate return 0;
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate FOREACH_ELT (udp_port_data, i, port) {
5497c478bd9Sstevel@tonic-gate sock = socket (addr->sa_family, SOCK_DGRAM, 0);
5507c478bd9Sstevel@tonic-gate if (sock == -1) {
5517c478bd9Sstevel@tonic-gate data->retval = errno;
5527c478bd9Sstevel@tonic-gate com_err(data->prog, data->retval,
5537c478bd9Sstevel@tonic-gate gettext("Cannot create server socket for port %d address %s"),
5547c478bd9Sstevel@tonic-gate port, haddrbuf);
5557c478bd9Sstevel@tonic-gate return 1;
5567c478bd9Sstevel@tonic-gate }
5577c478bd9Sstevel@tonic-gate set_sa_port(addr, htons(port));
5587c478bd9Sstevel@tonic-gate if (bind (sock, (struct sockaddr *)addr, socklen (addr)) == -1) {
5597c478bd9Sstevel@tonic-gate data->retval = errno;
5607c478bd9Sstevel@tonic-gate com_err(data->prog, data->retval,
5617c478bd9Sstevel@tonic-gate gettext("Cannot bind server socket to port %d address %s"),
5627c478bd9Sstevel@tonic-gate port, haddrbuf);
5637c478bd9Sstevel@tonic-gate return 1;
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate FD_SET (sock, &sstate.rfds);
5667c478bd9Sstevel@tonic-gate if (sock >= sstate.max)
5677c478bd9Sstevel@tonic-gate sstate.max = sock + 1;
56856a424ccSmp153739 krb5_klog_syslog (LOG_INFO, "listening on fd %d: udp %s", sock,
56956a424ccSmp153739 paddr((struct sockaddr *)addr));
5707c478bd9Sstevel@tonic-gate if (add_udp_fd (data, sock) == 0)
5717c478bd9Sstevel@tonic-gate return 1;
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate return 0;
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate #if 1
klog_handler(const void * data,size_t len)5777c478bd9Sstevel@tonic-gate static void klog_handler(const void *data, size_t len)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate static char buf[BUFSIZ];
5807c478bd9Sstevel@tonic-gate static int bufoffset;
5817c478bd9Sstevel@tonic-gate void *p;
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate #define flush_buf() \
5847c478bd9Sstevel@tonic-gate (bufoffset \
5857c478bd9Sstevel@tonic-gate ? (((buf[0] == 0 || buf[0] == '\n') \
5867c478bd9Sstevel@tonic-gate ? (fork()==0?abort():(void)0) \
5877c478bd9Sstevel@tonic-gate : (void)0), \
5887c478bd9Sstevel@tonic-gate krb5_klog_syslog(LOG_INFO, "%s", buf), \
5897c478bd9Sstevel@tonic-gate memset(buf, 0, sizeof(buf)), \
5907c478bd9Sstevel@tonic-gate bufoffset = 0) \
5917c478bd9Sstevel@tonic-gate : 0)
5927c478bd9Sstevel@tonic-gate
5937c478bd9Sstevel@tonic-gate p = memchr(data, 0, len);
5947c478bd9Sstevel@tonic-gate if (p)
5957c478bd9Sstevel@tonic-gate len = (const char *)p - (const char *)data;
5967c478bd9Sstevel@tonic-gate scan_for_newlines:
5977c478bd9Sstevel@tonic-gate if (len == 0)
5987c478bd9Sstevel@tonic-gate return;
5997c478bd9Sstevel@tonic-gate p = memchr(data, '\n', len);
6007c478bd9Sstevel@tonic-gate if (p) {
6017c478bd9Sstevel@tonic-gate if (p != data)
6027c478bd9Sstevel@tonic-gate klog_handler(data, (size_t)((const char *)p - (const char *)data));
6037c478bd9Sstevel@tonic-gate flush_buf();
6047c478bd9Sstevel@tonic-gate len -= ((const char *)p - (const char *)data) + 1;
6057c478bd9Sstevel@tonic-gate data = 1 + (const char *)p;
6067c478bd9Sstevel@tonic-gate goto scan_for_newlines;
6077c478bd9Sstevel@tonic-gate } else if (len > sizeof(buf) - 1 || len + bufoffset > sizeof(buf) - 1) {
6087c478bd9Sstevel@tonic-gate size_t x = sizeof(buf) - len - 1;
6097c478bd9Sstevel@tonic-gate klog_handler(data, x);
6107c478bd9Sstevel@tonic-gate flush_buf();
6117c478bd9Sstevel@tonic-gate len -= x;
6127c478bd9Sstevel@tonic-gate data = (const char *)data + x;
6137c478bd9Sstevel@tonic-gate goto scan_for_newlines;
6147c478bd9Sstevel@tonic-gate } else {
6157c478bd9Sstevel@tonic-gate memcpy(buf + bufoffset, data, len);
6167c478bd9Sstevel@tonic-gate bufoffset += len;
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate }
6197c478bd9Sstevel@tonic-gate #endif
6207c478bd9Sstevel@tonic-gate
62156a424ccSmp153739 /* XXX */
62256a424ccSmp153739 extern int krb5int_debug_sendto_kdc;
6237c478bd9Sstevel@tonic-gate extern void (*krb5int_sendtokdc_debug_handler)(const void*, size_t);
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate krb5_error_code
setup_network(const char * prog)6267c478bd9Sstevel@tonic-gate setup_network(const char *prog)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate struct socksetup setup_data;
6297c478bd9Sstevel@tonic-gate krb5_error_code retval;
6307c478bd9Sstevel@tonic-gate char *cp;
6317c478bd9Sstevel@tonic-gate int i, port;
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate FD_ZERO(&sstate.rfds);
6347c478bd9Sstevel@tonic-gate FD_ZERO(&sstate.wfds);
6357c478bd9Sstevel@tonic-gate FD_ZERO(&sstate.xfds);
6367c478bd9Sstevel@tonic-gate sstate.max = 0;
6377c478bd9Sstevel@tonic-gate
63856a424ccSmp153739 /* krb5int_debug_sendto_kdc = 1; */
6397c478bd9Sstevel@tonic-gate krb5int_sendtokdc_debug_handler = klog_handler;
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate /* Handle each realm's ports */
6427c478bd9Sstevel@tonic-gate for (i=0; i<kdc_numrealms; i++) {
6437c478bd9Sstevel@tonic-gate cp = kdc_realmlist[i]->realm_ports;
6447c478bd9Sstevel@tonic-gate while (cp && *cp) {
6457c478bd9Sstevel@tonic-gate if (*cp == ',' || isspace((int) *cp)) {
6467c478bd9Sstevel@tonic-gate cp++;
6477c478bd9Sstevel@tonic-gate continue;
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate port = strtol(cp, &cp, 10);
6507c478bd9Sstevel@tonic-gate if (cp == 0)
6517c478bd9Sstevel@tonic-gate break;
6527c478bd9Sstevel@tonic-gate retval = add_udp_port(port);
6537c478bd9Sstevel@tonic-gate if (retval)
6547c478bd9Sstevel@tonic-gate return retval;
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate cp = kdc_realmlist[i]->realm_tcp_ports;
6587c478bd9Sstevel@tonic-gate while (cp && *cp) {
6597c478bd9Sstevel@tonic-gate if (*cp == ',' || isspace((int) *cp)) {
6607c478bd9Sstevel@tonic-gate cp++;
6617c478bd9Sstevel@tonic-gate continue;
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate port = strtol(cp, &cp, 10);
6647c478bd9Sstevel@tonic-gate if (cp == 0)
6657c478bd9Sstevel@tonic-gate break;
6667c478bd9Sstevel@tonic-gate retval = add_tcp_port(port);
6677c478bd9Sstevel@tonic-gate if (retval)
6687c478bd9Sstevel@tonic-gate return retval;
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate
6727c478bd9Sstevel@tonic-gate setup_data.prog = prog;
6737c478bd9Sstevel@tonic-gate setup_data.retval = 0;
6747c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_INFO, "setting up network...");
6757c478bd9Sstevel@tonic-gate /* To do: Use RFC 2292 interface (or follow-on) and IPV6_PKTINFO,
6767c478bd9Sstevel@tonic-gate so we might need only one UDP socket; fall back to binding
6777c478bd9Sstevel@tonic-gate sockets on each address only if IPV6_PKTINFO isn't
6787c478bd9Sstevel@tonic-gate supported. */
6797c478bd9Sstevel@tonic-gate if (foreach_localaddr (&setup_data, setup_udp_port, 0, 0)) {
6807c478bd9Sstevel@tonic-gate return setup_data.retval;
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate setup_tcp_listener_ports(&setup_data);
6837c478bd9Sstevel@tonic-gate krb5_klog_syslog (LOG_INFO, "set up %d sockets", n_sockets);
6847c478bd9Sstevel@tonic-gate if (n_sockets == 0) {
6857c478bd9Sstevel@tonic-gate com_err(prog, 0, gettext("no sockets set up?"));
6867c478bd9Sstevel@tonic-gate exit (1);
6877c478bd9Sstevel@tonic-gate }
6887c478bd9Sstevel@tonic-gate
6897c478bd9Sstevel@tonic-gate return 0;
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate
init_addr(krb5_fulladdr * faddr,struct sockaddr * sa)6927c478bd9Sstevel@tonic-gate static void init_addr(krb5_fulladdr *faddr, struct sockaddr *sa)
6937c478bd9Sstevel@tonic-gate {
6947c478bd9Sstevel@tonic-gate switch (sa->sa_family) {
6957c478bd9Sstevel@tonic-gate case AF_INET:
6967c478bd9Sstevel@tonic-gate faddr->address->addrtype = ADDRTYPE_INET;
6977c478bd9Sstevel@tonic-gate faddr->address->length = IPV4_ADDR_LEN;
6987c478bd9Sstevel@tonic-gate faddr->address->contents = (krb5_octet *) &sa2sin(sa)->sin_addr;
6997c478bd9Sstevel@tonic-gate faddr->port = ntohs(sa2sin(sa)->sin_port);
7007c478bd9Sstevel@tonic-gate break;
7017c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_INET6
7027c478bd9Sstevel@tonic-gate case AF_INET6:
7037c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sa2sin6(sa)->sin6_addr)) {
7047c478bd9Sstevel@tonic-gate faddr->address->addrtype = ADDRTYPE_INET;
7057c478bd9Sstevel@tonic-gate faddr->address->length = IPV4_ADDR_LEN;
7067c478bd9Sstevel@tonic-gate /* offset to RAM address of ipv4 part of ipv6 address */
7077c478bd9Sstevel@tonic-gate faddr->address->contents = (IPV6_ADDR_LEN - IPV4_ADDR_LEN) +
7087c478bd9Sstevel@tonic-gate (krb5_octet *) &sa2sin6(sa)->sin6_addr;
7097c478bd9Sstevel@tonic-gate } else {
7107c478bd9Sstevel@tonic-gate faddr->address->addrtype = ADDRTYPE_INET6;
7117c478bd9Sstevel@tonic-gate faddr->address->length = IPV6_ADDR_LEN;
7127c478bd9Sstevel@tonic-gate faddr->address->contents = (krb5_octet *) &sa2sin6(sa)->sin6_addr;
7137c478bd9Sstevel@tonic-gate }
7147c478bd9Sstevel@tonic-gate faddr->port = ntohs(sa2sin6(sa)->sin6_port);
7157c478bd9Sstevel@tonic-gate break;
7167c478bd9Sstevel@tonic-gate #endif
7177c478bd9Sstevel@tonic-gate default:
7187c478bd9Sstevel@tonic-gate faddr->address->addrtype = -1;
7197c478bd9Sstevel@tonic-gate faddr->address->length = 0;
7207c478bd9Sstevel@tonic-gate faddr->address->contents = 0;
7217c478bd9Sstevel@tonic-gate faddr->port = 0;
7227c478bd9Sstevel@tonic-gate break;
7237c478bd9Sstevel@tonic-gate }
7247c478bd9Sstevel@tonic-gate }
7257c478bd9Sstevel@tonic-gate
process_packet(struct connection * conn,const char * prog,int selflags)7267c478bd9Sstevel@tonic-gate static void process_packet(struct connection *conn, const char *prog,
7277c478bd9Sstevel@tonic-gate int selflags)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate int cc;
7307c478bd9Sstevel@tonic-gate socklen_t saddr_len;
7317c478bd9Sstevel@tonic-gate krb5_fulladdr faddr;
7327c478bd9Sstevel@tonic-gate krb5_error_code retval;
7337c478bd9Sstevel@tonic-gate struct sockaddr_storage saddr;
7347c478bd9Sstevel@tonic-gate krb5_address addr;
7357c478bd9Sstevel@tonic-gate krb5_data request;
7367c478bd9Sstevel@tonic-gate krb5_data *response;
7377c478bd9Sstevel@tonic-gate char pktbuf[MAX_DGRAM_SIZE];
7387c478bd9Sstevel@tonic-gate int port_fd = conn->fd;
7397c478bd9Sstevel@tonic-gate
7406cf54e34Sbugbomb response = NULL;
7417c478bd9Sstevel@tonic-gate saddr_len = sizeof(saddr);
7427c478bd9Sstevel@tonic-gate cc = recvfrom(port_fd, pktbuf, sizeof(pktbuf), 0,
7437c478bd9Sstevel@tonic-gate (struct sockaddr *)&saddr, &saddr_len);
7447c478bd9Sstevel@tonic-gate if (cc == -1) {
7457c478bd9Sstevel@tonic-gate if (errno != EINTR
7467c478bd9Sstevel@tonic-gate /* This is how Linux indicates that a previous
7477c478bd9Sstevel@tonic-gate transmission was refused, e.g., if the client timed out
7487c478bd9Sstevel@tonic-gate before getting the response packet. */
7497c478bd9Sstevel@tonic-gate && errno != ECONNREFUSED
7507c478bd9Sstevel@tonic-gate )
7517c478bd9Sstevel@tonic-gate com_err(prog, errno, gettext("while receiving from network"));
7527c478bd9Sstevel@tonic-gate return;
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate if (!cc)
7557c478bd9Sstevel@tonic-gate return; /* zero-length packet? */
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate request.length = cc;
7587c478bd9Sstevel@tonic-gate request.data = pktbuf;
7597c478bd9Sstevel@tonic-gate faddr.address = &addr;
7607c478bd9Sstevel@tonic-gate init_addr(&faddr, ss2sa(&saddr));
7617c478bd9Sstevel@tonic-gate /* this address is in net order */
76256a424ccSmp153739 if ((retval = dispatch(&request, &faddr, &response))) {
7637c478bd9Sstevel@tonic-gate com_err(prog, retval, gettext("while dispatching (udp)"));
7647c478bd9Sstevel@tonic-gate return;
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate cc = sendto(port_fd, response->data, (socklen_t) response->length, 0,
7677c478bd9Sstevel@tonic-gate (struct sockaddr *)&saddr, saddr_len);
7687c478bd9Sstevel@tonic-gate if (cc == -1) {
7697c478bd9Sstevel@tonic-gate char addrbuf[46];
7707c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, response);
7717c478bd9Sstevel@tonic-gate if (inet_ntop(((struct sockaddr *)&saddr)->sa_family,
7727c478bd9Sstevel@tonic-gate addr.contents, addrbuf, sizeof(addrbuf)) == 0) {
7737c478bd9Sstevel@tonic-gate strcpy(addrbuf, "?");
7747c478bd9Sstevel@tonic-gate }
7757c478bd9Sstevel@tonic-gate com_err(prog, errno, gettext("while sending reply to %s/%d"),
7767c478bd9Sstevel@tonic-gate addrbuf, faddr.port);
7777c478bd9Sstevel@tonic-gate return;
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate if (cc != response->length) {
7807c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, response);
7817c478bd9Sstevel@tonic-gate com_err(prog, 0, gettext("short reply write %d vs %d\n"),
7827c478bd9Sstevel@tonic-gate response->length, cc);
7837c478bd9Sstevel@tonic-gate return;
7847c478bd9Sstevel@tonic-gate }
7857c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, response);
7867c478bd9Sstevel@tonic-gate return;
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate static int tcp_data_counter;
7907c478bd9Sstevel@tonic-gate /* Solaris kerberos: getting this value from elsewhere */
7917c478bd9Sstevel@tonic-gate extern int max_tcp_data_connections;
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate static void kill_tcp_connection(struct connection *);
7947c478bd9Sstevel@tonic-gate
accept_tcp_connection(struct connection * conn,const char * prog,int selflags)7957c478bd9Sstevel@tonic-gate static void accept_tcp_connection(struct connection *conn, const char *prog,
7967c478bd9Sstevel@tonic-gate int selflags)
7977c478bd9Sstevel@tonic-gate {
7987c478bd9Sstevel@tonic-gate int s;
7997c478bd9Sstevel@tonic-gate struct sockaddr_storage addr_s;
8007c478bd9Sstevel@tonic-gate struct sockaddr *addr = (struct sockaddr *)&addr_s;
8017c478bd9Sstevel@tonic-gate socklen_t addrlen = sizeof(addr_s);
8027c478bd9Sstevel@tonic-gate struct socksetup sockdata;
8037c478bd9Sstevel@tonic-gate struct connection *newconn;
8047c478bd9Sstevel@tonic-gate char tmpbuf[10];
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate s = accept(conn->fd, addr, &addrlen);
8077c478bd9Sstevel@tonic-gate if (s < 0)
8087c478bd9Sstevel@tonic-gate return;
8097c478bd9Sstevel@tonic-gate setnbio(s), setnolinger(s);
8107c478bd9Sstevel@tonic-gate
8117c478bd9Sstevel@tonic-gate sockdata.prog = prog;
8127c478bd9Sstevel@tonic-gate sockdata.retval = 0;
8137c478bd9Sstevel@tonic-gate
8147c478bd9Sstevel@tonic-gate newconn = add_tcp_data_fd(&sockdata, s);
8157c478bd9Sstevel@tonic-gate if (newconn == 0)
8167c478bd9Sstevel@tonic-gate return;
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate if (getnameinfo((struct sockaddr *)&addr_s, addrlen,
8197c478bd9Sstevel@tonic-gate newconn->u.tcp.addrbuf, sizeof(newconn->u.tcp.addrbuf),
8207c478bd9Sstevel@tonic-gate tmpbuf, sizeof(tmpbuf),
8217c478bd9Sstevel@tonic-gate NI_NUMERICHOST | NI_NUMERICSERV))
8227c478bd9Sstevel@tonic-gate strcpy(newconn->u.tcp.addrbuf, "???");
8237c478bd9Sstevel@tonic-gate else {
8247c478bd9Sstevel@tonic-gate char *p, *end;
8257c478bd9Sstevel@tonic-gate p = newconn->u.tcp.addrbuf;
8267c478bd9Sstevel@tonic-gate end = p + sizeof(newconn->u.tcp.addrbuf);
8277c478bd9Sstevel@tonic-gate p += strlen(p);
8287c478bd9Sstevel@tonic-gate if (end - p > 2 + strlen(tmpbuf)) {
8297c478bd9Sstevel@tonic-gate *p++ = '.';
8307c478bd9Sstevel@tonic-gate strcpy(p, tmpbuf);
8317c478bd9Sstevel@tonic-gate }
8327c478bd9Sstevel@tonic-gate }
83356a424ccSmp153739 #if 0
83456a424ccSmp153739 krb5_klog_syslog(LOG_INFO, "accepted TCP connection on socket %d from %s",
83556a424ccSmp153739 s, newconn->u.tcp.addrbuf);
83656a424ccSmp153739 #endif
8377c478bd9Sstevel@tonic-gate
8387c478bd9Sstevel@tonic-gate newconn->u.tcp.addr_s = addr_s;
8397c478bd9Sstevel@tonic-gate newconn->u.tcp.addrlen = addrlen;
8407c478bd9Sstevel@tonic-gate newconn->u.tcp.bufsiz = 1024 * 1024;
8417c478bd9Sstevel@tonic-gate newconn->u.tcp.buffer = malloc(newconn->u.tcp.bufsiz);
8427c478bd9Sstevel@tonic-gate newconn->u.tcp.start_time = time(0);
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate if (++tcp_data_counter > max_tcp_data_connections) {
8457c478bd9Sstevel@tonic-gate struct connection *oldest_tcp = NULL;
8467c478bd9Sstevel@tonic-gate struct connection *c;
8477c478bd9Sstevel@tonic-gate int i;
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate krb5_klog_syslog(LOG_INFO, "too many connections");
8507c478bd9Sstevel@tonic-gate
8517c478bd9Sstevel@tonic-gate FOREACH_ELT (connections, i, c) {
8527c478bd9Sstevel@tonic-gate if (c->type != CONN_TCP)
8537c478bd9Sstevel@tonic-gate continue;
8547c478bd9Sstevel@tonic-gate if (c == newconn)
8557c478bd9Sstevel@tonic-gate continue;
8567c478bd9Sstevel@tonic-gate #if 0
8577c478bd9Sstevel@tonic-gate krb5_klog_syslog(LOG_INFO, "fd %d started at %ld", c->fd,
8587c478bd9Sstevel@tonic-gate c->u.tcp.start_time);
8597c478bd9Sstevel@tonic-gate #endif
8607c478bd9Sstevel@tonic-gate if (oldest_tcp == NULL
8617c478bd9Sstevel@tonic-gate || oldest_tcp->u.tcp.start_time > c->u.tcp.start_time)
8627c478bd9Sstevel@tonic-gate oldest_tcp = c;
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate if (oldest_tcp != NULL) {
8657c478bd9Sstevel@tonic-gate krb5_klog_syslog(LOG_INFO, "dropping tcp fd %d from %s",
8667c478bd9Sstevel@tonic-gate oldest_tcp->fd, oldest_tcp->u.tcp.addrbuf);
8677c478bd9Sstevel@tonic-gate kill_tcp_connection(oldest_tcp);
8687c478bd9Sstevel@tonic-gate oldest_tcp = NULL;
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate if (newconn->u.tcp.buffer == 0) {
8727c478bd9Sstevel@tonic-gate com_err(prog, errno, gettext("allocating buffer for new TCP session from %s"),
8737c478bd9Sstevel@tonic-gate newconn->u.tcp.addrbuf);
8747c478bd9Sstevel@tonic-gate delete_fd(newconn);
8757c478bd9Sstevel@tonic-gate close(s);
87656a424ccSmp153739 tcp_data_counter--;
8777c478bd9Sstevel@tonic-gate return;
8787c478bd9Sstevel@tonic-gate }
8797c478bd9Sstevel@tonic-gate newconn->u.tcp.offset = 0;
8807c478bd9Sstevel@tonic-gate newconn->u.tcp.faddr.address = &newconn->u.tcp.kaddr;
8817c478bd9Sstevel@tonic-gate init_addr(&newconn->u.tcp.faddr, ss2sa(&newconn->u.tcp.addr_s));
8827c478bd9Sstevel@tonic-gate SG_SET(&newconn->u.tcp.sgbuf[0], newconn->u.tcp.lenbuf, 4);
8837c478bd9Sstevel@tonic-gate SG_SET(&newconn->u.tcp.sgbuf[1], 0, 0);
8847c478bd9Sstevel@tonic-gate
8857c478bd9Sstevel@tonic-gate FD_SET(s, &sstate.rfds);
8867c478bd9Sstevel@tonic-gate if (sstate.max <= s)
8877c478bd9Sstevel@tonic-gate sstate.max = s + 1;
8887c478bd9Sstevel@tonic-gate }
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate static void
kill_tcp_connection(struct connection * conn)8917c478bd9Sstevel@tonic-gate kill_tcp_connection(struct connection *conn)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate if (conn->u.tcp.response)
8947c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, conn->u.tcp.response);
8957c478bd9Sstevel@tonic-gate if (conn->u.tcp.buffer)
8967c478bd9Sstevel@tonic-gate free(conn->u.tcp.buffer);
8977c478bd9Sstevel@tonic-gate FD_CLR(conn->fd, &sstate.rfds);
8987c478bd9Sstevel@tonic-gate FD_CLR(conn->fd, &sstate.wfds);
8997c478bd9Sstevel@tonic-gate if (sstate.max == conn->fd + 1)
9007c478bd9Sstevel@tonic-gate while (sstate.max > 0
9017c478bd9Sstevel@tonic-gate && ! FD_ISSET(sstate.max-1, &sstate.rfds)
9027c478bd9Sstevel@tonic-gate && ! FD_ISSET(sstate.max-1, &sstate.wfds)
9037c478bd9Sstevel@tonic-gate /* && ! FD_ISSET(sstate.max-1, &sstate.xfds) */
9047c478bd9Sstevel@tonic-gate )
9057c478bd9Sstevel@tonic-gate sstate.max--;
9067c478bd9Sstevel@tonic-gate close(conn->fd);
9077c478bd9Sstevel@tonic-gate conn->fd = -1;
9087c478bd9Sstevel@tonic-gate delete_fd(conn);
90956a424ccSmp153739 tcp_data_counter--;
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate
912*159d09a2SMark Phalan static krb5_error_code
make_toolong_error(krb5_data ** out)913*159d09a2SMark Phalan make_toolong_error (krb5_data **out)
914*159d09a2SMark Phalan {
915*159d09a2SMark Phalan krb5_error errpkt;
916*159d09a2SMark Phalan krb5_error_code retval;
917*159d09a2SMark Phalan krb5_data *scratch;
918*159d09a2SMark Phalan
919*159d09a2SMark Phalan retval = krb5_us_timeofday(kdc_context, &errpkt.stime, &errpkt.susec);
920*159d09a2SMark Phalan if (retval)
921*159d09a2SMark Phalan return retval;
922*159d09a2SMark Phalan errpkt.error = KRB_ERR_FIELD_TOOLONG;
923*159d09a2SMark Phalan errpkt.server = tgs_server;
924*159d09a2SMark Phalan errpkt.client = NULL;
925*159d09a2SMark Phalan errpkt.cusec = 0;
926*159d09a2SMark Phalan errpkt.ctime = 0;
927*159d09a2SMark Phalan errpkt.text.length = 0;
928*159d09a2SMark Phalan errpkt.text.data = 0;
929*159d09a2SMark Phalan errpkt.e_data.length = 0;
930*159d09a2SMark Phalan errpkt.e_data.data = 0;
931*159d09a2SMark Phalan scratch = malloc(sizeof(*scratch));
932*159d09a2SMark Phalan if (scratch == NULL)
933*159d09a2SMark Phalan return ENOMEM;
934*159d09a2SMark Phalan retval = krb5_mk_error(kdc_context, &errpkt, scratch);
935*159d09a2SMark Phalan if (retval) {
936*159d09a2SMark Phalan free(scratch);
937*159d09a2SMark Phalan return retval;
938*159d09a2SMark Phalan }
939*159d09a2SMark Phalan
940*159d09a2SMark Phalan *out = scratch;
941*159d09a2SMark Phalan return 0;
942*159d09a2SMark Phalan }
943*159d09a2SMark Phalan
9447c478bd9Sstevel@tonic-gate static void
process_tcp_connection(struct connection * conn,const char * prog,int selflags)9457c478bd9Sstevel@tonic-gate process_tcp_connection(struct connection *conn, const char *prog, int selflags)
9467c478bd9Sstevel@tonic-gate {
9477c478bd9Sstevel@tonic-gate if (selflags & SSF_WRITE) {
9487c478bd9Sstevel@tonic-gate ssize_t nwrote;
9497c478bd9Sstevel@tonic-gate SOCKET_WRITEV_TEMP tmp;
9507c478bd9Sstevel@tonic-gate
9517c478bd9Sstevel@tonic-gate nwrote = SOCKET_WRITEV(conn->fd, conn->u.tcp.sgp, conn->u.tcp.sgnum,
9527c478bd9Sstevel@tonic-gate tmp);
9537c478bd9Sstevel@tonic-gate if (nwrote < 0) {
9547c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate if (nwrote == 0)
9577c478bd9Sstevel@tonic-gate /* eof */
9587c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
9597c478bd9Sstevel@tonic-gate while (nwrote) {
9607c478bd9Sstevel@tonic-gate sg_buf *sgp = conn->u.tcp.sgp;
9617c478bd9Sstevel@tonic-gate if (nwrote < SG_LEN(sgp)) {
9627c478bd9Sstevel@tonic-gate SG_ADVANCE(sgp, nwrote);
9637c478bd9Sstevel@tonic-gate nwrote = 0;
9647c478bd9Sstevel@tonic-gate } else {
9657c478bd9Sstevel@tonic-gate nwrote -= SG_LEN(sgp);
9667c478bd9Sstevel@tonic-gate conn->u.tcp.sgp++;
9677c478bd9Sstevel@tonic-gate conn->u.tcp.sgnum--;
9687c478bd9Sstevel@tonic-gate if (conn->u.tcp.sgnum == 0 && nwrote != 0)
9697c478bd9Sstevel@tonic-gate abort();
9707c478bd9Sstevel@tonic-gate }
9717c478bd9Sstevel@tonic-gate }
9727c478bd9Sstevel@tonic-gate if (conn->u.tcp.sgnum == 0) {
9737c478bd9Sstevel@tonic-gate /* finished sending */
974*159d09a2SMark Phalan /* We should go back to reading, though if we sent a
975*159d09a2SMark Phalan FIELD_TOOLONG error in reply to a length with the high
976*159d09a2SMark Phalan bit set, RFC 4120 says we have to close the TCP
977*159d09a2SMark Phalan stream. */
9787c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate } else if (selflags & SSF_READ) {
9817c478bd9Sstevel@tonic-gate /* Read message length and data into one big buffer, already
9827c478bd9Sstevel@tonic-gate allocated at connect time. If we have a complete message,
9837c478bd9Sstevel@tonic-gate we stop reading, so we should only be here if there is no
9847c478bd9Sstevel@tonic-gate data in the buffer, or only an incomplete message. */
9857c478bd9Sstevel@tonic-gate size_t len;
9867c478bd9Sstevel@tonic-gate ssize_t nread;
9877c478bd9Sstevel@tonic-gate if (conn->u.tcp.offset < 4) {
9887c478bd9Sstevel@tonic-gate /* msglen has not been computed */
9897c478bd9Sstevel@tonic-gate /* XXX Doing at least two reads here, letting the kernel
9907c478bd9Sstevel@tonic-gate worry about buffering. It'll be faster when we add
9917c478bd9Sstevel@tonic-gate code to manage the buffer here. */
9927c478bd9Sstevel@tonic-gate len = 4 - conn->u.tcp.offset;
9937c478bd9Sstevel@tonic-gate nread = SOCKET_READ(conn->fd,
9947c478bd9Sstevel@tonic-gate conn->u.tcp.buffer + conn->u.tcp.offset, len);
9957c478bd9Sstevel@tonic-gate if (nread < 0)
9967c478bd9Sstevel@tonic-gate /* error */
9977c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
9987c478bd9Sstevel@tonic-gate if (nread == 0)
9997c478bd9Sstevel@tonic-gate /* eof */
10007c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
10017c478bd9Sstevel@tonic-gate conn->u.tcp.offset += nread;
10027c478bd9Sstevel@tonic-gate if (conn->u.tcp.offset == 4) {
10037c478bd9Sstevel@tonic-gate unsigned char *p = (unsigned char *)conn->u.tcp.buffer;
10047c478bd9Sstevel@tonic-gate conn->u.tcp.msglen = ((p[0] << 24)
10057c478bd9Sstevel@tonic-gate | (p[1] << 16)
10067c478bd9Sstevel@tonic-gate | (p[2] << 8)
10077c478bd9Sstevel@tonic-gate | p[3]);
10087c478bd9Sstevel@tonic-gate if (conn->u.tcp.msglen > conn->u.tcp.bufsiz - 4) {
1009*159d09a2SMark Phalan krb5_error_code err;
10107c478bd9Sstevel@tonic-gate /* message too big */
10117c478bd9Sstevel@tonic-gate krb5_klog_syslog(LOG_ERR, "TCP client %s wants %lu bytes, cap is %lu",
10127c478bd9Sstevel@tonic-gate conn->u.tcp.addrbuf, (unsigned long) conn->u.tcp.msglen,
10137c478bd9Sstevel@tonic-gate (unsigned long) conn->u.tcp.bufsiz - 4);
10147c478bd9Sstevel@tonic-gate /* XXX Should return an error. */
1015*159d09a2SMark Phalan err = make_toolong_error (&conn->u.tcp.response);
1016*159d09a2SMark Phalan if (err) {
1017*159d09a2SMark Phalan krb5_klog_syslog(LOG_ERR,
1018*159d09a2SMark Phalan "error constructing KRB_ERR_FIELD_TOOLONG error! %s",
1019*159d09a2SMark Phalan error_message(err));
10207c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
10217c478bd9Sstevel@tonic-gate }
1022*159d09a2SMark Phalan goto have_response;
1023*159d09a2SMark Phalan }
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate } else {
10267c478bd9Sstevel@tonic-gate /* msglen known */
10277c478bd9Sstevel@tonic-gate krb5_data request;
10287c478bd9Sstevel@tonic-gate krb5_error_code err;
10297c478bd9Sstevel@tonic-gate
10307c478bd9Sstevel@tonic-gate len = conn->u.tcp.msglen - (conn->u.tcp.offset - 4);
10317c478bd9Sstevel@tonic-gate nread = SOCKET_READ(conn->fd,
10327c478bd9Sstevel@tonic-gate conn->u.tcp.buffer + conn->u.tcp.offset, len);
10337c478bd9Sstevel@tonic-gate if (nread < 0)
10347c478bd9Sstevel@tonic-gate /* error */
10357c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
10367c478bd9Sstevel@tonic-gate if (nread == 0)
10377c478bd9Sstevel@tonic-gate /* eof */
10387c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
10397c478bd9Sstevel@tonic-gate conn->u.tcp.offset += nread;
10407c478bd9Sstevel@tonic-gate if (conn->u.tcp.offset < conn->u.tcp.msglen + 4)
10417c478bd9Sstevel@tonic-gate return;
10427c478bd9Sstevel@tonic-gate /* have a complete message, and exactly one message */
10437c478bd9Sstevel@tonic-gate request.length = conn->u.tcp.msglen;
10447c478bd9Sstevel@tonic-gate request.data = conn->u.tcp.buffer + 4;
104556a424ccSmp153739 err = dispatch(&request, &conn->u.tcp.faddr,
10467c478bd9Sstevel@tonic-gate &conn->u.tcp.response);
10477c478bd9Sstevel@tonic-gate if (err) {
10487c478bd9Sstevel@tonic-gate com_err(prog, err, gettext("while dispatching (tcp)"));
10497c478bd9Sstevel@tonic-gate goto kill_tcp_connection;
10507c478bd9Sstevel@tonic-gate }
1051*159d09a2SMark Phalan have_response:
10527c478bd9Sstevel@tonic-gate conn->u.tcp.lenbuf[0] = 0xff & (conn->u.tcp.response->length >> 24);
10537c478bd9Sstevel@tonic-gate conn->u.tcp.lenbuf[1] = 0xff & (conn->u.tcp.response->length >> 16);
10547c478bd9Sstevel@tonic-gate conn->u.tcp.lenbuf[2] = 0xff & (conn->u.tcp.response->length >> 8);
10557c478bd9Sstevel@tonic-gate conn->u.tcp.lenbuf[3] = 0xff & (conn->u.tcp.response->length >> 0);
10567c478bd9Sstevel@tonic-gate SG_SET(&conn->u.tcp.sgbuf[1], conn->u.tcp.response->data,
10577c478bd9Sstevel@tonic-gate conn->u.tcp.response->length);
10587c478bd9Sstevel@tonic-gate conn->u.tcp.sgp = conn->u.tcp.sgbuf;
10597c478bd9Sstevel@tonic-gate conn->u.tcp.sgnum = 2;
10607c478bd9Sstevel@tonic-gate FD_CLR(conn->fd, &sstate.rfds);
10617c478bd9Sstevel@tonic-gate FD_SET(conn->fd, &sstate.wfds);
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate } else
10647c478bd9Sstevel@tonic-gate abort();
10657c478bd9Sstevel@tonic-gate
10667c478bd9Sstevel@tonic-gate return;
10677c478bd9Sstevel@tonic-gate
10687c478bd9Sstevel@tonic-gate kill_tcp_connection:
10697c478bd9Sstevel@tonic-gate kill_tcp_connection(conn);
10707c478bd9Sstevel@tonic-gate }
10717c478bd9Sstevel@tonic-gate
service_conn(struct connection * conn,const char * prog,int selflags)10727c478bd9Sstevel@tonic-gate static void service_conn(struct connection *conn, const char *prog,
10737c478bd9Sstevel@tonic-gate int selflags)
10747c478bd9Sstevel@tonic-gate {
10757c478bd9Sstevel@tonic-gate conn->service(conn, prog, selflags);
10767c478bd9Sstevel@tonic-gate }
10777c478bd9Sstevel@tonic-gate
10787c478bd9Sstevel@tonic-gate krb5_error_code
listen_and_process(const char * prog)10797c478bd9Sstevel@tonic-gate listen_and_process(const char *prog)
10807c478bd9Sstevel@tonic-gate {
10817c478bd9Sstevel@tonic-gate int nfound;
1082*159d09a2SMark Phalan /* This struct contains 3 fd_set objects; on some platforms, they
1083*159d09a2SMark Phalan can be rather large. Making this static avoids putting all
1084*159d09a2SMark Phalan that junk on the stack. */
1085*159d09a2SMark Phalan static struct select_state sout;
10867c478bd9Sstevel@tonic-gate int i, sret;
10877c478bd9Sstevel@tonic-gate krb5_error_code err;
10887c478bd9Sstevel@tonic-gate
10897c478bd9Sstevel@tonic-gate if (conns == (struct connection **) NULL)
10907c478bd9Sstevel@tonic-gate return KDC5_NONET;
10917c478bd9Sstevel@tonic-gate
10927c478bd9Sstevel@tonic-gate while (!signal_requests_exit) {
10937c478bd9Sstevel@tonic-gate if (signal_requests_hup) {
10947c478bd9Sstevel@tonic-gate krb5_klog_reopen(kdc_context);
10957c478bd9Sstevel@tonic-gate signal_requests_hup = 0;
10967c478bd9Sstevel@tonic-gate }
10977c478bd9Sstevel@tonic-gate sstate.end_time.tv_sec = sstate.end_time.tv_usec = 0;
10987c478bd9Sstevel@tonic-gate err = krb5int_cm_call_select(&sstate, &sout, &sret);
10997c478bd9Sstevel@tonic-gate if (err) {
11007c478bd9Sstevel@tonic-gate com_err(prog, err, gettext("while selecting for network input(1)"));
11017c478bd9Sstevel@tonic-gate continue;
11027c478bd9Sstevel@tonic-gate }
11037c478bd9Sstevel@tonic-gate if (sret == -1) {
11047c478bd9Sstevel@tonic-gate if (errno != EINTR)
11057c478bd9Sstevel@tonic-gate com_err(prog, errno, gettext("while selecting for network input(2)"));
11067c478bd9Sstevel@tonic-gate continue;
11077c478bd9Sstevel@tonic-gate }
11087c478bd9Sstevel@tonic-gate nfound = sret;
11097c478bd9Sstevel@tonic-gate for (i=0; i<n_sockets && nfound > 0; i++) {
11107c478bd9Sstevel@tonic-gate int sflags = 0;
11117c478bd9Sstevel@tonic-gate if (conns[i]->fd < 0)
11127c478bd9Sstevel@tonic-gate abort();
11137c478bd9Sstevel@tonic-gate if (FD_ISSET(conns[i]->fd, &sout.rfds))
11147c478bd9Sstevel@tonic-gate sflags |= SSF_READ, nfound--;
11157c478bd9Sstevel@tonic-gate if (FD_ISSET(conns[i]->fd, &sout.wfds))
11167c478bd9Sstevel@tonic-gate sflags |= SSF_WRITE, nfound--;
11177c478bd9Sstevel@tonic-gate if (sflags)
11187c478bd9Sstevel@tonic-gate service_conn(conns[i], prog, sflags);
11197c478bd9Sstevel@tonic-gate }
11207c478bd9Sstevel@tonic-gate }
11217c478bd9Sstevel@tonic-gate return 0;
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate krb5_error_code
closedown_network(const char * prog)11257c478bd9Sstevel@tonic-gate closedown_network(const char *prog)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate int i;
11287c478bd9Sstevel@tonic-gate struct connection *conn;
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate if (conns == (struct connection **) NULL)
11317c478bd9Sstevel@tonic-gate return KDC5_NONET;
11327c478bd9Sstevel@tonic-gate
11337c478bd9Sstevel@tonic-gate FOREACH_ELT (connections, i, conn) {
11347c478bd9Sstevel@tonic-gate if (conn->fd >= 0)
11357c478bd9Sstevel@tonic-gate (void) close(conn->fd);
11367c478bd9Sstevel@tonic-gate DEL (connections, i);
113756a424ccSmp153739 /* There may also be per-connection data in the tcp structure
113856a424ccSmp153739 (tcp.buffer, tcp.response) that we're not freeing here.
113956a424ccSmp153739 That should only happen if we quit with a connection in
114056a424ccSmp153739 progress. */
114156a424ccSmp153739 free(conn);
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate FREE_SET_DATA(connections);
11447c478bd9Sstevel@tonic-gate FREE_SET_DATA(udp_port_data);
11457c478bd9Sstevel@tonic-gate FREE_SET_DATA(tcp_port_data);
11467c478bd9Sstevel@tonic-gate
11477c478bd9Sstevel@tonic-gate return 0;
11487c478bd9Sstevel@tonic-gate }
11497c478bd9Sstevel@tonic-gate
11507c478bd9Sstevel@tonic-gate #endif /* INET */
1151