From cc37bc5ae487dda611d2bf4b383b2d2cfd1ea675 Mon Sep 17 00:00:00 2001 From: Russ Allbery Date: Mon, 31 Jul 2006 18:34:26 +0000 Subject: [PATCH] ka-forwarder-20060731 Add ka-forwarder. --- doc/man-pages/pod8/ka-forwarder.pod | 85 +++++++++++ src/kauth/Makefile.in | 13 +- src/kauth/ka-forwarder.c | 288 ++++++++++++++++++++++++++++++++++++ 3 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 doc/man-pages/pod8/ka-forwarder.pod create mode 100644 src/kauth/ka-forwarder.c diff --git a/doc/man-pages/pod8/ka-forwarder.pod b/doc/man-pages/pod8/ka-forwarder.pod new file mode 100644 index 0000000..321f900 --- /dev/null +++ b/doc/man-pages/pod8/ka-forwarder.pod @@ -0,0 +1,85 @@ +=head1 NAME + +ka-forwarder - Forward AFS Authentication Server requests to another server + +=head1 SYNOPSIS + +=for html +
+ +B S<<< [B<-p> >] >>> >[/>] [...] + +=for html +
+ +=head1 DESCRIPTION + +B listens for requests for an AFS Authentication Server and +forwards them to a remove B server. B is a server that +answers AFS Authentication Server protocol requests using a regular +Kerberos KDC and is provided with some Kerberos 5 implementations. +B has to run on the same host as the Kerberos KDC, however, and +AFS clients send all native AFS authentication requests to the AFS +database servers. If you don't want to run your Kerberos KDCs and your +AFS database servers on the same host, run B on the AFS +database servers and point it to B running on the Kerberos KDCs. + +B takes one or more servers to which to forward the +requests. The default port on the remote server to which to forward the +command is 7004, but a different port can be specified by following the +server name with a slash (C) and the port number. If multiple servers +are given, B will send queries to each server in turn in a +round-robin fashion. + +=head1 CAUTIONS + +Due to the way that B distinguishes from client requests and +server responses, any messages from one of the servers to which +B is forwarding will be considered a reply rather than a +command and will not be forwarded. This means that the servers running +B will not be able to use native AFS authentication requests and +rely on B to send the requests to the right server. + +B does not background itself. It should either be run in +the background via the shell, or run via the Basic OverSeer Server (see +L). + +=head1 OPTIONS + +=over 4 + +=item B<-p> > + +By default, B listens to the standard AFS Authentication +Server port (7004). To listen to a different port, specify it with the +B<-p> option. + +=back + +=head1 EXAMPLES + +Forward AFS Authentication Server reqests to the B servers on +kdc1.example.com and kdc2.example.com: + + % ka-forwarder kdc1.example.com kdc2.example.com & + +Note the C<&> to tell the shell to run this command in the background. + +=head1 PRIVILEGE REQUIRED + +B only has to listen to port 7004 and therefore does not +require any special privileges unless a privileged port is specified with +the B<-p> option. + +=head1 SEE ALSO + +L, +fakeka(8), +L + +=head1 COPYRIGHT + +Copyright 2006 Russ Allbery + +This documentation is covered by the IBM Public License Version 1.0. This +man page was written by Russ Allbery for OpenAFS. diff --git a/src/kauth/Makefile.in b/src/kauth/Makefile.in index af877bf..a588e74 100644 --- a/src/kauth/Makefile.in +++ b/src/kauth/Makefile.in @@ -52,7 +52,7 @@ OBJS=kauth.xdr.o kauth.cs.o kaaux.o client.o authclient.o token.o kautils.o kalo KOBJS=kauth.xdr.o kauth.cs.o kaaux.o client.o authclient.o token.o kautils.o kalocalcell.o kaerrors.o user.krb.o krb_tf.o -all: kaserver kas kpwvalid klog klog.krb knfs kpasswd rebuild kdb \ +all: kaserver kas kpwvalid klog klog.krb knfs kpasswd rebuild kdb ka-forwarder \ ${TOP_LIBDIR}/libkauth.a \ ${TOP_LIBDIR}/libkauth.krb.a \ depinstall @@ -200,6 +200,9 @@ krb_udp.o: krb_udp.c kaserver.h kautils.h kauth.h prot.h ${TOP_INCDIR}/lwp.h AFS krb_udp: krb_udp.o libkauth.a $(KLIBS) ${CC} ${LDFLAGS} -o krb_udp krb_udp.o libkauth.a $(KLIBS) +ka-forwarder: ka-forwarder.o + ${CC} -o $@ ${CFLAGS} ka-forwarder.o ${LIBS} ${XLIBS} + rebuild.o: rebuild.c $(INCLS) AFS_component_version_number.o rebuild: rebuild.o kautils.o $(LIBS) @@ -240,6 +243,7 @@ install: \ ${DESTDIR}${libdir}/afs/libkauth.krb.a \ ${DESTDIR}${afssrvsbindir}/kadb_check \ ${DESTDIR}${afssrvsbindir}/kdb \ + ${DESTDIR}${afssrvsbindir}/ka-forwarder \ ${DESTDIR}${includedir}/afs/kautils.h \ ${DESTDIR}${includedir}/afs/kauth.h \ ${DESTDIR}${includedir}/afs/kaport.h @@ -292,6 +296,9 @@ ${DESTDIR}${afssrvsbindir}/kadb_check: rebuild ${DESTDIR}${afssrvsbindir}/kdb: kdb ${INSTALL} -s $? $@ +${DESTDIR}${afssrvsbindir}/ka-forwarder: ka-forwarder + ${INSTALL} $? $@ + ${DESTDIR}${includedir}/afs/kautils.h: kautils.h ${INSTALL} $? $@ @@ -318,6 +325,7 @@ dest: \ ${DEST}/lib/afs/libkauth.krb.a \ ${DEST}/etc/kdb \ ${DEST}/etc/kadb_check \ + ${DEST}/root.server/usr/afs/bin/ka-forwarder \ ${DEST}/include/afs/kautils.h \ ${DEST}/include/afs/kauth.h \ ${DEST}/include/afs/kaport.h @@ -355,6 +363,9 @@ ${DEST}/etc/kadb_check: rebuild ${DEST}/etc/kdb: kdb ${INSTALL} -s $? $@ +${DEST}/root.server/usr/afs/bin/ka-forwarder: ka-forwarder + ${INSTALL} $? $@ + ${DEST}/include/afs/kautils.h: kautils.h ${INSTALL} $? $@ diff --git a/src/kauth/ka-forwarder.c b/src/kauth/ka-forwarder.c new file mode 100644 index 0000000..19e0465 --- /dev/null +++ b/src/kauth/ka-forwarder.c @@ -0,0 +1,288 @@ +/* + * COPYRIGHT NOTICE + * Copyright (c) 1994 Carnegie Mellon University + * All Rights Reserved. + * + * See for use and distribution information. + */ + +/* + * HISTORY + * $Log$ + * Revision 1.1 2006/07/31 17:34:26 rra + * DELTA ka-forwarder-20060731 + * AUTHOR rra@stanford.edu + * + * Add ka-forwarder. + * + * Revision 1.1 1997/06/03 18:23:54 kenh + * . + * + * Revision 1.4 1996/08/09 01:00:21 jhutz + * When initializing the array of fakeka servers, remember to set + * the address family of each server; otherwise SunOS complains. + * [1996/08/09 00:58:46 jhutz] + * + * Revision 1.3 1996/08/09 00:17:19 jhutz + * Merged in changes from Chuck Silvers: + * - Support for more than one fakeka server + * - Support for specifying ports for each fakeka server separately from the + * others, and from the port we listen on. + * + * Plus a minor bug fix to Chuck's code. + * Basically, this version is designed to provide both reliability and + * load-balancing cheaply. Basically, we forward packets to all of the + * fakeka servers in round-robin fashion. So, if a client is losing on + * one server, its retry should go to a different one, if more than one + * is specified. + * [1996/08/03 02:13:36 jhutz] + * + * Revision 1.2 1995/02/23 18:26:36 chs + * Created. + * [1995/02/23 18:26:03 chs] + * + * $EndLog$ + */ + +/* + * This program is intended to run on afs DB servers. + * Its function is to forward KA requests to a fakeka server + * running on an MIT kerberos server. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_GETOPT_H +#include +#else +int getopt (int, char * const *, const char *); +int optind, opterr; +char *optarg; +#endif + +#define BUFFER_SIZE 2048 + + +char *prog; + +int num_servers, cur_server; +struct sockaddr_in *servers; + + +void +perrorexit(str) +char *str; +{ + perror(str); + exit(1); +} + + +void +setup_servers(argc, argv) +int argc; +char **argv; +{ + int i; + u_int fwdaddr; + u_short fwdport; + + num_servers = argc; + + servers = malloc(sizeof(*servers) * num_servers); + if (servers == NULL) + perrorexit("malloc failed"); + + for (i = 0; i < num_servers; i++) { + char *host, *port; + + fwdport = htons(7004); + + host = argv[i]; + port = strchr(host, '/'); + if (port != NULL) { + *port++ = 0; + + if (isdigit(port[0])) { + fwdport = htons(atoi(port)); + } + else { + struct servent *srv = getservbyname(port, "udp"); + if (!srv) { + fprintf(stderr, "%s: unknown service %s\n", prog, port); + exit(1); + } + fwdport = srv->s_port; + } + } + + if (isdigit(host[0])) { + fwdaddr = inet_addr(host); + } + else { + struct hostent *h = gethostbyname(host); + if (!h) { + fprintf(stderr, "%s: unknown host %s\n", prog, host); + exit(1); + } + bcopy(h->h_addr, &fwdaddr, 4); + } + + servers[i].sin_family = AF_INET; + servers[i].sin_addr.s_addr = fwdaddr; + servers[i].sin_port = fwdport; + } +} + + +int +setup_socket(port) +u_short port; +{ + int s, rv; + struct sockaddr_in sin; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + perrorexit("Couldn't create socket"); + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = 0; + sin.sin_port = htons(port); + + rv = bind(s, (struct sockaddr *)&sin, sizeof(sin)); + if (rv < 0) + perrorexit("Couldn't bind socket"); + + return s; +} + + +int +packet_is_reply(from) +struct sockaddr_in *from; +{ + int i; + + for (i = 0; i < num_servers; i++) { + struct sockaddr_in *sin = &servers[i]; + + if (from->sin_addr.s_addr == sin->sin_addr.s_addr && + from->sin_port == sin->sin_port) + { + return 1; + } + } + + return 0; +} + + +int +main(argc, argv) +int argc; +char **argv; +{ + int c, s, rv; + u_short port; + + if (argc < 2) { + fprintf(stderr, + "usage: %s [-p port] [/port] [host/port ...]\n", + argv[0]); + exit(1); + } + + prog = argv[0]; + port = 7004; + + while ((c = getopt(argc, argv, "p:")) != -1) { + switch (c) { + case 'p': + port = atoi(optarg); + break; + default: + fprintf(stderr, "%s: invalid option '%c'\n", prog, c); + exit(1); + } + } + + /* + * hmm, different implementations of getopt seem to do different things + * when there aren't any options. linux sets optind = 1, which I would + * call correct, but sunos sets optind = 0. try to do the right thing. + */ + if (optind == 0) + optind = 1; + + setup_servers(argc - optind, argv + optind); + s = setup_socket(port); + + openlog("ka-forwarder", LOG_PID, LOG_DAEMON); + + for (;;) { + char buf[BUFFER_SIZE], *bufp, *sendptr; + struct sockaddr_in from, reply, *to; + int fromlen, sendlen; + + bufp = buf + 8; + fromlen = sizeof(from); + + rv = recvfrom(s, bufp, sizeof(buf) - 8, + 0, (struct sockaddr *)&from, &fromlen); + if (rv < 0) { + syslog(LOG_ERR, "recvfrom: %m"); + sleep(1); + continue; + } + + if (packet_is_reply(&from)) { + /* this is a reply, forward back to user */ + + to = &reply; + reply.sin_family = AF_INET; + bcopy(bufp, &reply.sin_addr.s_addr, 4); + bcopy(bufp + 4, &reply.sin_port, 2); + sendptr = bufp + 8; + sendlen = rv - 8; + } + else { + /* this is a request, forward to server */ + + cur_server = (cur_server + 1) % num_servers; + to = &servers[cur_server]; + + bcopy(&from.sin_addr.s_addr, bufp - 8, 4); + bcopy(&from.sin_port, bufp - 4, 2); + + sendptr = bufp - 8; + sendlen = rv + 8; + } + + { + char a1[16], a2[16]; + strcpy(a1, inet_ntoa(from.sin_addr)); + strcpy(a2, inet_ntoa(to->sin_addr)); + + syslog(LOG_INFO, "forwarding %d bytes from %s/%d to %s/%d\n", + sendlen, a1, htons(from.sin_port), a2, htons(to->sin_port)); + } + + rv = sendto(s, sendptr, sendlen, + 0, (struct sockaddr *)to, sizeof(*to)); + if (rv < 0) { + syslog(LOG_ERR, "sendto: %m"); + } + } +} -- 1.9.4