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