import from HEAD
[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                 return -1;
394
395         /*
396          *      Decode packet into radius attributes.
397          */
398
399         /*
400          *      Now find it in the outstanding requests.
401          */
402         for (i = 0; i < NR_SLOTS; i++) {
403                 r = slots + i;
404                 if (r->state == STATE_FULL && r->req->id == rep->id) {
405                         if (rad_verify(rep, r->req, r_args->secret) != 0) {
406                                 librad_perror("rad_verify");
407                                 return -1;
408                         }
409                         if (rad_decode(rep, r->req, r_args->secret) != 0) {
410                                 librad_perror("rad_decode");
411                                 return -1;
412                         }
413                         /*
414                          *      Got it. Clear slot.
415                          *      FIXME: check reponse digest ?
416                          */
417                         id_map[r->req->id] = 0;
418                         fprintf(stdout, "do_recv: Free RADIUS ID = %d\n",r->req->id);
419                         if (r->req->vps != NULL) {
420                                 pairfree(&r->req->vps);
421                                 r->req->vps = NULL;
422                         }
423                         if (r->req->data != NULL) {
424                                 free (r->req->data);
425                                 r->req->data = NULL;
426                         }
427                         r->state = STATE_EMPTY;
428                         r->retrans = 0;
429                         r->retrans_num = 0;
430                         r->timestamp = 0;
431                         r->client_ip = 0;
432                         break;
433                 }
434         }
435
436         rad_free(&rep);
437
438         return 0;
439 }
440
441 /*
442  *      Send accounting packet to remote server.
443  */
444 int do_send(struct relay_request *r, char *secret)
445 {
446         VALUE_PAIR *vp;
447         time_t now;
448
449         /*
450          *      Prevent loops.
451          */
452         if (r->client_ip == r->req->dst_ipaddr) {
453                 fprintf(stdout, "do_send: Client-IP == Dest-IP. Droping packet.\n");
454                 fprintf(stdout, "do_send: Free RADIUS ID = %d\n",r->req->id);
455                 id_map[r->req->id] = 0;
456                 if (r->req->vps != NULL) {
457                         pairfree(&r->req->vps);
458                         r->req->vps = NULL;
459                 }
460                 if (r->req->data != NULL) {
461                         free (r->req->data);
462                         r->req->data = NULL;
463                 }
464                 r->state = STATE_EMPTY;
465                 r->retrans = 0;
466                 r->retrans_num = 0;
467                 r->timestamp = 0;
468                 r->client_ip = 0;
469                 return 0;
470         }
471
472         /*
473          *      Has the time come for this packet ?
474          */
475         now = time(NULL);
476         if (r->retrans > now)
477                 return 0;
478         /*
479          * If we are resending a packet we *need* to
480          * change the radius packet id since the request
481          * authenticator is different (due to different
482          * Acct-Delay-Time value).
483          * Otherwise the radius server may consider the
484          * packet a duplicate and we 'll get caught in a
485          * loop.
486          */
487         if (r->retrans > 0){
488                 id_map[r->req->id] = 0;
489                 r->req->id = get_radius_id();
490                 if (r->req->data != NULL){
491                         free(r->req->data);
492                         r->req->data = NULL;
493                 }
494                 r->retrans_num++;
495         }
496         if (r->retrans_num > 20)
497                 r->retrans = now + 70;
498         else
499                 r->retrans = now + 3 + (3 * r->retrans_num);
500
501         /*
502          *      Find the Acct-Delay-Time attribute. If it's
503          *      not there, add one.
504          */
505         if ((vp = pairfind(r->req->vps, PW_ACCT_DELAY_TIME)) == NULL) {
506                 vp = paircreate(PW_ACCT_DELAY_TIME, PW_TYPE_INTEGER);
507                 pairadd(&(r->req->vps), vp);
508         }
509         vp->lvalue = (now - r->timestamp);
510
511         /*
512          *      Rebuild the entire packet every time from
513          *      scratch - the signature changed because
514          *      Acct-Delay-Time changed.
515          */
516         rad_send(r->req, NULL, secret);
517
518         return 1;
519 }
520
521 /*
522  *      Rename a file, then recreate the old file with the
523  *      same permissions and zero size.
524  */
525 int detail_move(char *from, char *to)
526 {
527         struct stat st;
528         int n;
529         int oldmask;
530
531         if (stat(from, &st) < 0)
532                 return -1;
533         if (rename(from, to) < 0)
534                 return -1;
535
536         oldmask = umask(0);
537         if ((n = open(from, O_CREAT|O_RDWR, st.st_mode)) >= 0)
538                 close(n);
539         umask(oldmask);
540
541         return 0;
542 }
543
544
545 /*
546  *      Open detail file, collect records, send them to the
547  *      remote accounting server, yadda yadda yadda.
548  *
549  *      STATE_RUN:      Reading from detail file, sending to server.
550  *      STATE_BACKLOG:  Reading from the detail.work file, for example
551  *                      after a crash or restart. Sending to server.
552  *      STATE_WAIT:     Waiting for all outstanding requests to be handled.
553  *      STATE_CLOSE:    Reached end of detail.work file, waiting for
554  *                      outstanding requests, and removing the file.
555  *      STATE_SHUTDOWN: Got SIG_TERM, waiting for outstanding requests
556  *                      and exiting program.
557  */
558 void loop(struct relay_misc *r_args)
559 {
560         FILE *fp = NULL;
561         struct relay_request *r;
562         struct timeval tv;
563         struct relay_stats stats;
564         fd_set readfds;
565         char work[1030];
566         time_t now, uptime, last_rename = 0;
567         int i, n;
568         int state = STATE_RUN;
569         int id;
570         long fpos;
571
572         strNcpy(work, r_args->detail, sizeof(work) - 6);
573         strcat(work, ".work");
574
575         id = ((int)getpid() & 0xff);
576
577         memset(&stats,0,sizeof(struct relay_stats));
578         stats.startup = time(NULL);
579
580         /*
581          * Initialize all our slots, might as well do this right away.
582          */
583         for (i = 0; i < NR_SLOTS; i++) {
584                 if ((slots[i].req = rad_alloc(1)) == NULL) {
585                         librad_perror("radrelay");
586                         exit(1);
587                 }
588                 slots[i].state = STATE_EMPTY;
589                 slots[i].retrans = 0;
590                 slots[i].retrans_num = 0;
591                 slots[i].timestamp = 0;
592                 slots[i].client_ip = 0;
593                 slots[i].req->sockfd = r_args->sockfd;
594                 slots[i].req->dst_ipaddr = r_args->dst_addr;
595                 slots[i].req->dst_port = r_args->dst_port;
596                 slots[i].req->src_ipaddr = r_args->src_addr;
597                 slots[i].req->code = PW_ACCOUNTING_REQUEST;
598                 slots[i].req->vps = NULL;
599                 slots[i].req->data = NULL;
600         }
601
602         while(1) {
603                 if (got_sigterm) state = STATE_SHUTDOWN;
604
605                 /*
606                  *      Open detail file - if needed, and if we can.
607                  */
608                 if (state == STATE_RUN && fp == NULL) {
609                         if ((fp = fopen(work, "r+")) != NULL)
610                                 state = STATE_BACKLOG;
611                         else
612                                 fp = fopen(r_args->detail, "r+");
613                         if (fp == NULL) {
614                                 fprintf(stderr, "%s: Unable to open detail file - %s\n", progname, r_args->detail);
615                                 perror("fopen");
616                                 return;
617                         }
618
619                 }
620
621                 /*
622                  *      If "request_head" points to a free or not-completely-
623                  *      filled slot, we can read from the detail file.
624                  */
625                 r = &slots[request_head];
626                 if (fp && (state == STATE_RUN || state == STATE_BACKLOG) &&
627                     r->state != STATE_FULL) {
628                         if (read_one(fp, r) == EOF) do {
629
630                                 /*
631                                  *      We've reached end of the <detail>.work
632                                  *      It's going to be closed as soon as all
633                                  *      outstanting requests are handled
634                                  */
635                                 if (state == STATE_BACKLOG) {
636                                         state = STATE_CLOSE;
637                                         break;
638                                 }
639
640                                 /*
641                                  *      End of file. See if the file has
642                                  *      any size, and if we renamed less
643                                  *      than 10 seconds ago or not.
644                                  */
645                                 now = time(NULL);
646                                 if (ftell(fp) == 0 || now < last_rename + 10) {
647                                         fpos = ftell(fp);
648                                         fseek(fp, 0L, SEEK_SET);
649                                         rad_unlockfd(fileno(fp), 0);
650                                         fseek(fp, fpos, SEEK_SET);
651                                         break;
652                                 }
653                                 last_rename = now;
654
655                                 /*
656                                  *      We rename the file to <file>.work
657                                  *      and create an empty new file.
658                                  */
659                                 if (detail_move(r_args->detail, work) == 0) {
660                                         if (debug_flag > 0)
661                                                 fprintf(stderr, "Moving %s to %s\n",
662                                                         r_args->detail, work);
663                                         /*
664                                          *      rlm_detail might still write
665                                          *      something to <detail>.work if
666                                          *      it opens <detail> before it is
667                                          *      renamed (race condition)
668                                          */
669                                         ms_sleep(1000);
670                                         state = STATE_BACKLOG;
671                                 }
672                                 fpos = ftell(fp);
673                                 fseek(fp, 0L, SEEK_SET);
674                                 rad_unlockfd(fileno(fp), 0);
675                                 fseek(fp, fpos, SEEK_SET);
676                         } while(0);
677                         if (r_args->records_print && state == STATE_RUN){
678                                 stats.records_read++;
679                                 if (stats.last_print_records - stats.records_read >= r_args->records_print){
680                                         now = time(NULL);
681                                         uptime = (stats.startup == now) ? 1 : now - stats.startup;
682                                         fprintf(stderr, "%s: Running and Processing Records.\n",progname);
683                                         fprintf(stderr, "Seconds since startup: %ld\n",uptime);
684                                         fprintf(stderr, "Records Read: %d\n",stats.records_read);
685                                         fprintf(stderr, "Packets Sent: %d\n",stats.packets_sent);
686                                         fprintf(stderr, "Record Rate since startup: %.2f\n",
687                                                 (double)stats.records_read / uptime);
688                                         fprintf(stderr, "Packet Rate since startup: %.2f\n",
689                                                 (double)stats.packets_sent / uptime);
690                                         stats.last_print_records = stats.records_read;
691                                 }
692                         }
693                         if (r->state == STATE_FULL)
694                                 request_head = (request_head + 1) % NR_SLOTS;
695                 }
696
697                 /*
698                  *      Perhaps we can receive something.
699                  */
700                 tv.tv_sec = 0;
701                 tv.tv_usec = 25000;
702                 FD_ZERO(&readfds);
703                 FD_SET(r_args->sockfd, &readfds);
704                 n = 0;
705                 while (select(r_args->sockfd + 1, &readfds, NULL, NULL, &tv) > 0) {
706                         do_recv(r_args);
707                         if (n++ >= NR_SLOTS) break;
708                 }
709
710                 /*
711                  *      If we're in STATE_WAIT and all slots are
712                  *      finally empty, we can remove the <detail>.work
713                  */
714                 if (state == STATE_WAIT || state == STATE_CLOSE || state == STATE_SHUTDOWN) {
715                         for (i = 0; i < NR_SLOTS; i++)
716                                 if (slots[i].state != STATE_EMPTY)
717                                         break;
718                         if (i == NR_SLOTS) {
719                                 if (state == STATE_CLOSE) {
720                                         if (fp) fclose(fp);
721                                         fp = NULL;
722                                         if (debug_flag > 0)
723                                                 fprintf(stderr, "Unlink file %s\n", work);
724                                         unlink(work);
725                                 }
726                                 else if (state == STATE_SHUTDOWN) {
727                                         for (i = 0; i < NR_SLOTS; i++) {
728                                                 rad_free(&slots[i].req);
729                                         }
730                                         exit(0);
731                                 }
732                                 state = STATE_RUN;
733                         }
734                 }
735
736                 /*
737                  *      See if there's anything to send.
738                  */
739                 n=0;
740                 for (i = 0; i < NR_SLOTS; i++) {
741                         if (slots[i].state == STATE_FULL) {
742                                 n += do_send(&slots[i], r_args->secret);
743                                 if ((n % r_args->sleep_every) == 0)
744                                         ms_sleep(r_args->sleep_time);
745                                 if (n > NR_SLOTS / 2)
746                                         break;
747                         }
748                 }
749                 if (r_args->records_print)
750                         stats.packets_sent += n;
751         }
752 }
753
754 /*
755  * Search through the "client" config sections (usually in clients.conf).
756  * This is an easy way to find a secret and an host.
757  */
758 int find_shortname(char *shortname, char **host, char **secret)
759 {
760         CONF_SECTION *maincs, *cs;
761         char buffer[256];
762
763         /* Lets go look for the new configuration files */
764         memset(&mainconfig, 0, sizeof(mainconfig)); /* for radlog() */
765         snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", radius_dir);
766         if ((maincs = conf_read(NULL, 0, buffer, NULL)) == NULL) {
767                 return -1;
768         }
769
770         /*
771          * Find the first 'client' section.
772          */
773         cs = cf_section_sub_find(maincs, "client");
774         if (cs) {
775                 c_shortname = cf_section_value_find(cs, "shortname");
776                 c_secret = cf_section_value_find(cs, "secret");
777                 /*
778                  * Keep searching for 'client' sections until they run out
779                  * or we find one that matches.
780                  */
781                 while (cs && strcmp(shortname, c_shortname)) {
782                         cs = cf_subsection_find_next(cs, cs, "client");
783                         if (cs) {
784                                 c_shortname = cf_section_value_find(cs, "shortname");
785                                 c_secret = cf_section_value_find(cs, "secret");
786                         }
787                 };
788         };
789
790         if (cs) {
791                 *host = cf_section_name2(cs);
792                 *secret = c_secret;
793                 if (host && secret)
794                         return 0;
795         }
796
797         return -1;
798 }
799
800 void usage(void)
801 {
802         fprintf(stderr, "Usage: radrelay [-a accounting_dir] [-d radius_dir] [-i local_ip] [-s secret]\n");
803         fprintf(stderr, "[-e sleep_every packets] [-t sleep_time (ms)] [-S secret_file] [-fx]\n");
804         fprintf(stderr, "[-R records_print] <[-n shortname] [-r remote-server[:port]]> detailfile\n");
805         fprintf(stderr, " -a accounting_dir     Base accounting directory.\n");
806         fprintf(stderr, " -d radius_dir         Base radius (raddb) directory.\n");
807         fprintf(stderr, " -f                    Stay in the foreground (don't fork).\n");
808         fprintf(stderr, " -h                    This help.\n");
809         fprintf(stderr, " -i local_ip           Use local_ip as source address.\n");
810         fprintf(stderr, " -n shortname          Use the [shortname] entry from clients.conf for\n");
811         fprintf(stderr, "                       ip-adress and secret.\n");
812         fprintf(stderr, " -t sleep_time         Sleep so much time (in ms) between sending packets. Default: %dms.\n",
813                                                 DEFAULT_SLEEP);
814         fprintf(stderr, " -e sleep_every        Sleep after sending so many packets. Default: %d\n",
815                                                 DEFAULT_SLEEP_EVERY);
816         fprintf(stderr, " -R records_print      If in foreground mode, print statistics after so many records read.\n");
817         fprintf(stderr, " -r remote-server      The destination address/hostname.\n");
818         fprintf(stderr, " -s secret             Server secret.\n");
819         fprintf(stderr, " -S secret_file        Read server secret from file.\n");
820         fprintf(stderr, " -x                    Debug mode (-xx gives more debugging).\n");
821
822         exit(1);
823 }
824
825 int main(int argc, char **argv)
826 {
827         struct servent *svp;
828         char *server_name;
829         char *shortname;
830         char *p;
831         int c;
832         int i;
833         int dontfork = 0;
834         struct relay_misc r_args;
835         FILE *sfile_fp;
836
837         progname = argv[0];
838
839         r_args.sockfd = -1;
840         r_args.dst_addr = 0;
841         r_args.dst_port = 0;
842         r_args.src_addr = 0;
843         memset((char *) r_args.detail, 0, 1024);
844         memset((char *) r_args.f_secret, 0, 256);
845         r_args.secret = NULL;
846         r_args.sleep_time = DEFAULT_SLEEP;
847         r_args.sleep_every = DEFAULT_SLEEP_EVERY;
848
849         shortname = NULL;
850         server_name = NULL;
851
852         radius_dir = strdup(RADIUS_DIR);
853
854         librad_debug = 0;
855
856         /*
857          *      Make sure there are stdin/stdout/stderr fds.
858          */
859         while ((c = open("/dev/null", O_RDWR)) < 3 && c >= 0);
860         if (c >= 3) close(c);
861
862         /*
863          *      Process the options.
864          */
865         while ((c = getopt(argc, argv, "a:d:fhi:t:e:n:r:R:s:S:x")) != EOF) switch(c) {
866                 case 'a':
867                         if (strlen(optarg) > 1021) {
868                                 fprintf(stderr, "%s: acct_dir to long\n", progname);
869                                 exit(1);
870                         }
871                         strncpy(r_args.detail, optarg, 1021);
872                         break;
873                 case 'd':
874                         if (radius_dir)
875                                 free(radius_dir);
876                         radius_dir = strdup(optarg);
877                         break;
878                 case 'f':
879                         dontfork = 1;
880                         break;
881                 case 'n':
882                         shortname = optarg;
883                         break;
884                 case 't':
885                         r_args.sleep_time = atoi(optarg);
886                         break;
887                 case 'e':
888                         r_args.sleep_every = atoi(optarg);
889                         break;
890                 case 'R':
891                         if (!dontfork){
892                                 fprintf(stderr, "%s: Not in foreground mode. Can't print statistics.\n",progname);
893                                 usage();
894                         }
895                         r_args.records_print = atoi(optarg);
896                         break;
897                 case 'r':
898                         server_name = optarg;
899                         break;
900                 case 's':
901                         r_args.secret = optarg;
902                         break;
903                 case 'x':
904                         /*
905                          * If -x is called once we enable internal radrelay
906                          * debugging, if it's called twice we also active
907                          * lib_rad debugging (fairly verbose).
908                          */
909                         if (debug == 1)
910                                 librad_debug = 1;
911                         debug = 1;
912                         dontfork = 1;
913                         break;
914                 case 'S':
915                         sfile_fp = fopen(optarg, "r");
916                         if (sfile_fp == NULL) {
917                                 fprintf(stderr, "Error opening %s: %s\n",
918                                         optarg, strerror(errno));
919                                 exit(1);
920                         }
921
922                         if (fgets(r_args.f_secret, 256, sfile_fp) == NULL) {
923                                 fprintf(stderr, "Error reading from %s: %s\n",
924                                         optarg, strerror(errno));
925                                 fclose(sfile_fp);
926                                 exit(1);
927                         }
928                         fclose(sfile_fp);
929
930                         for (c = 0; c < strlen(r_args.f_secret); c++)
931                                 if (r_args.f_secret[c] == ' ' ||
932                                     r_args.f_secret[c] == '\n')
933                                         r_args.f_secret[c] = '\0';
934
935                         if (strlen(r_args.f_secret) < 2) {
936                                 fprintf(stderr, "Secret in %s is to short\n",
937                                         optarg);
938                                 exit(1);
939                         }
940
941                         r_args.secret = r_args.f_secret;
942                         break;
943                 case 'i':
944                         if ((r_args.src_addr = ip_getaddr(optarg)) == 0) {
945                                 fprintf(stderr, "%s: unknown host %s\n",
946                                         progname, optarg);
947                                 exit(1);
948                         }
949                         break;
950                 case 'h':
951                 default:
952                         usage();
953                         break;
954         }
955
956         /*
957          *      No detail file: die.
958          */
959         if (argc == optind) {
960                 usage();
961         }
962
963         argc -= (optind - 1);
964         argv += (optind - 1);
965         if (shortname && server_name)
966                 usage();
967         if (!shortname && !server_name)
968                 usage();
969         if (r_args.secret != NULL && shortname != NULL)
970                 usage();
971
972         /*
973          * If we've been given a shortname, try to fetch the secret and
974          * adress from the config files.
975          */
976         if (shortname != NULL) {
977                 if (find_shortname(shortname, &server_name, &r_args.secret) == -1) {
978                         fprintf(stderr, "Couldn't find %s in configuration files.\n", shortname);
979                         exit(1);
980                 }
981         }
982
983         /*
984          * server_name should already be set either by the -r or the -s
985          * commandline argument.
986          */
987         if ((p = strrchr(server_name, ':')) != NULL) {
988                 *p = 0;
989                 p++;
990                 r_args.dst_port = ntohs(atoi(p));
991         }
992         if (r_args.dst_port == 0) {
993                 svp = getservbyname ("radacct", "udp");
994                 r_args.dst_port = svp ? ntohs(svp->s_port) : PW_ACCT_UDP_PORT;
995         } else {
996                 r_args.dst_port = ntohs(r_args.dst_port);
997         }
998         r_args.dst_addr = ip_getaddr(server_name);
999         if (r_args.dst_addr == 0) {
1000                 fprintf(stderr, "%s: unknown host\n",
1001                         server_name);
1002                 exit(1);
1003         }
1004
1005         if (r_args.secret == NULL || r_args.secret[0] == 0) {
1006                 fprintf(stderr, "No secret available for server %s\n",
1007                         server_name);
1008                 exit(1);
1009         }
1010
1011         /*
1012          * Find what detail file to read from.
1013          *
1014          * FIXME: We should be able to expand dates etc. based on the pathname,
1015          * just like the detail module does.
1016          */
1017         if (r_args.detail[0] == '\0') {
1018                 if (strlen(RADIR) > 1021) {
1019                         fprintf(stderr, "acct_dir to long\n");
1020                         exit(1);
1021                 }
1022                 strncpy(r_args.detail, RADIR, 1021);
1023         }
1024         if (chdir(r_args.detail) == -1) {
1025                 perror("chdir");
1026                 exit(1);
1027         }
1028
1029         if (strlen(argv[1]) + strlen(r_args.detail) > 1023) {
1030                 fprintf(stderr, "Detail file path to long");
1031                 exit(1);
1032         } else {
1033                 if (r_args.detail[strlen(r_args.detail) - 1] != '/')
1034                         r_args.detail[strlen(r_args.detail)] = '/';
1035                 strncat (r_args.detail, argv[1], 1023 - strlen(r_args.detail));
1036         }
1037
1038         /*
1039          *      Initialize dictionary.
1040          */
1041         if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
1042                 librad_perror("radrelay");
1043                 exit(1);
1044         }
1045
1046         /*
1047          *      Open a socket to the remote server.
1048          */
1049         if ((r_args.sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
1050                 fprintf(stderr, "Error opening socket: %s", strerror(errno));
1051                 exit(1);
1052         }
1053
1054         signal(SIGTERM, sigterm_handler);
1055
1056         if (!dontfork) {
1057                 if (fork() != 0)
1058                         exit(0);
1059                 close(0);
1060                 close(1);
1061                 close(2);
1062                 (void)open("/dev/null", O_RDWR);
1063                 dup(0);
1064                 dup(0);
1065                 signal(SIGHUP,  SIG_IGN);
1066                 signal(SIGINT,  SIG_IGN);
1067                 signal(SIGQUIT, SIG_IGN);
1068 #ifdef HAVE_SETSID
1069                 setsid();
1070 #endif
1071         }
1072
1073         /*
1074          * Initialize the radius id map
1075          */
1076         for(i=0;i<256;i++)
1077                 id_map[i] = 0;
1078
1079         /*
1080          *      Call main processing loop.
1081          */
1082         loop(&r_args);
1083
1084         return 0;
1085 }