9484db6949209f4ebb47ddef3d077cf39bbe0d79
[freeradius.git] / src / main / radrelay.c
1 /*
2  * radrelay.c   This program tails a detail logfile, reads the log
3  *              entries, forwards them to a remote radius server,
4  *              and moves the processed records to another file.
5  *
6  *              Used to replicate accounting records to one (central)
7  *              server - works even if remote server has extended
8  *              downtime, and/or if this program is restarted.
9  *
10  *   This program is free software; you can redistribute it and/or modify
11  *   it under the terms of the GNU General Public License as published by
12  *   the Free Software Foundation; either version 2 of the License, or
13  *   (at your option) any later version.
14  *
15  *   This program is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with this program; if not, write to the Free Software
22  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * Copyright 2001 Cistron Internet Services B.V.
25  * Copyright 2002 Simon Ekstrand <simon@routemeister.net>
26  *
27  */
28 char radrelay_rcsid[] =
29 "$Id$";
30
31 #include "autoconf.h"
32
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <sys/stat.h>
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h>
39 #endif
40
41 #include <stdio.h>
42 #include <fcntl.h>
43 #include <time.h>
44 #include <unistd.h>
45 #include <netdb.h>
46 #include <stdlib.h>
47 #include <signal.h>
48 #include <errno.h>
49 #include <string.h>
50
51 #include "radiusd.h"
52 #include "conf.h"
53 #include "radpaths.h"
54 #include "missing.h"
55 #include "conffile.h"
56
57 const char *progname;
58
59 int debug_flag = 0;
60 const char *radlog_dir = NULL;
61 radlog_dest_t radlog_dest = RADLOG_FILES;
62
63 const char *radius_dir = NULL;
64 const char *radacct_dir = NULL;
65 const char *radlib_dir = NULL;
66 uint32_t myip = INADDR_ANY;
67 int log_stripped_names;
68 struct main_config_t mainconfig;
69
70 /*
71  *      Possible states for request->state
72  */
73 #define         STATE_EMPTY     0
74 #define         STATE_BUSY1     1
75 #define         STATE_BUSY2     2
76 #define         STATE_FULL      3
77
78 /*
79  *      Possible states for the loop() function.
80  */
81 #define         STATE_RUN       0
82 #define         STATE_BACKLOG   1
83 #define         STATE_WAIT      2
84 #define         STATE_SHUTDOWN  3
85 #define         STATE_CLOSE     4
86
87 #define         NR_SLOTS                64
88 #define         DEFAULT_SLEEP           50
89 #define         DEFAULT_SLEEP_EVERY     1
90
91 /*
92  *      A relay request.
93  */
94 struct relay_request {
95         int             state;                          /* REQ_* state */
96         time_t          retrans;                        /* when to retrans */
97         unsigned int    retrans_num;                    /* Number of retransmissions */
98         time_t          timestamp;                      /* orig recv time */
99         uint32_t        client_ip;                      /* Client-IP-Addr */
100         RADIUS_PACKET   *req;                           /* Radius request */
101 };
102
103 struct relay_misc {
104         int             sockfd;                         /* Main socket descriptor */
105         uint32_t        dst_addr;                       /* Destination address */
106         short           dst_port;                       /* Destination port */
107         uint32_t        src_addr;                       /* Source address */
108         char            detail[1024];                   /* Detail file */
109         char            *secret;                        /* Secret */
110         char            f_secret[256];                  /* File secret */
111         int             sleep_time;                     /* Time to sleep between sending packets */
112         int             sleep_every;                    /* Sleep every so many packets */
113         int             records_print;                  /* Print statistics after so many records */
114 };
115
116 struct relay_stats {
117         time_t          startup;
118         uint32_t        records_read;                   /* Records read */
119         uint32_t        packets_sent;                   /* Packets sent */
120         uint32_t        last_print_records;             /* Records on last statistics printout */
121 };
122
123 /*
124  * Used for reading the client configurations from the config files.
125  */
126 char *c_secret = NULL;
127 char *c_shortname = NULL;
128
129 struct relay_request slots[NR_SLOTS];
130 char id_map[256];
131 int request_head = 0;
132 int got_sigterm = 0;
133 int debug = 0;
134
135
136 int get_radius_id(void);
137 void sigterm_handler(int sig);
138 void ms_sleep(int msec);
139 int isdateline(char *d);
140 int read_one(FILE *fp, struct relay_request *req);
141 int do_recv(struct relay_misc *r_args);
142 int do_send(struct relay_request *r, char *secret);
143 int detail_move(char *from, char *to);
144 void loop(struct relay_misc *r_args);
145 int find_shortname(char *shortname, char **host, char **secret);
146 void usage(void);
147
148
149 /*
150  * Get a radius id which is not
151  * currently being used (outstanding request)
152  * Since NR_SLOTS < 256 we can't
153  * have more outstanding requests than radius ids
154  */
155 int get_radius_id()
156 {
157         unsigned int id = 0;
158
159         for(id = 0; id < 256; id++){
160                 if (id_map[id] == 0)
161                         break;
162         }
163         if (id == 256 || id_map[id] != 0){
164                 fprintf(stdout, "get_radius_id(): No IDs available. Something is very wrong\n");
165                 return -1;
166         }
167         id_map[id] = 1;
168         fprintf(stdout, "get_radius_id(): Assign RADIUS ID = %d\n",id);
169
170         return id;
171 }
172
173 void sigterm_handler(int sig)
174 {
175         signal(sig, sigterm_handler);
176         got_sigterm = 1;
177 }
178
179
180 /*
181  *      Sleep a number of milli seconds
182  */
183 inline void ms_sleep(int msec)
184 {
185         struct timeval tv;
186
187         tv.tv_sec  = (msec / 1000);
188         tv.tv_usec = (msec % 1000) * 1000;
189         select(0, NULL, NULL, NULL, &tv);
190 }
191
192 /*
193  *      Does this (remotely) look like "Tue Jan 23 06:55:48 2001" ?
194  */
195 inline int isdateline(char *d)
196 {
197         int y;
198
199         return sscanf(d, "%*s %*s %*d %*d:%*d:%*d %d", &y);
200 }
201
202
203 /*
204  *      Read one request from the detail file.
205  *      Note that the file is locked during the read, and that
206  *      we return *with the file locked* if we reach end-of-file.
207  *
208  *      STATE_EMPTY:    Slot is empty.
209  *      STATE_BUSY1:    Looking for start of a detail record (timestamp)
210  *      STATE_BUSY2:    Reading the A/V pairs of a detail record.
211  *      STATE_FULL:     Read the complete record.
212  *
213  */
214 int read_one(FILE *fp, struct relay_request *r_req)
215 {
216         VALUE_PAIR *vp;
217         char *s;
218         char buf[2048];
219         char key[32], val[32];
220         int skip;
221         long fpos;
222         int x;
223         unsigned int i = 0;
224
225         /* Never happens */
226         if (r_req->state == STATE_FULL)
227                 return 0;
228
229         if (r_req->state == STATE_EMPTY) {
230                 r_req->state = STATE_BUSY1;
231         }
232
233         /*
234          * Try to lock the detail-file.
235          * If lockf is used we want to lock the _whole_ file, hence the
236          * fseek to the start of the file.
237          */
238         fpos = ftell(fp);
239         fseek(fp, 0L, SEEK_SET);
240         do {
241                 x = rad_lockfd_nonblock(fileno(fp), 0);
242                 if (x == -1)
243                         ms_sleep(100);
244         } while (x == -1 && i++ < 20);
245
246         if (x == -1)
247                 return 0;
248
249 redo:
250         s = NULL;
251         fseek(fp, fpos, SEEK_SET);
252         fpos = ftell(fp);
253         while ((s = fgets(buf, sizeof(buf), fp)) != NULL) {
254                 /*
255                  * Eek! We've just read a broken attribute.
256                  * This does seem to happen every once in a long while
257                  * due to some quirk involving threading, multiple processes
258                  * going for the detail file lock at once and writes not
259                  * being flushed properly. Things should be ok next time
260                  * around.
261                  */
262                 if (!strlen(buf)) {
263                         fprintf(stdout, "read_one: ZERO BYTE\n");
264                        fseek(fp, fpos + 1, SEEK_SET);
265                        break;
266                } else if (buf[strlen(buf) - 1] != '\n') {
267                         fprintf(stdout, "read_one: BROKEN ATTRIBUTE\n");
268                         fseek(fp, fpos + strlen(buf), SEEK_SET);
269                         break;
270                 }
271                 if (r_req->state == STATE_BUSY1) {
272                         if (isdateline(buf)) {
273                                 r_req->state = STATE_BUSY2;
274                         }
275                 } else if (r_req->state == STATE_BUSY2) {
276                         if (buf[0] != ' ' && buf[0] != '\t') {
277                                 r_req->state = STATE_FULL;
278                                 break;
279                         }
280                         /*
281                          *      Found A/V pair, but we skip non-protocol
282                          *      values.
283                          */
284                         skip = 0;
285                         if (sscanf(buf, "%31s = %31s", key, val) == 2) {
286                                 if (!strcasecmp(key, "Timestamp")) {
287                                         r_req->timestamp = atoi(val);
288                                         skip++;
289                                 } else
290                                 if (!strcasecmp(key, "Client-IP-Address")) {
291                                         r_req->client_ip = ip_getaddr(val);
292                                         skip++;
293                                 } else
294                                 if (!strcasecmp(key, "Request-Authenticator"))
295                                         skip++;
296                         }
297                         if (!skip) {
298                                 vp = NULL;
299                                 if (userparse(buf, &vp) > 0 &&
300                                     (vp != NULL) &&
301                                     (vp->attribute < 256 ||
302                                      vp->attribute > 65535) &&
303                                     vp->attribute != PW_VENDOR_SPECIFIC) {
304                                         pairadd(&(r_req->req->vps), vp);
305                                 } else {
306                                   pairfree(&vp);
307                                 }
308                         }
309                 }
310                 fpos = ftell(fp);
311         }
312         clearerr(fp);
313
314         if (r_req->state == STATE_FULL) {
315                 /*
316                  *      w00 - we just completed reading a record in full.
317                  */
318
319                 /*
320                  * Check that we have an Acct-Status-Type attribute. If not
321                  * reject the record
322                  */
323                 if (pairfind(r_req->req->vps, PW_ACCT_STATUS_TYPE) == NULL){
324                         fprintf(stdout, "read_one: No Acct-Status-Type attribute present. Rejecting record.\n");
325                         r_req->state = STATE_BUSY1;
326                         if (r_req->req->vps != NULL) {
327                                 pairfree(&r_req->req->vps);
328                                 r_req->req->vps = NULL;
329                         }
330                         if (r_req->req->data != NULL) {
331                                 free (r_req->req->data);
332                                 r_req->req->data = NULL;
333                         }
334                         r_req->retrans = 0;
335                         r_req->retrans_num = 0;
336                         r_req->timestamp = 0;
337                         r_req->client_ip = 0;
338                         goto redo;
339                 }
340                 if (r_req->timestamp == 0)
341                         r_req->timestamp = time(NULL);
342                 if ((vp = pairfind(r_req->req->vps, PW_ACCT_DELAY_TIME)) != NULL) {
343                         r_req->timestamp -= vp->lvalue;
344                         vp->lvalue = 0;
345                 }
346                 r_req->req->id = get_radius_id();
347         }
348
349         if (s == NULL) {
350                 /*
351                  *      Apparently we reached end of file. If we didn't
352                  *      partially read a record, we let the caller know
353                  *      we're at end of file.
354                  */
355                 if (r_req->state == STATE_BUSY1) {
356                         r_req->state = STATE_EMPTY;
357                 }
358                 if (r_req->state == STATE_EMPTY || r_req->state == STATE_FULL)
359                         return EOF;
360         }
361
362         fpos = ftell(fp);
363         fseek(fp, 0L, SEEK_SET);
364         rad_unlockfd(fileno(fp), 0);
365         fseek(fp, fpos, SEEK_SET);
366
367         return 0;
368 }
369
370 /*
371  *      Receive answers from the remote server.
372  */
373 int do_recv(struct relay_misc *r_args)
374 {
375         RADIUS_PACKET *rep;
376         struct relay_request *r;
377         int i;
378
379         /*
380          *      Receive packet and validate it's length.
381          */
382         rep = rad_recv(r_args->sockfd);
383         if (rep == NULL) {
384                 librad_perror("radrelay:");
385                 return -1;
386         }
387
388         /*
389          *      Must be an accounting response.
390          *      FIXME: check if this is the right server!
391          */
392         if (rep->code != PW_ACCOUNTING_RESPONSE)
393                 rad_free(&rep);
394                 return -1;
395
396         /*
397          *      Decode packet into radius attributes.
398          */
399
400         /*
401          *      Now find it in the outstanding requests.
402          */
403         for (i = 0; i < NR_SLOTS; i++) {
404                 r = slots + i;
405                 if (r->state == STATE_FULL && r->req->id == rep->id) {
406                         if (rad_verify(rep, r->req, r_args->secret) != 0) {
407                                 librad_perror("rad_verify");
408                                 rad_free(&rep);
409                                 return -1;
410                         }
411                         if (rad_decode(rep, r->req, r_args->secret) != 0) {
412                                 librad_perror("rad_decode");
413                                 rad_free(&rep);
414                                 return -1;
415                         }
416                         /*
417                          *      Got it. Clear slot.
418                          *      FIXME: check reponse digest ?
419                          */
420                         id_map[r->req->id] = 0;
421                         fprintf(stdout, "do_recv: Free RADIUS ID = %d\n",r->req->id);
422                         if (r->req->vps != NULL) {
423                                 pairfree(&r->req->vps);
424                                 r->req->vps = NULL;
425                         }
426                         if (r->req->data != NULL) {
427                                 free (r->req->data);
428                                 r->req->data = NULL;
429                         }
430                         r->state = STATE_EMPTY;
431                         r->retrans = 0;
432                         r->retrans_num = 0;
433                         r->timestamp = 0;
434                         r->client_ip = 0;
435                         break;
436                 }
437         }
438
439         rad_free(&rep);
440
441         return 0;
442 }
443
444 /*
445  *      Send accounting packet to remote server.
446  */
447 int do_send(struct relay_request *r, char *secret)
448 {
449         VALUE_PAIR *vp;
450         time_t now;
451
452         /*
453          *      Prevent loops.
454          */
455         if (r->client_ip == r->req->dst_ipaddr) {
456                 fprintf(stdout, "do_send: Client-IP == Dest-IP. Droping packet.\n");
457                 fprintf(stdout, "do_send: Free RADIUS ID = %d\n",r->req->id);
458                 id_map[r->req->id] = 0;
459                 if (r->req->vps != NULL) {
460                         pairfree(&r->req->vps);
461                         r->req->vps = NULL;
462                 }
463                 if (r->req->data != NULL) {
464                         free (r->req->data);
465                         r->req->data = NULL;
466                 }
467                 r->state = STATE_EMPTY;
468                 r->retrans = 0;
469                 r->retrans_num = 0;
470                 r->timestamp = 0;
471                 r->client_ip = 0;
472                 return 0;
473         }
474
475         /*
476          *      Has the time come for this packet ?
477          */
478         now = time(NULL);
479         if (r->retrans > now)
480                 return 0;
481         /*
482          * If we are resending a packet we *need* to
483          * change the radius packet id since the request
484          * authenticator is different (due to different
485          * Acct-Delay-Time value).
486          * Otherwise the radius server may consider the
487          * packet a duplicate and we 'll get caught in a
488          * loop.
489          */
490         if (r->retrans > 0){
491                 id_map[r->req->id] = 0;
492                 r->req->id = get_radius_id();
493                 if (r->req->data != NULL){
494                         free(r->req->data);
495                         r->req->data = NULL;
496                 }
497                 r->retrans_num++;
498         }
499         if (r->retrans_num > 20)
500                 r->retrans = now + 70;
501         else
502                 r->retrans = now + 3 + (3 * r->retrans_num);
503
504         /*
505          *      Find the Acct-Delay-Time attribute. If it's
506          *      not there, add one.
507          */
508         if ((vp = pairfind(r->req->vps, PW_ACCT_DELAY_TIME)) == NULL) {
509                 vp = paircreate(PW_ACCT_DELAY_TIME, PW_TYPE_INTEGER);
510                 pairadd(&(r->req->vps), vp);
511         }
512         vp->lvalue = (now - r->timestamp);
513
514         /*
515          *      Rebuild the entire packet every time from
516          *      scratch - the signature changed because
517          *      Acct-Delay-Time changed.
518          */
519         rad_send(r->req, NULL, secret);
520
521         return 1;
522 }
523
524 /*
525  *      Rename a file, then recreate the old file with the
526  *      same permissions and zero size.
527  */
528 int detail_move(char *from, char *to)
529 {
530         struct stat st;
531         int n;
532         int oldmask;
533
534         if (stat(from, &st) < 0)
535                 return -1;
536         if (rename(from, to) < 0)
537                 return -1;
538
539         oldmask = umask(0);
540         if ((n = open(from, O_CREAT|O_RDWR, st.st_mode)) >= 0)
541                 close(n);
542         umask(oldmask);
543
544         return 0;
545 }
546
547
548 /*
549  *      Open detail file, collect records, send them to the
550  *      remote accounting server, yadda yadda yadda.
551  *
552  *      STATE_RUN:      Reading from detail file, sending to server.
553  *      STATE_BACKLOG:  Reading from the detail.work file, for example
554  *                      after a crash or restart. Sending to server.
555  *      STATE_WAIT:     Waiting for all outstanding requests to be handled.
556  *      STATE_CLOSE:    Reached end of detail.work file, waiting for
557  *                      outstanding requests, and removing the file.
558  *      STATE_SHUTDOWN: Got SIG_TERM, waiting for outstanding requests
559  *                      and exiting program.
560  */
561 void loop(struct relay_misc *r_args)
562 {
563         FILE *fp = NULL;
564         struct relay_request *r;
565         struct timeval tv;
566         struct relay_stats stats;
567         fd_set readfds;
568         char work[1030];
569         time_t now, uptime, last_rename = 0;
570         int i, n;
571         int state = STATE_RUN;
572         int id;
573         long fpos;
574
575         strNcpy(work, r_args->detail, sizeof(work) - 6);
576         strcat(work, ".work");
577
578         id = ((int)getpid() & 0xff);
579
580         memset(&stats,0,sizeof(struct relay_stats));
581         stats.startup = time(NULL);
582
583         /*
584          * Initialize all our slots, might as well do this right away.
585          */
586         for (i = 0; i < NR_SLOTS; i++) {
587                 if ((slots[i].req = rad_alloc(1)) == NULL) {
588                         librad_perror("radrelay");
589                         exit(1);
590                 }
591                 slots[i].state = STATE_EMPTY;
592                 slots[i].retrans = 0;
593                 slots[i].retrans_num = 0;
594                 slots[i].timestamp = 0;
595                 slots[i].client_ip = 0;
596                 slots[i].req->sockfd = r_args->sockfd;
597                 slots[i].req->dst_ipaddr = r_args->dst_addr;
598                 slots[i].req->dst_port = r_args->dst_port;
599                 slots[i].req->src_ipaddr = r_args->src_addr;
600                 slots[i].req->code = PW_ACCOUNTING_REQUEST;
601                 slots[i].req->vps = NULL;
602                 slots[i].req->data = NULL;
603         }
604
605         while(1) {
606                 if (got_sigterm) state = STATE_SHUTDOWN;
607
608                 /*
609                  *      Open detail file - if needed, and if we can.
610                  */
611                 if (state == STATE_RUN && fp == NULL) {
612                         if ((fp = fopen(work, "r+")) != NULL)
613                                 state = STATE_BACKLOG;
614                         else
615                                 fp = fopen(r_args->detail, "r+");
616                         if (fp == NULL) {
617                                 fprintf(stderr, "%s: Unable to open detail file - %s\n", progname, r_args->detail);
618                                 perror("fopen");
619                                 return;
620                         }
621
622                 }
623
624                 /*
625                  *      If "request_head" points to a free or not-completely-
626                  *      filled slot, we can read from the detail file.
627                  */
628                 r = &slots[request_head];
629                 if (fp && (state == STATE_RUN || state == STATE_BACKLOG) &&
630                     r->state != STATE_FULL) {
631                         if (read_one(fp, r) == EOF) do {
632
633                                 /*
634                                  *      We've reached end of the <detail>.work
635                                  *      It's going to be closed as soon as all
636                                  *      outstanting requests are handled
637                                  */
638                                 if (state == STATE_BACKLOG) {
639                                         state = STATE_CLOSE;
640                                         break;
641                                 }
642
643                                 /*
644                                  *      End of file. See if the file has
645                                  *      any size, and if we renamed less
646                                  *      than 10 seconds ago or not.
647                                  */
648                                 now = time(NULL);
649                                 if (ftell(fp) == 0 || now < last_rename + 10) {
650                                         fpos = ftell(fp);
651                                         fseek(fp, 0L, SEEK_SET);
652                                         rad_unlockfd(fileno(fp), 0);
653                                         fseek(fp, fpos, SEEK_SET);
654                                         break;
655                                 }
656                                 last_rename = now;
657
658                                 /*
659                                  *      We rename the file to <file>.work
660                                  *      and create an empty new file.
661                                  */
662                                 if (detail_move(r_args->detail, work) == 0) {
663                                         if (debug_flag > 0)
664                                                 fprintf(stderr, "Moving %s to %s\n",
665                                                         r_args->detail, work);
666                                         /*
667                                          *      rlm_detail might still write
668                                          *      something to <detail>.work if
669                                          *      it opens <detail> before it is
670                                          *      renamed (race condition)
671                                          */
672                                         ms_sleep(1000);
673                                         state = STATE_BACKLOG;
674                                 }
675                                 fpos = ftell(fp);
676                                 fseek(fp, 0L, SEEK_SET);
677                                 rad_unlockfd(fileno(fp), 0);
678                                 fseek(fp, fpos, SEEK_SET);
679                         } while(0);
680                         if (r_args->records_print && state == STATE_RUN){
681                                 stats.records_read++;
682                                 if (stats.last_print_records - stats.records_read >= r_args->records_print){
683                                         now = time(NULL);
684                                         uptime = (stats.startup == now) ? 1 : now - stats.startup;
685                                         fprintf(stderr, "%s: Running and Processing Records.\n",progname);
686                                         fprintf(stderr, "Seconds since startup: %ld\n",uptime);
687                                         fprintf(stderr, "Records Read: %d\n",stats.records_read);
688                                         fprintf(stderr, "Packets Sent: %d\n",stats.packets_sent);
689                                         fprintf(stderr, "Record Rate since startup: %.2f\n",
690                                                 (double)stats.records_read / uptime);
691                                         fprintf(stderr, "Packet Rate since startup: %.2f\n",
692                                                 (double)stats.packets_sent / uptime);
693                                         stats.last_print_records = stats.records_read;
694                                 }
695                         }
696                         if (r->state == STATE_FULL)
697                                 request_head = (request_head + 1) % NR_SLOTS;
698                 }
699
700                 /*
701                  *      Perhaps we can receive something.
702                  */
703                 tv.tv_sec = 0;
704                 tv.tv_usec = 25000;
705                 FD_ZERO(&readfds);
706                 FD_SET(r_args->sockfd, &readfds);
707                 n = 0;
708                 while (select(r_args->sockfd + 1, &readfds, NULL, NULL, &tv) > 0) {
709                         do_recv(r_args);
710                         if (n++ >= NR_SLOTS) break;
711                 }
712
713                 /*
714                  *      If we're in STATE_WAIT and all slots are
715                  *      finally empty, we can remove the <detail>.work
716                  */
717                 if (state == STATE_WAIT || state == STATE_CLOSE || state == STATE_SHUTDOWN) {
718                         for (i = 0; i < NR_SLOTS; i++)
719                                 if (slots[i].state != STATE_EMPTY)
720                                         break;
721                         if (i == NR_SLOTS) {
722                                 if (state == STATE_CLOSE) {
723                                         if (fp) fclose(fp);
724                                         fp = NULL;
725                                         if (debug_flag > 0)
726                                                 fprintf(stderr, "Unlink file %s\n", work);
727                                         unlink(work);
728                                 }
729                                 else if (state == STATE_SHUTDOWN) {
730                                         for (i = 0; i < NR_SLOTS; i++) {
731                                                 rad_free(&slots[i].req);
732                                         }
733                                         exit(0);
734                                 }
735                                 state = STATE_RUN;
736                         }
737                 }
738
739                 /*
740                  *      See if there's anything to send.
741                  */
742                 n=0;
743                 for (i = 0; i < NR_SLOTS; i++) {
744                         if (slots[i].state == STATE_FULL) {
745                                 n += do_send(&slots[i], r_args->secret);
746                                 if ((n % r_args->sleep_every) == 0)
747                                         ms_sleep(r_args->sleep_time);
748                                 if (n > NR_SLOTS / 2)
749                                         break;
750                         }
751                 }
752                 if (r_args->records_print)
753                         stats.packets_sent += n;
754         }
755 }
756
757 /*
758  * Search through the "client" config sections (usually in clients.conf).
759  * This is an easy way to find a secret and an host.
760  */
761 int find_shortname(char *shortname, char **host, char **secret)
762 {
763         CONF_SECTION *maincs, *cs;
764         char buffer[256];
765
766         /* Lets go look for the new configuration files */
767         memset(&mainconfig, 0, sizeof(mainconfig)); /* for radlog() */
768         snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", radius_dir);
769         if ((maincs = conf_read(NULL, 0, buffer, NULL)) == NULL) {
770                 return -1;
771         }
772
773         /*
774          * Find the first 'client' section.
775          */
776         cs = cf_section_sub_find(maincs, "client");
777         if (cs) {
778                 c_shortname = cf_section_value_find(cs, "shortname");
779                 c_secret = cf_section_value_find(cs, "secret");
780                 /*
781                  * Keep searching for 'client' sections until they run out
782                  * or we find one that matches.
783                  */
784                 while (cs && strcmp(shortname, c_shortname)) {
785                         cs = cf_subsection_find_next(cs, cs, "client");
786                         if (cs) {
787                                 c_shortname = cf_section_value_find(cs, "shortname");
788                                 c_secret = cf_section_value_find(cs, "secret");
789                         }
790                 };
791         };
792
793         if (cs) {
794                 *host = cf_section_name2(cs);
795                 *secret = c_secret;
796                 if (host && secret)
797                         return 0;
798         }
799
800         return -1;
801 }
802
803 void usage(void)
804 {
805         fprintf(stderr, "Usage: radrelay [-a accounting_dir] [-d radius_dir] [-i local_ip] [-s secret]\n");
806         fprintf(stderr, "[-e sleep_every packets] [-t sleep_time (ms)] [-S secret_file] [-fx]\n");
807         fprintf(stderr, "[-R records_print] <[-n shortname] [-r remote-server[:port]]> detailfile\n");
808         fprintf(stderr, " -a accounting_dir     Base accounting directory.\n");
809         fprintf(stderr, " -d radius_dir         Base radius (raddb) directory.\n");
810         fprintf(stderr, " -f                    Stay in the foreground (don't fork).\n");
811         fprintf(stderr, " -h                    This help.\n");
812         fprintf(stderr, " -i local_ip           Use local_ip as source address.\n");
813         fprintf(stderr, " -n shortname          Use the [shortname] entry from clients.conf for\n");
814         fprintf(stderr, "                       ip-adress and secret.\n");
815         fprintf(stderr, " -t sleep_time         Sleep so much time (in ms) between sending packets. Default: %dms.\n",
816                                                 DEFAULT_SLEEP);
817         fprintf(stderr, " -e sleep_every        Sleep after sending so many packets. Default: %d\n",
818                                                 DEFAULT_SLEEP_EVERY);
819         fprintf(stderr, " -R records_print      If in foreground mode, print statistics after so many records read.\n");
820         fprintf(stderr, " -r remote-server      The destination address/hostname.\n");
821         fprintf(stderr, " -s secret             Server secret.\n");
822         fprintf(stderr, " -S secret_file        Read server secret from file.\n");
823         fprintf(stderr, " -x                    Debug mode (-xx gives more debugging).\n");
824
825         exit(1);
826 }
827
828 int main(int argc, char **argv)
829 {
830         struct servent *svp;
831         char *server_name;
832         char *shortname;
833         char *p;
834         int c;
835         int i;
836         int dontfork = 0;
837         struct relay_misc r_args;
838         FILE *sfile_fp;
839
840         progname = argv[0];
841
842         r_args.sockfd = -1;
843         r_args.dst_addr = 0;
844         r_args.dst_port = 0;
845         r_args.src_addr = 0;
846         memset((char *) r_args.detail, 0, 1024);
847         memset((char *) r_args.f_secret, 0, 256);
848         r_args.secret = NULL;
849         r_args.sleep_time = DEFAULT_SLEEP;
850         r_args.sleep_every = DEFAULT_SLEEP_EVERY;
851
852         shortname = NULL;
853         server_name = NULL;
854
855         radius_dir = strdup(RADIUS_DIR);
856
857         librad_debug = 0;
858
859         /*
860          *      Make sure there are stdin/stdout/stderr fds.
861          */
862         while ((c = open("/dev/null", O_RDWR)) < 3 && c >= 0);
863         if (c >= 3) close(c);
864
865         /*
866          *      Process the options.
867          */
868         while ((c = getopt(argc, argv, "a:d:fhi:t:e:n:r:R:s:S:x")) != EOF) switch(c) {
869                 case 'a':
870                         if (strlen(optarg) > 1021) {
871                                 fprintf(stderr, "%s: acct_dir to long\n", progname);
872                                 exit(1);
873                         }
874                         strncpy(r_args.detail, optarg, 1021);
875                         break;
876                 case 'd':
877                         if (radius_dir)
878                                 free(radius_dir);
879                         radius_dir = strdup(optarg);
880                         break;
881                 case 'f':
882                         dontfork = 1;
883                         break;
884                 case 'n':
885                         shortname = optarg;
886                         break;
887                 case 't':
888                         r_args.sleep_time = atoi(optarg);
889                         break;
890                 case 'e':
891                         r_args.sleep_every = atoi(optarg);
892                         break;
893                 case 'R':
894                         if (!dontfork){
895                                 fprintf(stderr, "%s: Not in foreground mode. Can't print statistics.\n",progname);
896                                 usage();
897                         }
898                         r_args.records_print = atoi(optarg);
899                         break;
900                 case 'r':
901                         server_name = optarg;
902                         break;
903                 case 's':
904                         r_args.secret = optarg;
905                         break;
906                 case 'x':
907                         /*
908                          * If -x is called once we enable internal radrelay
909                          * debugging, if it's called twice we also active
910                          * lib_rad debugging (fairly verbose).
911                          */
912                         if (debug == 1)
913                                 librad_debug = 1;
914                         debug = 1;
915                         dontfork = 1;
916                         break;
917                 case 'S':
918                         sfile_fp = fopen(optarg, "r");
919                         if (sfile_fp == NULL) {
920                                 fprintf(stderr, "Error opening %s: %s\n",
921                                         optarg, strerror(errno));
922                                 exit(1);
923                         }
924
925                         if (fgets(r_args.f_secret, 256, sfile_fp) == NULL) {
926                                 fprintf(stderr, "Error reading from %s: %s\n",
927                                         optarg, strerror(errno));
928                                 fclose(sfile_fp);
929                                 exit(1);
930                         }
931                         fclose(sfile_fp);
932
933                         for (c = 0; c < strlen(r_args.f_secret); c++)
934                                 if (r_args.f_secret[c] == ' ' ||
935                                     r_args.f_secret[c] == '\n')
936                                         r_args.f_secret[c] = '\0';
937
938                         if (strlen(r_args.f_secret) < 2) {
939                                 fprintf(stderr, "Secret in %s is to short\n",
940                                         optarg);
941                                 exit(1);
942                         }
943
944                         r_args.secret = r_args.f_secret;
945                         break;
946                 case 'i':
947                         if ((r_args.src_addr = ip_getaddr(optarg)) == 0) {
948                                 fprintf(stderr, "%s: unknown host %s\n",
949                                         progname, optarg);
950                                 exit(1);
951                         }
952                         break;
953                 case 'h':
954                 default:
955                         usage();
956                         break;
957         }
958
959         /*
960          *      No detail file: die.
961          */
962         if (argc == optind) {
963                 usage();
964         }
965
966         argc -= (optind - 1);
967         argv += (optind - 1);
968         if (shortname && server_name)
969                 usage();
970         if (!shortname && !server_name)
971                 usage();
972         if (r_args.secret != NULL && shortname != NULL)
973                 usage();
974
975         /*
976          * If we've been given a shortname, try to fetch the secret and
977          * adress from the config files.
978          */
979         if (shortname != NULL) {
980                 if (find_shortname(shortname, &server_name, &r_args.secret) == -1) {
981                         fprintf(stderr, "Couldn't find %s in configuration files.\n", shortname);
982                         exit(1);
983                 }
984         }
985
986         /*
987          * server_name should already be set either by the -r or the -s
988          * commandline argument.
989          */
990         if ((p = strrchr(server_name, ':')) != NULL) {
991                 *p = 0;
992                 p++;
993                 r_args.dst_port = ntohs(atoi(p));
994         }
995         if (r_args.dst_port == 0) {
996                 svp = getservbyname ("radacct", "udp");
997                 r_args.dst_port = svp ? ntohs(svp->s_port) : PW_ACCT_UDP_PORT;
998         } else {
999                 r_args.dst_port = ntohs(r_args.dst_port);
1000         }
1001         r_args.dst_addr = ip_getaddr(server_name);
1002         if (r_args.dst_addr == 0) {
1003                 fprintf(stderr, "%s: unknown host\n",
1004                         server_name);
1005                 exit(1);
1006         }
1007
1008         if (r_args.secret == NULL || r_args.secret[0] == 0) {
1009                 fprintf(stderr, "No secret available for server %s\n",
1010                         server_name);
1011                 exit(1);
1012         }
1013
1014         /*
1015          * Find what detail file to read from.
1016          *
1017          * FIXME: We should be able to expand dates etc. based on the pathname,
1018          * just like the detail module does.
1019          */
1020         if (r_args.detail[0] == '\0') {
1021                 if (strlen(RADIR) > 1021) {
1022                         fprintf(stderr, "acct_dir to long\n");
1023                         exit(1);
1024                 }
1025                 strncpy(r_args.detail, RADIR, 1021);
1026         }
1027         if (chdir(r_args.detail) == -1) {
1028                 perror("chdir");
1029                 exit(1);
1030         }
1031
1032         if (strlen(argv[1]) + strlen(r_args.detail) > 1023) {
1033                 fprintf(stderr, "Detail file path to long");
1034                 exit(1);
1035         } else {
1036                 if (r_args.detail[strlen(r_args.detail) - 1] != '/')
1037                         r_args.detail[strlen(r_args.detail)] = '/';
1038                 strncat (r_args.detail, argv[1], 1023 - strlen(r_args.detail));
1039         }
1040
1041         /*
1042          *      Initialize dictionary.
1043          */
1044         if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
1045                 librad_perror("radrelay");
1046                 exit(1);
1047         }
1048
1049         /*
1050          *      Open a socket to the remote server.
1051          */
1052         if ((r_args.sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1053                 fprintf(stderr, "Error opening socket: %s", strerror(errno));
1054                 exit(1);
1055         }
1056
1057         signal(SIGTERM, sigterm_handler);
1058
1059         if (!dontfork) {
1060                 if (fork() != 0)
1061                         exit(0);
1062                 close(0);
1063                 close(1);
1064                 close(2);
1065                 (void)open("/dev/null", O_RDWR);
1066                 dup(0);
1067                 dup(0);
1068                 signal(SIGHUP,  SIG_IGN);
1069                 signal(SIGINT,  SIG_IGN);
1070                 signal(SIGQUIT, SIG_IGN);
1071 #ifdef HAVE_SETSID
1072                 setsid();
1073 #endif
1074         }
1075
1076         /*
1077          * Initialize the radius id map
1078          */
1079         for(i=0;i<256;i++)
1080                 id_map[i] = 0;
1081
1082         /*
1083          *      Call main processing loop.
1084          */
1085         loop(&r_args);
1086
1087         return 0;
1088 }