#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
#include <arpa/inet.h>
#include <netdb.h>
extern char *krb5_kdc_udp_portname;
+extern char *krb5_kdc_sec_udp_portname;
extern int errno;
static int udp_port_fd = -1;
+static int sec_udp_port_fd = -1;
+static fd_set select_fds;
+static int select_nfsd;
krb5_error_code
setup_network(prog)
struct sockaddr_in sin;
krb5_error_code retval;
+ FD_ZERO(&select_fds);
+ select_nfsd = 0;
sp = getservbyname(krb5_kdc_udp_portname, "udp");
if (!sp) {
com_err(prog, 0, "%s/udp service unknown\n",
com_err(prog, 0, "Cannot bind server socket");
return retval;
}
+ FD_SET(udp_port_fd, &select_fds);
+ if (udp_port_fd+1 > select_nfsd)
+ select_nfsd = udp_port_fd+1;
+
+ /*
+ * Now we set up the secondary listening port, if it is enabled
+ */
+ if (!krb5_kdc_sec_udp_portname)
+ return 0; /* No secondary listening port defined */
+
+ sp = getservbyname(krb5_kdc_sec_udp_portname, "udp");
+ if (!sp) {
+ com_err(prog, 0, "%s/udp service unknown\n",
+ krb5_kdc_sec_udp_portname);
+ return 0; /* Don't give an error if we can't */
+ /* find it */
+ }
+ if ((sec_udp_port_fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
+ retval = errno;
+ com_err(prog, 0, "Cannot create secondary server socket");
+ return retval;
+ }
+ memset((char *)&sin, 0, sizeof(sin));
+ sin.sin_port = sp->s_port;
+ if (bind(sec_udp_port_fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ retval = errno;
+ com_err(prog, 0, "Cannot bind secondary server socket");
+ return retval;
+ }
+ FD_SET(sec_udp_port_fd, &select_fds);
+ if (sec_udp_port_fd+1 > select_nfsd)
+ select_nfsd = sec_udp_port_fd+1;
+
return 0;
}
listen_and_process(prog)
const char *prog;
{
- int cc, saddr_len;
- krb5_error_code retval;
- struct sockaddr_in saddr;
- krb5_fulladdr faddr;
- krb5_address addr;
- krb5_data request;
- krb5_data *response;
- char pktbuf[MAX_DGRAM_SIZE];
+ static int errcount = 0;
+ int nfound;
+ fd_set readfds;
+ krb5_error_code retval;
if (udp_port_fd == -1)
return KDC5_NONET;
while (!signal_requests_exit) {
- saddr_len = sizeof(saddr);
- if ((cc = recvfrom(udp_port_fd, pktbuf, sizeof(pktbuf), 0,
- (struct sockaddr *)&saddr, &saddr_len)) != -1) {
- if (!cc)
- continue; /* 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, &response)) {
- com_err(prog, retval, "while dispatching");
+ readfds = select_fds;
+ nfound = select(select_nfsd, &readfds, 0, 0, 0);
+ if (nfound == -1) {
+ if (errno == EINTR)
+ continue;
+ com_err(prog, errno, "while selecting for network input");
+ if (errcount++ > 3)
+ break;
continue;
- }
- if ((cc = sendto(udp_port_fd, response->data, response->length, 0,
- (struct sockaddr *)&saddr, saddr_len)) != response->length) {
- switch (cc) {
- case -1:
- com_err(prog, errno, "while sending reply to %s/%d",
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
- break;
- default:
- com_err(prog, 0, "short reply write %d vs %d\n",
- response->length, cc);
- break;
+ }
+ if (FD_ISSET(udp_port_fd, &readfds)) {
+ retval = process_packet(udp_port_fd, prog, 0);
+ if (retval) {
+ if (errcount++ > 3)
+ break;
+ }
+ }
+ if (FD_ISSET(sec_udp_port_fd, &readfds)) {
+ retval = process_packet(sec_udp_port_fd, prog, 1);
+ if (retval) {
+ if (errcount++ > 3)
+ break;
}
- }
- krb5_free_data(response);
- } else {
- switch (errno) {
- case EINTR:
- continue;
- default:
- com_err(prog, errno, "while receiving from network");
- break;
- }
}
-
+ errcount = 0;
+ }
+ return 0;
+}
+
+krb5_error_code
+process_packet(port_fd, prog, is_secondary)
+ int port_fd;
+ char *prog;
+ int is_secondary;
+{
+ 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];
+
+ saddr_len = sizeof(saddr);
+ cc = recvfrom(port_fd, pktbuf, sizeof(pktbuf), 0,
+ (struct sockaddr *)&saddr, &saddr_len);
+ if (cc == -1) {
+ if (errno == EINTR)
+ return 0;
+ com_err(prog, errno, "while receiving from network");
+ return errno;
+ }
+ if (!cc)
+ return 0; /* 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, is_secondary, &response)) {
+ com_err(prog, retval, "while dispatching");
+ return 0;
+ }
+ cc = sendto(port_fd, response->data, response->length, 0,
+ (struct sockaddr *)&saddr, saddr_len);
+ krb5_free_data(response);
+ if (cc == -1) {
+ com_err(prog, errno, "while sending reply to %s/%d",
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+ return errno;
+ }
+ if (cc != response->length) {
+ com_err(prog, 0, "short reply write %d vs %d\n",
+ response->length, cc);
+ return KDC5_IO_RESPONSE;
}
return 0;
}
+
krb5_error_code
closedown_network(prog)
const char *prog;
(void) close(udp_port_fd);
udp_port_fd = -1;
+
+ if (sec_udp_port_fd != -1)
+ (void) close(sec_udp_port_fd);
+ sec_udp_port_fd = -1;
return 0;
}