ka-forwarder-licensing-20070508
[openafs.git] / src / kauth / ka-forwarder.c
1 /*
2  * COPYRIGHT NOTICE
3  * Copyright (c) 1994 Carnegie Mellon University
4  * All Rights Reserved.
5  *
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.
11  *
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.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie Mellon
24  * the rights to redistribute these changes.
25  */
26
27 /*
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.
31  */
32
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <stdio.h>
39 #include <netdb.h>
40 #include <ctype.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
45
46 #if     HAVE_GETOPT_H
47 #include <getopt.h>
48 #else
49 int getopt (int, char * const *, const char *);
50 int optind, opterr;
51 char *optarg;
52 #endif
53
54 #define BUFFER_SIZE 2048
55
56
57 char *prog;
58
59 int num_servers, cur_server;
60 struct sockaddr_in *servers;
61
62
63 void
64 perrorexit(str)
65 char *str;
66 {
67     perror(str);
68     exit(1);
69 }
70
71
72 void
73 setup_servers(argc, argv)
74 int argc;
75 char **argv;
76 {
77     int i;
78     u_int fwdaddr;
79     u_short fwdport;
80
81     num_servers = argc;
82
83     servers = malloc(sizeof(*servers) * num_servers);
84     if (servers == NULL)
85         perrorexit("malloc failed");
86
87     for (i = 0; i < num_servers; i++) {
88         char *host, *port;
89
90         fwdport = htons(7004);
91
92         host = argv[i];
93         port = strchr(host, '/');
94         if (port != NULL) {
95             *port++ = 0;
96
97             if (isdigit(port[0])) {
98                 fwdport = htons(atoi(port));
99             }
100             else {
101                 struct servent *srv = getservbyname(port, "udp");
102                 if (!srv) {
103                     fprintf(stderr, "%s: unknown service %s\n", prog, port);
104                     exit(1);
105                 }
106                 fwdport = srv->s_port;
107             }
108         }
109
110         if (isdigit(host[0])) {
111             fwdaddr = inet_addr(host);
112         }
113         else {
114             struct hostent *h = gethostbyname(host);
115             if (!h) {
116                 fprintf(stderr, "%s: unknown host %s\n", prog, host);
117                 exit(1);
118             }
119             bcopy(h->h_addr, &fwdaddr, 4);
120         }
121
122         servers[i].sin_family = AF_INET;
123         servers[i].sin_addr.s_addr = fwdaddr;
124         servers[i].sin_port = fwdport;
125     }
126 }
127
128
129 int
130 setup_socket(port)
131 u_short port;
132 {
133     int s, rv;
134     struct sockaddr_in sin;
135
136     s = socket(AF_INET, SOCK_DGRAM, 0);
137     if (s < 0)
138         perrorexit("Couldn't create socket");
139
140     sin.sin_family = AF_INET;
141     sin.sin_addr.s_addr = 0;
142     sin.sin_port = htons(port);
143
144     rv = bind(s, (struct sockaddr *)&sin, sizeof(sin));
145     if (rv < 0)
146         perrorexit("Couldn't bind socket");
147
148     return s;
149 }
150
151
152 int
153 packet_is_reply(from)
154 struct sockaddr_in *from;
155 {
156     int i;
157
158     for (i = 0; i < num_servers; i++) {
159         struct sockaddr_in *sin = &servers[i];
160
161         if (from->sin_addr.s_addr == sin->sin_addr.s_addr &&
162             from->sin_port == sin->sin_port)
163         {
164             return 1;
165         }
166     }
167
168     return 0;
169 }
170
171
172 int
173 main(argc, argv)
174 int argc;
175 char **argv;
176 {
177     int c, s, rv;
178     u_short port;
179
180     if (argc < 2) {
181         fprintf(stderr,
182                 "usage: %s [-p port] <host>[/port] [host/port ...]\n",
183                 argv[0]);
184         exit(1);
185     }
186
187     prog = argv[0];
188     port = 7004;
189
190     while ((c = getopt(argc, argv, "p:")) != -1) {
191         switch (c) {
192         case 'p':
193             port = atoi(optarg);
194             break;
195         default:
196             fprintf(stderr, "%s: invalid option '%c'\n", prog, c);
197             exit(1);
198         }
199     }
200
201     /*
202      * hmm, different implementations of getopt seem to do different things
203      * when there aren't any options.  linux sets optind = 1, which I would
204      * call correct, but sunos sets optind = 0.  try to do the right thing.
205      */
206     if (optind == 0)
207         optind = 1;
208
209     setup_servers(argc - optind, argv + optind);
210     s = setup_socket(port);
211
212     openlog("ka-forwarder", LOG_PID, LOG_DAEMON);
213
214     for (;;) {
215         char buf[BUFFER_SIZE], *bufp, *sendptr;
216         struct sockaddr_in from, reply, *to;
217         int fromlen, sendlen;
218
219         bufp = buf + 8;
220         fromlen = sizeof(from);
221
222         rv = recvfrom(s, bufp, sizeof(buf) - 8,
223                       0, (struct sockaddr *)&from, &fromlen);
224         if (rv < 0) {
225             syslog(LOG_ERR, "recvfrom: %m");
226             sleep(1);
227             continue;
228         }
229
230         if (packet_is_reply(&from)) {
231             /* this is a reply, forward back to user */
232
233             to = &reply;
234             reply.sin_family = AF_INET;
235             bcopy(bufp, &reply.sin_addr.s_addr, 4);
236             bcopy(bufp + 4, &reply.sin_port, 2);
237             sendptr = bufp + 8;
238             sendlen = rv - 8;
239         }
240         else {
241             /* this is a request, forward to server */
242
243             cur_server = (cur_server + 1) % num_servers;
244             to = &servers[cur_server];
245
246             bcopy(&from.sin_addr.s_addr, bufp - 8, 4);
247             bcopy(&from.sin_port, bufp - 4, 2);
248
249             sendptr = bufp - 8;
250             sendlen = rv + 8;
251         }
252
253         {
254             char a1[16], a2[16];
255             strcpy(a1, inet_ntoa(from.sin_addr));
256             strcpy(a2, inet_ntoa(to->sin_addr));
257
258             syslog(LOG_INFO, "forwarding %d bytes from %s/%d to %s/%d\n",
259                    sendlen, a1, htons(from.sin_port), a2, htons(to->sin_port));
260         }
261
262         rv = sendto(s, sendptr, sendlen,
263                     0, (struct sockaddr *)to, sizeof(*to));
264         if (rv < 0) {
265             syslog(LOG_ERR, "sendto: %m");
266         }
267     }
268 }