Update NEWS for 1.6.22
[pkg-k5-afs_openafs.git] / src / kauth / ka-forwarder.c
blob091e7c6ef71930b8ec7fc2a8f04354ea6d789809
1 /*
2 * COPYRIGHT NOTICE
3 * Copyright (c) 1994 Carnegie Mellon University
4 * All Rights Reserved.
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
16 * Carnegie Mellon requests users of this software to return to
18 * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
28 * This program is intended to run on afs DB servers.
29 * Its function is to forward KA requests to a fakeka server
30 * running on an MIT kerberos server.
33 #include <afsconfig.h>
34 #include <afs/param.h>
36 #include <afs/stds.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/ioctl.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <stdio.h>
44 #include <netdb.h>
45 #include <ctype.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <syslog.h>
49 #include <unistd.h>
51 #if HAVE_GETOPT_H
52 #include <getopt.h>
53 #else
54 int getopt (int, char * const *, const char *);
55 int optind, opterr;
56 char *optarg;
57 #endif
59 #define BUFFER_SIZE 2048
62 char *prog;
64 int num_servers, cur_server;
65 struct sockaddr_in *servers;
68 void
69 perrorexit(char *str)
71 perror(str);
72 exit(1);
76 void
77 setup_servers(int argc, char **argv)
79 int i;
80 u_int fwdaddr;
81 u_short fwdport;
83 num_servers = argc;
85 servers = malloc(sizeof(*servers) * num_servers);
86 if (servers == NULL)
87 perrorexit("malloc failed");
89 for (i = 0; i < num_servers; i++) {
90 char *host, *port;
92 fwdport = htons(7004);
94 host = argv[i];
95 port = strchr(host, '/');
96 if (port != NULL) {
97 *port++ = 0;
99 if (isdigit(port[0])) {
100 fwdport = htons(atoi(port));
102 else {
103 struct servent *srv = getservbyname(port, "udp");
104 if (!srv) {
105 fprintf(stderr, "%s: unknown service %s\n", prog, port);
106 exit(1);
108 fwdport = srv->s_port;
112 if (isdigit(host[0])) {
113 fwdaddr = inet_addr(host);
115 else {
116 struct hostent *h = gethostbyname(host);
117 if (!h) {
118 fprintf(stderr, "%s: unknown host %s\n", prog, host);
119 exit(1);
121 bcopy(h->h_addr, &fwdaddr, 4);
124 servers[i].sin_family = AF_INET;
125 servers[i].sin_addr.s_addr = fwdaddr;
126 servers[i].sin_port = fwdport;
132 setup_socket(u_short port)
134 int s, rv;
135 struct sockaddr_in sin;
137 s = socket(AF_INET, SOCK_DGRAM, 0);
138 if (s < 0)
139 perrorexit("Couldn't create socket");
141 sin.sin_family = AF_INET;
142 sin.sin_addr.s_addr = 0;
143 sin.sin_port = htons(port);
145 rv = bind(s, (struct sockaddr *)&sin, sizeof(sin));
146 if (rv < 0)
147 perrorexit("Couldn't bind socket");
149 return s;
154 packet_is_reply(struct sockaddr_in *from)
156 int i;
158 for (i = 0; i < num_servers; i++) {
159 struct sockaddr_in *sin = &servers[i];
161 if (from->sin_addr.s_addr == sin->sin_addr.s_addr &&
162 from->sin_port == sin->sin_port)
164 return 1;
168 return 0;
173 main(int argc, char **argv)
175 int c, s, rv;
176 u_short port;
178 if (argc < 2) {
179 fprintf(stderr,
180 "usage: %s [-p port] <host>[/port] [host/port ...]\n",
181 argv[0]);
182 exit(1);
185 prog = argv[0];
186 port = 7004;
188 while ((c = getopt(argc, argv, "p:")) != -1) {
189 switch (c) {
190 case 'p':
191 port = atoi(optarg);
192 break;
193 default:
194 fprintf(stderr, "%s: invalid option '%c'\n", prog, c);
195 exit(1);
200 * hmm, different implementations of getopt seem to do different things
201 * when there aren't any options. linux sets optind = 1, which I would
202 * call correct, but sunos sets optind = 0. try to do the right thing.
204 if (optind == 0)
205 optind = 1;
207 setup_servers(argc - optind, argv + optind);
208 s = setup_socket(port);
210 openlog("ka-forwarder", LOG_PID, LOG_DAEMON);
212 for (;;) {
213 char buf[BUFFER_SIZE], *bufp, *sendptr;
214 struct sockaddr_in from, reply, *to;
215 size_t sendlen;
216 socklen_t fromlen;
218 bufp = buf + 8;
219 fromlen = sizeof(from);
221 rv = recvfrom(s, bufp, sizeof(buf) - 8,
222 0, (struct sockaddr *)&from, &fromlen);
223 if (rv < 0) {
224 syslog(LOG_ERR, "recvfrom: %m");
225 sleep(1);
226 continue;
229 if (packet_is_reply(&from)) {
230 /* this is a reply, forward back to user */
232 to = &reply;
233 reply.sin_family = AF_INET;
234 bcopy(bufp, &reply.sin_addr.s_addr, 4);
235 bcopy(bufp + 4, &reply.sin_port, 2);
236 sendptr = bufp + 8;
237 sendlen = rv - 8;
239 else {
240 /* this is a request, forward to server */
242 cur_server = (cur_server + 1) % num_servers;
243 to = &servers[cur_server];
245 bcopy(&from.sin_addr.s_addr, bufp - 8, 4);
246 bcopy(&from.sin_port, bufp - 4, 2);
248 sendptr = bufp - 8;
249 sendlen = rv + 8;
253 char a1[16], a2[16];
254 strcpy(a1, inet_ntoa(from.sin_addr));
255 strcpy(a2, inet_ntoa(to->sin_addr));
257 syslog(LOG_INFO, "forwarding %"AFS_SIZET_FMT" bytes from %s/%d to %s/%d\n",
258 sendlen, a1, htons(from.sin_port), a2, htons(to->sin_port));
261 rv = sendto(s, sendptr, sendlen,
262 0, (struct sockaddr *)to, sizeof(*to));
263 if (rv < 0) {
264 syslog(LOG_ERR, "sendto: %m");