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 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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