f6098cf71ce3e8266d4c789ca012c19f9764d432
[freeradius.git] / src / main / radiusd.c
1 /*
2  * radiusd.c    Main loop of the radius server.
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000-2004,2006  The FreeRADIUS server project
21  * Copyright 1999,2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  * Copyright 2000  Alan Curry <pacman-radius@cqc.com>
24  * Copyright 2000  Jeff Carneal <jeff@apex.net>
25  * Copyright 2000  Chad Miller <cmiller@surfsouth.com>
26  */
27
28 #include <freeradius-devel/ident.h>
29 RCSID("$Id$")
30
31 #include <freeradius-devel/radiusd.h>
32 #include <freeradius-devel/radius_snmp.h>
33 #include <freeradius-devel/modules.h>
34 #include <freeradius-devel/rad_assert.h>
35
36 #include <sys/file.h>
37
38 #include <fcntl.h>
39 #include <ctype.h>
40
41 #include <signal.h>
42
43 #ifdef HAVE_GETOPT_H
44 #       include <getopt.h>
45 #endif
46
47 #ifdef HAVE_SYS_WAIT_H
48 #       include <sys/wait.h>
49 #endif
50 #ifndef WEXITSTATUS
51 #       define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
52 #endif
53 #ifndef WIFEXITED
54 #       define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
55 #endif
56
57 #ifndef HAVE_PTHREAD_H
58 #define thread_pool_lock(_x)
59 #define thread_pool_unlock(_x)
60 #endif
61
62 /*
63  *  Global variables.
64  */
65 const char *progname = NULL;
66 const char *radius_dir = NULL;
67 const char *radacct_dir = NULL;
68 const char *radlog_dir = NULL;
69 const char *radlib_dir = NULL;
70 int log_stripped_names;
71 int debug_flag = 0;
72 int check_config = FALSE;
73
74 const char *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION ", for host " HOSTINFO ", built on " __DATE__ " at " __TIME__;
75
76 time_t time_now;
77 pid_t radius_pid;
78
79 static int debug_memory = 0;
80
81 /*
82  *  Configuration items.
83  */
84
85 /*
86  *      Static functions.
87  */
88 static void usage(int);
89
90 static void sig_fatal (int);
91 #ifdef SIGHUP
92 static void sig_hup (int);
93 #endif
94
95 /*
96  *      The main guy.
97  */
98 int main(int argc, char *argv[])
99 {
100         int rcode;
101         int argval;
102         int spawn_flag = TRUE;
103         int dont_fork = FALSE;
104         int flag = 0;
105
106 #ifdef HAVE_SIGACTION
107         struct sigaction act;
108 #endif
109
110 #ifdef OSFC2
111         set_auth_parameters(argc,argv);
112 #endif
113
114         if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL)
115                 progname = argv[0];
116         else
117                 progname++;
118
119 #ifdef WIN32
120         {
121                 WSADATA wsaData;
122                 if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
123                         fprintf(stderr, "%s: Unable to initialize socket library.\n");
124                         return 1;
125                 }
126         }
127 #endif
128
129         debug_flag = 0;
130         spawn_flag = TRUE;
131         radius_dir = strdup(RADIUS_DIR);
132
133         /*
134          *      Ensure that the configuration is initialized.
135          */
136         memset(&mainconfig, 0, sizeof(mainconfig));
137         mainconfig.myip.af = AF_UNSPEC;
138         mainconfig.port = -1;
139         mainconfig.name = "radiusd";
140
141 #ifdef HAVE_SIGACTION
142         memset(&act, 0, sizeof(act));
143         act.sa_flags = 0 ;
144         sigemptyset( &act.sa_mask ) ;
145 #endif
146
147         /*
148          *      Don't put output anywhere until we get told a little
149          *      more.
150          */
151         mainconfig.radlog_fd = -1;
152         mainconfig.log_file = NULL;
153
154         /*  Process the options.  */
155         while ((argval = getopt(argc, argv, "Cd:fhi:mn:p:svxX")) != EOF) {
156
157                 switch(argval) {
158                         case 'C':
159                                 check_config = TRUE;
160                                 spawn_flag = FALSE;
161                                 dont_fork = TRUE;
162                                 break;
163
164                         case 'd':
165                                 if (radius_dir) free(radius_dir);
166                                 radius_dir = strdup(optarg);
167                                 break;
168
169                         case 'f':
170                                 dont_fork = TRUE;
171                                 break;
172
173                         case 'h':
174                                 usage(0);
175                                 break;
176
177                         case 'i':
178                                 if (ip_hton(optarg, AF_UNSPEC, &mainconfig.myip) < 0) {
179                                         fprintf(stderr, "radiusd: Invalid IP Address or hostname \"%s\"\n", optarg);
180                                         exit(1);
181                                 }
182                                 flag |= 1;
183                                 break;
184
185                         case 'n':
186                                 mainconfig.name = optarg;
187                                 break;
188
189                         case 'm':
190                                 debug_memory = 1;
191                                 break;
192
193                         case 'p':
194                                 mainconfig.port = atoi(optarg);
195                                 if ((mainconfig.port <= 0) ||
196                                     (mainconfig.port >= 65536)) {
197                                         fprintf(stderr, "radiusd: Invalid port number %s\n", optarg);
198                                         exit(1);
199                                 }
200                                 flag |= 2;
201                                 break;
202
203                         case 's':       /* Single process mode */
204                                 spawn_flag = FALSE;
205                                 dont_fork = TRUE;
206                                 break;
207
208                         case 'v':
209                                 version();
210                                 break;
211
212                         case 'X':
213                                 spawn_flag = FALSE;
214                                 dont_fork = TRUE;
215                                 debug_flag += 2;
216                                 mainconfig.log_auth = TRUE;
217                                 mainconfig.log_auth_badpass = TRUE;
218                                 mainconfig.log_auth_goodpass = TRUE;
219                                 mainconfig.radlog_dest = RADLOG_STDOUT;
220                                 mainconfig.radlog_fd = STDOUT_FILENO;
221                                 break;
222
223                         case 'x':
224                                 debug_flag++;
225                                 break;
226
227                         default:
228                                 usage(1);
229                                 break;
230                 }
231         }
232
233         if (flag && (flag != 0x03)) {
234                 fprintf(stderr, "radiusd: The options -i and -p cannot be used individually.\n");
235                 exit(1);
236         }
237
238         if (debug_flag) {
239                 radlog(L_INFO, "%s", radiusd_version);
240                 radlog(L_INFO, "Copyright (C) 2000-2007 The FreeRADIUS server project.\n");
241                 radlog(L_INFO, "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n");
242                 radlog(L_INFO, "PARTICULAR PURPOSE.\n");
243                 radlog(L_INFO, "You may redistribute copies of FreeRADIUS under the terms of the\n");
244                 radlog(L_INFO, "GNU General Public License.\n");
245                 fflush(NULL);
246         }
247
248         /*  Read the configuration files, BEFORE doing anything else.  */
249         if (read_mainconfig(0) < 0) {
250                 exit(1);
251         }
252
253 #ifndef __MINGW32__
254         /*
255          *  Disconnect from session
256          */
257         if (debug_flag == 0 && dont_fork == FALSE) {
258                 pid_t pid = fork();
259
260                 if (pid < 0) {
261                         radlog(L_ERR, "Couldn't fork: %s", strerror(errno));
262                         exit(1);
263                 }
264
265                 /*
266                  *  The parent exits, so the child can run in the background.
267                  */
268                 if (pid > 0) {
269                         exit(0);
270                 }
271 #ifdef HAVE_SETSID
272                 setsid();
273 #endif
274         }
275 #endif
276
277         /*
278          *  Ensure that we're using the CORRECT pid after forking,
279          *  NOT the one we started with.
280          */
281         radius_pid = getpid();
282
283         /*
284          *  Only write the PID file if we're running as a daemon.
285          *
286          *  And write it AFTER we've forked, so that we write the
287          *  correct PID.
288          */
289         if (dont_fork == FALSE) {
290                 FILE *fp;
291
292                 fp = fopen(mainconfig.pid_file, "w");
293                 if (fp != NULL) {
294                         /*
295                          *      FIXME: What about following symlinks,
296                          *      and having it over-write a normal file?
297                          */
298                         fprintf(fp, "%d\n", (int) radius_pid);
299                         fclose(fp);
300                 } else {
301                         radlog(L_ERR|L_CONS, "Failed creating PID file %s: %s\n",
302                                mainconfig.pid_file, strerror(errno));
303                         exit(1);
304                 }
305         }
306
307         /*
308          *      If we're running as a daemon, close the default file
309          *      descriptors, AFTER forking.
310          */
311         if (!debug_flag) {
312                 int devnull;
313
314                 devnull = open("/dev/null", O_RDWR);
315                 if (devnull < 0) {
316                         radlog(L_ERR|L_CONS, "Failed opening /dev/null: %s\n",
317                                strerror(errno));
318                         exit(1);
319                 }
320                 dup2(devnull, STDIN_FILENO);
321                 if (mainconfig.radlog_dest == RADLOG_STDOUT) {
322                         mainconfig.radlog_fd = dup(STDOUT_FILENO);
323                 }
324                 dup2(devnull, STDOUT_FILENO);
325                 if (mainconfig.radlog_dest == RADLOG_STDERR) {
326                         mainconfig.radlog_fd = dup(STDERR_FILENO);
327                 }
328                 dup2(devnull, STDERR_FILENO);
329                 close(devnull);
330
331         } else {
332                 setlinebuf(stdout); /* unbuffered output */
333         }
334
335         /*
336          *      It's called the thread pool, but it does a little
337          *      more than that.
338          */
339         radius_event_init(mainconfig.config, spawn_flag);
340
341         /*
342          *      Now that we've set everything up, we can install the signal
343          *      handlers.  Before this, if we get any signal, we don't know
344          *      what to do, so we might as well do the default, and die.
345          */
346 #ifdef SIGPIPE
347         signal(SIGPIPE, SIG_IGN);
348 #endif
349 #ifdef HAVE_SIGACTION
350         act.sa_handler = sig_hup;
351         sigaction(SIGHUP, &act, NULL);
352         act.sa_handler = sig_fatal;
353         sigaction(SIGTERM, &act, NULL);
354 #else
355 #ifdef SIGHUP
356         signal(SIGHUP, sig_hup);
357 #endif
358         signal(SIGTERM, sig_fatal);
359 #endif
360         /*
361          *      If we're debugging, then a CTRL-C will cause the
362          *      server to die immediately.  Use SIGTERM to shut down
363          *      the server cleanly in that case.
364          */
365         if ((debug_memory == 1) || (debug_flag == 0)) {
366 #ifdef HAVE_SIGACTION
367                 act.sa_handler = sig_fatal;
368                 sigaction(SIGINT, &act, NULL);
369                 sigaction(SIGQUIT, &act, NULL);
370 #else
371                 signal(SIGINT, sig_fatal);
372 #ifdef SIGQUIT
373                 signal(SIGQUIT, sig_fatal);
374 #endif
375 #endif
376         }
377
378         /*
379          *      Everything seems to have loaded OK, exit gracefully.
380          */
381         if (check_config) {
382                 DEBUG("Configuration appears OK.");
383                 exit(0);
384         }
385
386         /*
387          *      Process requests until HUP or exit.
388          */
389         while ((rcode = radius_event_process()) == 0x80) {
390                 module_hup(cf_section_sub_find(mainconfig.config, "modules"));
391         }
392         
393         DEBUG("Exiting...");
394         
395         /*
396          *      Ignore the TERM signal: we're
397          *      about to die.
398          */
399         signal(SIGTERM, SIG_IGN);
400         
401         /*
402          *      Send a TERM signal to all
403          *      associated processes
404          *      (including us, which gets
405          *      ignored.)
406          */
407 #ifndef __MINGW32__
408         kill(-radius_pid, SIGTERM);
409 #endif
410         
411         /*
412          *      We're exiting, so we can delete the PID
413          *      file.  (If it doesn't exist, we can ignore
414          *      the error returned by unlink)
415          */
416         if (dont_fork == FALSE) {
417                 unlink(mainconfig.pid_file);
418         }
419                 
420         radius_event_free();
421         
422         /*
423          *      Free the configuration items.
424          */
425         free_mainconfig();
426         
427         /*
428          *      Detach any modules.
429          */
430         detach_modules();
431         
432         xlat_free();            /* modules may have xlat's */
433
434         free(radius_dir);
435                 
436 #ifdef WIN32
437         WSACleanup();
438 #endif
439
440         return (rcode - 1);
441 }
442
443
444 /*
445  *  Display the syntax for starting this program.
446  */
447 static void NEVER_RETURNS usage(int status)
448 {
449         FILE *output = status?stderr:stdout;
450
451         fprintf(output,
452                         "Usage: %s [-d db_dir] [-l log_dir] [-i address] [-n name] [-fsvXx]\n", progname);
453         fprintf(output, "Options:\n\n");
454         fprintf(output, "  -C              Check configuration and exit.\n");
455         fprintf(output, "  -d raddb_dir    Configuration files are in \"raddbdir/*\".\n");
456         fprintf(output, "  -f              Run as a foreground process, not a daemon.\n");
457         fprintf(output, "  -h              Print this help message.\n");
458         fprintf(output, "  -i ipaddr       Listen on ipaddr ONLY\n");
459         fprintf(output, "  -n name         Read raddb/name.conf instead of raddb/radiusd.conf\n");
460         fprintf(output, "  -p port         Listen on port ONLY\n");
461         fprintf(output, "  -s              Do not spawn child processes to handle requests.\n");
462         fprintf(output, "  -v              Print server version information.\n");
463         fprintf(output, "  -X              Turn on full debugging.\n");
464         fprintf(output, "  -x              Turn on additional debugging. (-xx gives more debugging).\n");
465         exit(status);
466 }
467
468
469 /*
470  *      We got a fatal signal.
471  */
472 static void sig_fatal(int sig)
473 {
474         switch(sig) {
475                 case SIGSEGV:
476                         /*
477                          *      We can't really do anything
478                          *      intelligent here so just die
479                          */
480                         _exit(1);
481
482                 case SIGTERM:
483                         radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
484                         break;
485
486                 case SIGINT:
487 #ifdef SIGQUIT
488                 case SIGQUIT:
489 #endif
490                         if (debug_memory) {
491                                 radius_signal_self(RADIUS_SIGNAL_SELF_TERM);
492                                 break;
493                         }
494                         /* FALL-THROUGH */
495
496                 default:
497                         radius_signal_self(RADIUS_SIGNAL_SELF_EXIT);
498                         break;
499         }
500 }
501
502 #ifdef SIGHUP
503 /*
504  *  We got the hangup signal.
505  *  Re-read the configuration files.
506  */
507 static void sig_hup(int sig)
508 {
509         sig = sig; /* -Wunused */
510
511         reset_signal(SIGHUP, sig_hup);
512
513         radius_signal_self(RADIUS_SIGNAL_SELF_HUP);
514 }
515 #endif