/* * kdc/network.c * * Copyright 1990 by the Massachusetts Institute of Technology. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * * Network code for Kerberos v5 KDC. */ #include "k5-int.h" #include "com_err.h" #include "kdc_util.h" #include "extern.h" #include "kdc5_err.h" #include #ifdef HAVE_NETINET_IN_H #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif #include extern int errno; static int *udp_port_fds = (int *) NULL; static u_short *udp_port_nums = (u_short *) NULL; static int n_udp_ports = 0; static int max_udp_ports = 0; static fd_set select_fds; static int select_nfds; #define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n))) static krb5_error_code add_port(port) u_short port; { int i; int *new_fds; u_short *new_ports; int new_max; for (i=0; i < n_udp_ports; i++) { if (udp_port_nums[i] == port) return 0; } if (n_udp_ports >= max_udp_ports) { new_max = max_udp_ports + 10; new_fds = safe_realloc(udp_port_fds, new_max * sizeof(int)); if (new_fds == 0) return ENOMEM; udp_port_fds = new_fds; new_ports = safe_realloc(udp_port_nums, new_max * sizeof(u_short)); if (new_ports == 0) return ENOMEM; udp_port_nums = new_ports; max_udp_ports = new_max; } udp_port_nums[n_udp_ports++] = port; return 0; } #undef safe_realloc krb5_error_code setup_network(prog) const char *prog; { struct sockaddr_in sin; krb5_error_code retval; u_short port; char *cp; int i; FD_ZERO(&select_fds); select_nfds = 0; memset((char *)&sin, 0, sizeof(sin)); /* Handle each realm's ports */ for (i=0; irealm_ports; while (cp && *cp) { if (*cp == ',' || isspace(*cp)) { cp++; continue; } port = strtol(cp, &cp, 10); if (cp == 0) break; retval = add_port(port); if (retval) return retval; } } for (i=0; i select_nfds) select_nfds = udp_port_fds[i]+1; } return 0; } void process_packet(port_fd, prog, portnum) int port_fd; const char *prog; int portnum; { int cc, saddr_len; krb5_fulladdr faddr; krb5_error_code retval; struct sockaddr_in saddr; krb5_address addr; krb5_data request; krb5_data *response; char pktbuf[MAX_DGRAM_SIZE]; if (port_fd < 0) return; saddr_len = sizeof(saddr); cc = recvfrom(port_fd, pktbuf, sizeof(pktbuf), 0, (struct sockaddr *)&saddr, &saddr_len); if (cc == -1) { if (errno != EINTR) com_err(prog, errno, "while receiving from network"); return; } if (!cc) return; /* zero-length packet? */ request.length = cc; request.data = pktbuf; faddr.port = ntohs(saddr.sin_port); faddr.address = &addr; addr.addrtype = ADDRTYPE_INET; addr.length = 4; /* this address is in net order */ addr.contents = (krb5_octet *) &saddr.sin_addr; if ((retval = dispatch(&request, &faddr, portnum, &response))) { com_err(prog, retval, "while dispatching"); return; } cc = sendto(port_fd, response->data, response->length, 0, (struct sockaddr *)&saddr, saddr_len); if (cc == -1) { krb5_free_data(kdc_context, response); com_err(prog, errno, "while sending reply to %s/%d", inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return; } if (cc != response->length) { krb5_free_data(kdc_context, response); com_err(prog, 0, "short reply write %d vs %d\n", response->length, cc); return; } krb5_free_data(kdc_context, response); return; } krb5_error_code listen_and_process(prog) const char *prog; { int nfound; fd_set readfds; int i; if (udp_port_fds == (int *) NULL) return KDC5_NONET; while (!signal_requests_exit) { if (signal_requests_hup) { krb5_klog_reopen(); signal_requests_hup = 0; } readfds = select_fds; nfound = select(select_nfds, &readfds, 0, 0, 0); if (nfound == -1) { if (errno == EINTR) continue; com_err(prog, errno, "while selecting for network input"); continue; } for (i=0; i= 0) (void) close(udp_port_fds[i]); } free(udp_port_fds); free(udp_port_nums); return 0; } #endif /* INET */