/[radius]/radius/radiusd/radiusd.c
ViewVC logotype

Diff of /radius/radiusd/radiusd.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.115 by gray, Mon Dec 30 15:04:39 2002 UTC revision 1.116 by gray, Fri Apr 18 05:27:10 2003 UTC
# Line 1  Line 1 
1  /* This file is part of GNU RADIUS.  /* This file is part of GNU Radius.
2     Copyright (C) 2000,2001 Sergey Poznyakoff     Copyright (C) 2000,2001,2002,2003 Free Software Foundation
3        
4     This program is free software; you can redistribute it and/or modify     GNU Radius is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.     (at your option) any later version.
8        
9     This program is distributed in the hope that it will be useful,     GNU Radius is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.     GNU General Public License for more details.
13        
14     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software Foundation,     along with GNU Radius; if not, write to the Free Software Foundation,
16     Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */     Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17    
18  #define RADIUS_MODULE_RADIUSD_C  #define RADIUS_MODULE_RADIUSD_C
   
 #ifndef lint  
 static char rcsid[] =  
 "@(#) $Id$";  
 #endif  
   
19  #ifdef HAVE_CONFIG_H  #ifdef HAVE_CONFIG_H
20  # include <config.h>  # include <config.h>
21  #endif  #endif
   
22  #include <sys/types.h>  #include <sys/types.h>
 #include <sys/socket.h>  
 #include <sys/time.h>  
 #include <sys/stat.h>  
 #include <sys/wait.h>  
23  #include <netinet/in.h>  #include <netinet/in.h>
24  #include <netdb.h>  #include <netdb.h>
25  #include <fcntl.h>  #include <fcntl.h>
# Line 39  static char rcsid[] = Line 28  static char rcsid[] =
28  #include <unistd.h>  #include <unistd.h>
29  #include <signal.h>  #include <signal.h>
30  #include <errno.h>  #include <errno.h>
31    #include <sys/wait.h>
32    
33  #include <radiusd.h>  #include <radiusd.h>
34  #include <radargp.h>  #include <radargp.h>
 #include <radsql.h>  
 #include <symtab.h>  
35  #include <radutmp.h>  #include <radutmp.h>
36  #include <rewrite.h>  #include <rewrite.h>
 #ifdef USE_SERVER_GUILE  
 # include <libguile.h>  
 #endif  
37  #include <snmp/asn1.h>  #include <snmp/asn1.h>
38  #include <snmp/snmp.h>  #include <snmp/snmp.h>
 #include <argcv.h>  
 #include <envar.h>  
39    
40  /* ********************** Request list handling **************************** */  const char *argp_program_version = "radiusd (" PACKAGE ") " VERSION;
41            static char doc[] = N_("GNU radius daemon");
 void rad_req_free(RADIUS_REQ *req);  
 int rad_req_cmp(RADIUS_REQ *a, RADIUS_REQ *b);  
 int rad_req_setup(REQUEST *radreq);  
 void rad_req_xmit(int type, int code, void *data, int fd);  
   
 struct request_class request_class[] = {  
         { "AUTH", 0, MAX_REQUEST_TIME, CLEANUP_DELAY,  
           rad_req_setup, rad_authenticate, rad_req_xmit, rad_req_cmp,  
           rad_req_free, rad_req_drop, rad_sql_cleanup },  
         { "ACCT", 0, MAX_REQUEST_TIME, CLEANUP_DELAY,  
           rad_req_setup, rad_accounting, rad_req_xmit, rad_req_cmp,  
           rad_req_free, rad_req_drop, rad_sql_cleanup },  
         { "PROXY",0, MAX_REQUEST_TIME, CLEANUP_DELAY,  
           NULL, rad_proxy, rad_req_xmit, rad_req_cmp,  
           rad_req_free, proxy_retry, NULL },  
 #ifdef USE_SNMP  
         { "SNMP", 0, MAX_REQUEST_TIME, 0,  
           NULL, snmp_answer, NULL, snmp_req_cmp,  
           snmp_req_free, snmp_req_drop, NULL },  
 #endif  
         { NULL, }  
 };  
42    
43  /* Implementation functions */  static struct argp_option options[] = {
44  int auth_respond(int fd, struct sockaddr *sa, int salen,          {NULL, 0, NULL, 0,
45                   u_char *buf, int size);           N_("radiusd specific switches:"), 0},
46  int acct_success(struct sockaddr *sa, int salen);          {"log-auth-detail", 'A', 0, 0,
47  int acct_failure(struct sockaddr *sa, int salen);           N_("Do detailed authentication logging"), 0},
48  int snmp_respond(int fd, struct sockaddr *sa, int salen,          {"acct-directory",  'a', N_("DIR"), 0,
49                   u_char *buf, int size);           N_("Set accounting directory"), 0},
50  int radiusd_respond(int fd, RADIUS_REQ *radreq, u_char *buf, size_t size);  #ifdef USE_DBM
51            {"dbm", 'b', NULL, 0,
52  struct request_handler_tab request_handler_tab[] = {           N_("Enable DBM support"), 0},
         /* AUTH */  { NULL, auth_respond, NULL },  
         /* ACCT */  { acct_success, auth_respond, acct_failure },  
         /* PROXY */ { NULL, NULL, NULL },/* not used currently */  
 #ifdef USE_SNMP  
         /* SNMP */  { NULL, snmp_respond, NULL },  
53  #endif  #endif
54            {"foreground", 'f', NULL, 0,
55             N_("Stay in foreground"), 0},
56            {"logging-directory", 'l', N_("DIR"), 0,
57             N_("Set logging directory name"), 0},
58            {"mode", 'm', "{t|c|b}", 0,
59             N_("Select operation mode: test, checkconf, builddbm.")},
60            {"do-not-resolve", 'n', NULL, 0,
61             N_("Do not resolve IP addresses"), 0},
62            {"ip-address", 'i', N_("IPADDR"), 0,
63             N_("Listen on IPADDR"), 0},
64            {"port", 'p', "NUMBER", 0,
65             N_("Set authentication port number"), 0},
66            {"pid-file-dir", 'P', N_("DIR"), 0,
67             N_("Store pidfile in DIR"), 0},
68            {"log-stripped-names", 'S', NULL, 0,
69             N_("Strip prefixes/suffixes off user names before logging")},
70            {"single-process", 's', NULL, 0,
71             N_("Run in single process mode"), 0},
72            {"debug", 'x', N_("DEBUGSPEC"), 0,
73             N_("Set debugging level"), 0},
74            {"log-auth", 'y', NULL, 0,
75             N_("Log authentications"), 0},
76            {"log-auth-pass", 'z', NULL, 0,
77             N_("Log users' passwords"), 0},
78            {NULL, 0, NULL, 0, NULL, 0}
79  };  };
80    
81  /* *************************** Global variables. ************************** */  
82    /* *************************** Global Variables **************************** */
83    
84  int        debug_flag; /* can be raised from debugger only */  int        debug_flag; /* can be raised from debugger only */
85  int        log_mode;  int        log_mode;
86    
87  static int foreground; /* Stay in the foreground */  static int foreground; /* Stay in the foreground */
88  static int spawn_flag;  static int spawn_flag;
89    
90  int use_dbm = 0;  int use_dbm = 0;
 int open_acct = 1;  
91  int auth_detail = 0;  int auth_detail = 0;
92  int acct_detail = 1;        int acct_detail = 1;      
93  int strip_names;  int strip_names;
94  int suspend_flag;  int suspend_flag;
95    
96    #define CMD_NONE     0 /* No command */
97    #define CMD_CLEANUP  1 /* Cleanup finished children */
98    #define CMD_RELOAD   2 /* The reload of the configuration is needed */
99    #define CMD_RESTART  3 /* Try to restart */
100    #define CMD_MEMINFO  4 /* Dump memory usage statistics */
101    #define CMD_DUMPDB   5 /* Dump authentication database */
102    #define CMD_SHUTDOWN 6 /* Stop immediately */
103    
104    int daemon_command = CMD_NONE;
105    
106    static INPUT *radius_input;   /* The input channels */
107    
108  #ifdef USE_SNMP  #ifdef USE_SNMP
109    int snmp_port;
110  serv_stat saved_status;  serv_stat saved_status;
111  #endif  #endif
112    
113                      /* These are the user flag marking attributes that                      /* These are the user flag marking attributes that
114                         can be used in comparing ... */                         can be used in comparing ... */
115  int auth_comp_flag; /* ... authentication requests */  int auth_comp_flag; /* ... authentication requests */
116  int acct_comp_flag; /* ... accounting requests */  int acct_comp_flag; /* ... accounting requests */
117    
118  int checkrad_assume_logged = 1;  int checkrad_assume_logged = 1;
119  int max_requests = MAX_REQUESTS;  size_t max_requests = MAX_REQUESTS;
120    size_t max_children = MAX_CHILDREN;
121  char *exec_user = NULL;  char *exec_user = NULL;
122    
123  UINT4 warning_seconds;  UINT4 warning_seconds;
124  int use_guile;  int use_guile;
125  char *message_text[MSG_COUNT];  char *message_text[MSG_COUNT];
   
126  UINT4 myip = INADDR_ANY;  UINT4 myip = INADDR_ANY;
127  UINT4 ref_ip = INADDR_ANY;  UINT4 ref_ip = INADDR_ANY;
128  int auth_port;  int auth_port;
129  int acct_port;  int acct_port;
 #ifdef USE_SNMP  
 int snmp_port;  
 #endif  
 SOCKET_LIST *socket_first;  
   
 pthread_t radius_tid;       /* Thread ID of the main thread */  
 pthread_attr_t thread_attr; /* Attribute for creating child threads */  
   
 int max_threads = 128;  /* Maximum number of threads allowed */  
 int num_threads = 0;    /* Number of threads currently spawned */  
   
 #define CMD_NONE     0 /* No command */  
 #define CMD_RELOAD   1 /* The reload of the configuration is needed */  
 #define CMD_RESTART  2 /* Try to restart ourselves when set to 1 */  
 #define CMD_MEMINFO  3 /* Dump memory usage statistics */  
 #define CMD_DUMPDB   4 /* Dump authentication database */  
 #define CMD_SHUTDOWN 5 /* Stop immediately */  
   
 int daemon_command = CMD_NONE;  
   
 static void check_reload();  
 static void check_snmp_request();  
   
 static void set_config_defaults();  
 void radiusd_exit();  
 static int sig_exit (int, void *, rad_sigid_t, const void *);  
 static int sig_fatal (int, void *, rad_sigid_t, const void *);  
 static int sig_hup (int, void *, rad_sigid_t, const void *);  
 static int sig_dumpdb (int, void *, rad_sigid_t, const void *);  
   
 static struct signal_list {  
         int mask;  /* 1 if the signal should be masked in the threads */  
         int sig;  
         int type;  
         rad_signal_t handler;  
 } rad_signal_list[] = {  
         1, SIGHUP,  SH_ASYNC, sig_hup,  
         0, SIGQUIT, SH_ASYNC, sig_exit,  
         0, SIGTERM, SH_ASYNC, sig_exit,  
         0, SIGCHLD, SH_ASYNC, NULL,  
         0, SIGBUS,  SH_ASYNC, sig_fatal,  
         0, SIGTRAP, SH_ASYNC, sig_fatal,  
         0, SIGFPE,  SH_ASYNC, sig_fatal,  
         0, SIGSEGV, SH_ASYNC, sig_fatal,  
         0, SIGILL,  SH_ASYNC, sig_fatal,  
         1, SIGINT,  SH_ASYNC, sig_dumpdb  
 };  
   
 sigset_t rad_signal_set;  
   
 static int rad_cfg_listen_auth(int argc, cfg_value_t *argv,  
                                void *block_data, void *handler_data);  
 static int rad_cfg_listen_acct(int argc, cfg_value_t *argv,  
                                void *block_data, void *handler_data);  
   
 static void reconfigure();  
 static void radiusd_daemon();  
 static void radiusd_watcher();  
 static void common_init();  
 static void radiusd_main_loop();  
 static void radiusd_fork_child_handler();  
 static void meminfo();  
 static void radiusd_before_config_hook(void *unused1, void *unused2);  
 static void radiusd_after_config_hook(void *unused1, void *unused2);  
130    
131    pid_t radiusd_pid;
132  int radius_mode = MODE_DAEMON;      int radius_mode = MODE_DAEMON;    
 int radius_port = 0;  
133    
134    /* Invocation vector for self-restart */
135  int  xargc;  int  xargc;
136  char **xargv;  char **xargv;
137  char *x_debug_spec;  char *x_debug_spec;
138    
139  extern void version(FILE *stream, struct argp_state *state);  /* Forward declarations */
140    static RETSIGTYPE sig_handler(int sig);
141    void radiusd_main_loop();
142    
143  const char *argp_program_version = "radiusd (" PACKAGE ") " VERSION;  struct cfg_stmt config_syntax[];
144  static char doc[] = N_("GNU radius daemon");  
145    
146    /* ************************ Command Line Parser **************************** */
147    
 static struct argp_option options[] = {  
         {NULL, 0, NULL, 0,  
          N_("radiusd specific switches:"), 0},  
         {"log-auth-detail", 'A', 0, 0,  
          N_("Do detailed authentication logging"), 0},  
         {"acct-directory",  'a', N_("DIR"), 0,  
          N_("Set accounting directory"), 0},  
 #ifdef USE_DBM  
         {"dbm", 'b', NULL, 0,  
          N_("Enable DBM support"), 0},  
 #endif  
         {"foreground", 'f', NULL, 0,  
          N_("Stay in foreground"), 0},  
         {"logging-directory", 'l', N_("DIR"), 0,  
          N_("Set logging directory name"), 0},  
         {"mode", 'm', "{t|c|b}", 0,  
          N_("Select operation mode: test, checkconf, builddbm.")},  
         {"auth-only", 'N', NULL, 0,  
          N_("Do only authentication"), 0},  
         {"do-not-resolve", 'n', NULL, 0,  
          N_("Do not resolve IP addresses"), 0},  
         {"ip-address", 'i', N_("IPADDR"), 0,  
          N_("Listen on IPADDR"), 0},  
         {"port", 'p', "NUMBER", 0,  
          N_("Set authentication port number"), 0},  
         {"pid-file-dir", 'P', N_("DIR"), 0,  
          N_("Store pidfile in DIR"), 0},  
         {"log-stripped-names", 'S', NULL, 0,  
          N_("Strip prefixes/suffixes off user names before logging")},  
         {"single-process", 's', NULL, 0,  
          N_("Run in single process mode"), 0},  
         {"debug", 'x', N_("DEBUGSPEC"), 0,  
          N_("Set debugging level"), 0},  
         {"log-auth", 'y', NULL, 0,  
          N_("Log authentications"), 0},  
         {"log-auth-pass", 'z', NULL, 0,  
          N_("Log users' passwords"), 0},  
         {NULL, 0, NULL, 0, NULL, 0}  
 };  
           
 /*ARGSUSED*/  
148  static error_t  static error_t
149  parse_opt (key, arg, state)  parse_opt(int key, char *arg, struct argp_state *state)
         int key;  
         char *arg;  
         struct argp_state *state;  
150  {  {
151          switch (key) {          switch (key) {
152          case 'A':          case 'A':
153                  auth_detail++;                  auth_detail++;
154                  break;                  break;
155                    
156          case 'a':          case 'a':
157                  radacct_dir = string_create(optarg);                  radacct_dir = string_create(optarg);
158                  break;                  break;
159                    
160  #ifdef USE_DBM  #ifdef USE_DBM
161          case 'b':          case 'b':
162                  use_dbm++;                  use_dbm++;
163                  break;                  break;
164  #endif  #endif
165                    
166          case 'f':          case 'f':
167                  foreground = 1;                  foreground = 1;
168                  break;                  break;
169                    
170          case 'l':          case 'l':
171                  radlog_dir = string_create(optarg);                  radlog_dir = string_create(optarg);
172                  break;                  break;
173                    
174          case 'm':          case 'm':
175                  switch (arg[0]) {                  switch (arg[0]) {
176                  case 't':                  case 't':
177                          radius_mode = MODE_TEST;                          radius_mode = MODE_TEST;
178                          break;                          break;
179                            
180                  case 'b':                  case 'b':
181  #ifdef USE_DBM  #ifdef USE_DBM
182                          radius_mode = MODE_BUILDDBM;                          radius_mode = MODE_BUILDDBM;
183  #else  #else
184                          fprintf(stderr,                          argp_error(state,
185                                  _("radiusd compiled without DBM support"));                                     _("radiusd compiled without DBM support"));
186                          exit(1);                          exit(1);
187  #endif  #endif
188                          break;                          break;
189                            
190                  case 'c':                  case 'c':
191                          radius_mode = MODE_CHECKCONF;                          radius_mode = MODE_CHECKCONF;
192                          break;                          break;
193                            
194                  default:                  default:
195                          radlog(L_ERR,                          argp_error(state, _("unknown mode: %s"), arg);
196                                 _("unknown mode: %s"), arg);                          exit(1);
197                          }                  }
                 break;  
         case 'N':  
                 open_acct = 0;  
198                  break;                  break;
199                    
200          case 'n':          case 'n':
201                  resolve_hostnames = 0;                  resolve_hostnames = 0;
202                  break;                  break;
203                    
204          case 'i':          case 'i':
205                  if ((myip = ip_gethostaddr(optarg)) == 0)                  if ((myip = ip_gethostaddr(optarg)) == 0)
206                          fprintf(stderr,                          fprintf(stderr,
207                                  _("invalid IP address: %s"),                                  _("invalid IP address: %s"),
208                                  optarg);                                  optarg);
209                  break;                  break;
210                    
211          case 'P':          case 'P':
212                  radpid_dir = optarg;                  radpid_dir = optarg;
213                  break;                  break;
214                    
215          case 'p':          case 'p':
216                  radius_port = atoi(optarg);                  auth_port = atoi(optarg);
217                    acct_port = auth_port+1;
218                  break;                  break;
219                    
220          case 'S':          case 'S':
221                  strip_names++;                    strip_names++;  
222                  break;                  break;
223                    
224          case 's':       /* Single process mode */          case 's':       /* Single process mode */
225                  spawn_flag = 0;                  spawn_flag = 0;
226                  break;                  break;
227                    
228          case 'x':          case 'x':
229                  x_debug_spec = optarg;                  x_debug_spec = optarg;
230                  set_debug_levels(optarg);                  set_debug_levels(optarg);
231                  break;                  break;
232                    
233          case 'y':          case 'y':
234                  log_mode |= RLOG_AUTH;                      log_mode |= RLOG_AUTH;    
235                  break;                  break;
236                    
237          case 'z':          case 'z':
238                  log_mode |= RLOG_AUTH_PASS;                  log_mode |= RLOG_AUTH_PASS;
239                  break;                  break;
240                    
241          default:          default:
242                  return ARGP_ERR_UNKNOWN;                  return ARGP_ERR_UNKNOWN;
243          }          }
# Line 344  static struct argp argp = { Line 253  static struct argp argp = {
253          NULL, NULL          NULL, NULL
254  };  };
255    
256  int  
257  main(argc, argv)  /* *********************** Configuration Functions ************************* */
         int argc;  
         char **argv;  
 {  
         struct servent *svp;  
         int t;  
         char *p;  
         FILE *fp;  
         pid_t pid;  
   
         for (t = getmaxfd(); t >= 3; t--)  
                 close(t);  
   
         /* debug_flag can be set only from debugger.  
            It means developer is taking control in his hands, so  
            we won't modify any variables that could prevent him  
            from doing so. */  
         if (debug_flag == 0) {  
                 foreground = 0;  
                 spawn_flag = 1;  
         }  
   
         app_setup();  
   
         /* save the invocation */  
         xargc = argc;  
         xargv = argv;  
   
         /* Set up some default values */  
         set_config_defaults();  
   
         /* Process the options.  */  
         argp_program_version_hook = version;  
         if (rad_argp_parse(&argp, &argc, &argv, 0, NULL, NULL))  
                 return 1;  
   
         log_set_default("default.log", -1, -1);  
         if (radius_mode != MODE_DAEMON)  
                 log_set_to_console();  
   
         /* Determine default port numbers for authentication and accounting */  
         if (radius_port)  
                 auth_port = radius_port;  
         else {  
                 svp = getservbyname ("radius", "udp");  
                 if (svp)  
                         auth_port = ntohs(svp->s_port);  
                 else  
                         auth_port = DEF_AUTH_PORT;  
         }  
         if (radius_port || (svp = getservbyname ("radacct", "udp")) == NULL)  
                 acct_port = auth_port + 1;  
         else  
                 acct_port = ntohs(svp->s_port);  
   
         srand(time(NULL));  
           
         /* Register radiusd hooks first. This ensures they will be  
            executed after all other hooks */  
         register_before_config_hook(radiusd_before_config_hook, NULL);  
         register_after_config_hook(radiusd_after_config_hook, NULL);  
   
         snmp_init(0, 0, (snmp_alloc_t)emalloc, (snmp_free_t)efree);  
 #ifdef USE_SNMP  
         snmpserv_init(&saved_status);  
 #endif  
   
         switch (radius_mode) {  
         case MODE_CHECKCONF:  
                 common_init();  
                 exit(0);  
   
         case MODE_TEST:  
                 common_init();  
                 exit(test_shell());  
                   
 #ifdef USE_DBM            
         case MODE_BUILDDBM:  
                 common_init();  
                 exit(builddbm(extra_arg));  
 #endif  
         case MODE_DAEMON:  
                 if (myip != INADDR_ANY)  
                         ref_ip = myip;  
                 else  
                         ref_ip = get_first_ip();  
                 if (ref_ip == INADDR_ANY)  
                     radlog(L_ALERT, _("can't find out my own IP address"));  
                   
                 chdir("/");  
                 umask(022);  
   
                 if (!foreground)  
                         radiusd_daemon();  
                   
                 common_init();  
         }  
   
         radiusd_pidfile_write(RADIUSD_PID_FILE);  
   
         radiusd_main_loop();  
         /*NOTREACHED*/  
 }  
   
258  void  void
259  set_config_defaults()  set_config_defaults()
260  {  {
# Line 472  set_config_defaults() Line 278  set_config_defaults()
278                  string_create(_("You are calling outside your allowed timespan\n"));                  string_create(_("You are calling outside your allowed timespan\n"));
279  }  }
280    
281    static int
282    get_port_number(char *name, char *proto, int defval)
283    {
284            struct servent *svp;
285    
286            svp = getservbyname(name, proto);
287            return svp ? ntohs(svp->s_port) : defval;
288    }
289    
290    void
291    radiusd_setup()
292    {
293            int i;
294    
295            /* Close unneeded file descriptors */
296            for (i = getmaxfd(); i >= 3; i--)
297                    close(i);
298            /* Determine default port numbers for authentication and accounting */
299            if (auth_port == 0)
300                    auth_port = get_port_number("radius", "udp", DEF_AUTH_PORT);
301            if (acct_port == 0)
302                    acct_port = get_port_number("radacct", "udp", auth_port+1);
303            srand(time(NULL));
304    
305            /* Register radiusd hooks first. This ensures they will be
306               executed after all other hooks */
307    #ifdef FIXME
308            register_before_config_hook(radiusd_before_config_hook, NULL);
309            register_after_config_hook(radiusd_after_config_hook, NULL);
310    #endif
311            
312            snmp_init(0, 0, (snmp_alloc_t)emalloc, (snmp_free_t)efree);
313    #ifdef USE_SNMP
314            snmpserv_init(&saved_status);
315    #endif          
316    }
317    
318    void
319    common_init()
320    {
321            int i;
322            
323            radlog(L_INFO, _("Starting"));
324    
325            radiusd_pid = getpid();
326            radius_input = input_create();
327            input_register_method(radius_input, "udp",
328                                  udp_input_handler,
329                                  udp_input_close,
330                                  udp_input_cmp);
331            input_register_method(radius_input, "rpp",
332                                  rpp_input_handler,
333                                  rpp_input_close,
334                                  NULL);
335    #ifdef HAVE_SETVBUF
336            setvbuf(stdout, NULL, _IOLBF, 0);
337    #endif
338            radiusd_signal_init(sig_handler);
339            radiusd_reconfigure();
340            if (x_debug_spec)
341                    set_debug_levels(x_debug_spec);
342            radpath_init();
343            stat_init();
344            radlog(L_INFO, _("Ready"));
345    }      
346    
347    
348    /* ************************** Core of radiusd ****************************** */
349  void  void
350  radiusd_daemon()  radiusd_daemon()
351  {  {
# Line 495  radiusd_daemon() Line 369  radiusd_daemon()
369  #endif  #endif
370          /* SIGHUP is ignored because when the session leader terminates          /* SIGHUP is ignored because when the session leader terminates
371             all process in the session are sent the SIGHUP.  */             all process in the session are sent the SIGHUP.  */
372          install_signal(SIGHUP, SIG_IGN);          signal(SIGHUP, SIG_IGN);
373    
374          /* fork() again so the parent, can exit. This means that we, as a          /* fork() again so the parent, can exit. This means that we, as a
375             non-session group leader, can never regain a controlling             non-session group leader, can never regain a controlling
# Line 527  radiusd_daemon() Line 401  radiusd_daemon()
401          efree(p);          efree(p);
402  }  }
403    
404  void  int
405  common_init()  radiusd_master()
406  {  {
407          int i;          return radiusd_pid == getpid();
408    }
409                    
410          radlog(L_INFO, _("Starting"));  
411    /* ****************************** Main function **************************** */
412    
413  #ifdef HAVE_SETVBUF  int
414          setvbuf(stdout, NULL, _IOLBF, 0);  main(int argc, char **argv)
415  #endif  {
416          radius_tid = pthread_self();          /* debug_flag can be set only from debugger.
417          pthread_attr_init(&thread_attr);             It means developer is taking control in his hands, so
418          pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);             we won't modify any variables that could prevent him
419  #ifdef HAVE_PTHREAD_ATFORK             from doing so. */
420          pthread_atfork(NULL, NULL, radiusd_fork_child_handler);          if (debug_flag == 0) {
421                    foreground = 0;
422                    spawn_flag = 1;
423            }
424            app_setup();
425    
426            /* save the invocation */
427            xargc = argc;
428            xargv = argv;
429    
430            /* Set up some default values */
431            set_config_defaults();
432    
433            /* Process the options.  */
434            argp_program_version_hook = version;
435            if (rad_argp_parse(&argp, &argc, &argv, 0, NULL, NULL))
436                    return 1;
437    
438            log_set_default("default.log", -1, -1);
439            if (radius_mode != MODE_DAEMON)
440                    log_set_to_console();
441    
442            radiusd_setup();
443    
444            switch (radius_mode) {
445            case MODE_CHECKCONF:
446                    common_init();
447                    exit(0);
448    
449            case MODE_TEST:
450                    common_init();
451                    exit(test_shell());
452                    
453    #ifdef USE_DBM          
454            case MODE_BUILDDBM:
455                    common_init();
456                    exit(builddbm(NULL));
457  #endif  #endif
458                    
459            case MODE_DAEMON:
460                    if (myip != INADDR_ANY)
461                            ref_ip = myip;
462                    else
463                            ref_ip = get_first_ip();
464                    if (ref_ip == INADDR_ANY)
465                        radlog(L_ALERT, _("can't find out my own IP address"));
466                    
467                    chdir("/");
468                    umask(022);
469    
470                    if (!foreground)
471                            radiusd_daemon();
472                    
473                    common_init();
474            }
475    
476            radiusd_pidfile_write(RADIUSD_PID_FILE);
477    
478          /* Install signal handlers */          radiusd_main_loop();
479          install_signal(SIGPIPE, SIG_IGN);          /*NOTREACHED*/
480          install_signal(SIGIOT, SIG_DFL);  }
481    
482          sigemptyset(&rad_signal_set);  static void
483          for (i = 0; i < NITEMS(rad_signal_list); i++) {  check_reload()
484                  rad_signal_install (rad_signal_list[i].sig,  {
485                                      rad_signal_list[i].type,          switch (daemon_command) {
486                                      rad_signal_list[i].handler, NULL);          case CMD_CLEANUP:
487                  if (rad_signal_list[i].mask)                  radiusd_cleanup();
488                          sigaddset(&rad_signal_set, rad_signal_list[i].sig);                  break;
489                    
490            case CMD_RELOAD:
491                    radlog(L_INFO, _("Reloading configuration now"));
492                    radiusd_reconfigure();
493                    break;
494                    
495            case CMD_RESTART:
496                    radiusd_restart();
497                    break;
498                    
499            case CMD_MEMINFO:
500    //                meminfo();
501                    break;
502                    
503            case CMD_DUMPDB:
504                    radlog(L_INFO, _("Dumping users db to `%s'"),
505                           RADIUS_DUMPDB_NAME);
506                    dump_users_db();
507                    break;
508                    
509            case CMD_SHUTDOWN:
510                    radiusd_exit();
511                    
512            default:
513                    //check_snmp_request();
514                    break;
515            }
516            daemon_command = CMD_NONE;
517    }
518    
519    void
520    radiusd_register_input_fd(char *name, int fd, void *data)
521    {
522            input_register_channel(radius_input, name, fd, data);
523    }
524    
525    void
526    radiusd_close_channel(int fd)
527    {
528            input_close_channel_fd(radius_input, fd);
529    }
530    
531    void
532    radiusd_cleanup()
533    {
534            pid_t pid;
535            int status;
536    
537            for (;;) {
538                    pid = waitpid((pid_t)-1, &status, WNOHANG);
539                    if (pid <= 0)
540                            break;
541    
542                    debug(2, ("child %d exited: %d", pid, WEXITSTATUS(status)));
543    
544                    rpp_remove(pid);
545          }          }
546            }
 #ifdef USE_SERVER_GUILE  
         start_guile();  
 #endif  
         reconfigure();  
         if (x_debug_spec)  
                 set_debug_levels(x_debug_spec);  
         radpath_init();  
         stat_init();  
         radlog(L_INFO, _("Ready"));  
 }        
547    
548  void  void
549  radiusd_thread_init()  radiusd_restart()
550    {
551            pid_t pid;
552            
553            radlog(L_NOTICE, _("restart initiated"));
554            if (xargv[0][0] != '/') {
555                    radlog(L_ERR,
556                           _("can't restart: not started as absolute pathname"));
557                    return;
558            }
559    
560            radiusd_flush_queue();
561    
562            if (foreground)
563                    pid = 0; /* make-believe we're child */
564            else
565                    pid = fork();
566            if (pid < 0) {
567                    radlog(L_CRIT|L_PERROR,
568                           _("rad_restart: cannot fork"));
569                    return;
570            }
571            
572            input_close_channels(radius_input);
573            radiusd_signal_init(SIG_DFL);
574            if (pid > 0) {
575                    /* Parent */
576                    sleep(10);
577                    exit(0);
578            }
579    
580            /* Let the things settle */
581            sleep(10);
582    
583            /* Child */
584            radlog(L_NOTICE, _("restarting radius"));
585            execvp(xargv[0], xargv);
586            radlog(L_CRIT|L_PERROR, _("RADIUS NOT RESTARTED: exec failed"));
587            exit(1);
588            /*NOTREACHED*/
589    }
590    
591    void
592    radiusd_flush_queue()
593    {
594            rpp_flush();
595    }
596                    
597    void
598    radiusd_exit()
599  {  {
600          pthread_sigmask(SIG_SETMASK, &rad_signal_set, NULL);          stat_done();
601            radiusd_pidfile_remove(RADIUSD_PID_FILE);
602            
603            radiusd_flush_queue();
604            radlog(L_CRIT, _("Normal shutdown."));
605    
606    #ifdef USE_SQL
607            radiusd_sql_shutdown();
608    #endif
609            exit(0);
610  }  }
611    
612  void  void
# Line 582  radiusd_main_loop() Line 617  radiusd_main_loop()
617          for(;;) {          for(;;) {
618                  struct timeval tv;                  struct timeval tv;
619    
620                  rad_signal_deliver ();                  check_reload();
                 check_reload();  
621                  tv.tv_sec = 2;                  tv.tv_sec = 2;
622                  tv.tv_usec = 0;                  tv.tv_usec = 0;
623                  socket_list_select(socket_first,                  input_select(radius_input, &tv);
624                                     request_handler_tab,          }
625                                     NITEMS(request_handler_tab),  }
626                                     &tv);  
627    void
628    radiusd_reconfigure()
629    {
630            int rc = 0;
631            char *filename;
632    
633            /* Flush any pending requests and empty the request queue */
634            radiusd_flush_queue();
635            request_init_queue();
636            
637            /* Terminate all subprocesses */
638            rpp_kill(-1, SIGTERM);
639            radiusd_cleanup();
640            
641            radlog(L_INFO, _("Loading configuration files."));
642            /* Read main configuration file */
643            filename = mkfilename(radius_dir, RADIUS_CONFIG);
644            cfg_read(filename, config_syntax, NULL);
645            efree(filename);
646    
647            /* Read other files */
648            rc = reload_config_file(reload_all);
649            
650            if (rc) {
651                    radlog(L_CRIT, _("Errors reading config file - EXITING"));
652                    exit(1);
653          }          }
         /*NOTREACHED*/  
654  }  }
655    
656    
657    /* ***************************** Signal Handling *************************** */
658    
659  /* ************************************************************************* */  static RETSIGTYPE
660  /* Test shell */  sig_handler(int sig)
661    {
662            switch (sig) {
663            case SIGHUP:
664                    daemon_command = CMD_RELOAD;
665                    break;
666    
667            case SIGUSR1:
668                    daemon_command = CMD_MEMINFO;
669                    break;
670    
671            case SIGUSR2:
672                    daemon_command = CMD_DUMPDB;
673                    break;
674    
675            case SIGCHLD:
676                    daemon_command = CMD_CLEANUP;
677                    break;
678    
679            case SIGTERM:
680            case SIGQUIT:
681                    daemon_command = CMD_SHUTDOWN;
682                    break;
683                    
684            case SIGPIPE:
685                    /*FIXME: Any special action? */
686                    daemon_command = CMD_CLEANUP;
687                    break;
688    
689            default:
690                    abort();
691            }
692            signal(sig, sig_handler);
693    }
694    
695    void
696    radiusd_signal_init(RETSIGTYPE (*hp)(int sig))
697    {
698            static int signum[] = {
699                    SIGHUP, SIGUSR1, SIGUSR2, SIGQUIT,
700                    SIGTERM, SIGCHLD, SIGBUS, SIGTRAP,
701                    SIGFPE, SIGSEGV, SIGILL, SIGPIPE
702            };
703            int i;
704    
705            for (i = 0; i < sizeof(signum)/sizeof(signum[0]); i++)
706                    signal(signum[i], hp);
707    }
708    
709    
710    /* ****************************** Test Shell ******************************* */
711        
712  static char buf[128];  static char buf[128];
713  int doprompt;  int doprompt;
714    
715  char *  char *
716  moreinput(buf, bufsize)  moreinput(char *buf, size_t bufsize)
         char *buf;  
         size_t bufsize;  
717  {  {
718          if (doprompt)          if (doprompt)
719                  printf("%% ");                  printf("%% ");
# Line 708  test_shell() Line 817  test_shell()
817                          printf("%d\n", parse_rewrite(tok));                          printf("%d\n", parse_rewrite(tok));
818                          break;                          break;
819                  case 'm': /*memory statistics */                  case 'm': /*memory statistics */
820                          meminfo();                          //meminfo();
821                          break;                          break;
822                  default:                  default:
823                          printf("no command\n");                          printf("no command\n");
# Line 717  test_shell() Line 826  test_shell()
826          return 0;          return 0;
827  }  }
828    
829    
830  /* ************************************************************************* */  /* ************************************************************************* */
831    
 /* Called in the child process just before fork() returns. */  
832  void  void
833  radiusd_fork_child_handler()  radiusd_pidfile_write(char *name)
834  {  {
835          socket_list_close(&socket_first);          pid_t pid = getpid();
836  }          char *p = mkfilename(radpid_dir, name);
837            FILE *fp = fopen(p, "w");
838  void          if (fp) {
839  radiusd_suspend()                  fprintf(fp, "%lu\n", (u_long) pid);
840  {                  fclose(fp);
841          suspend_flag = 1;          }
842  }          efree(p);
843    }      
844    
845  void  pid_t
846  radiusd_continue()  radiusd_pidfile_read(char *name)
847  {  {
848          suspend_flag = 0;          unsigned long val;
849  #ifdef USE_SNMP          char *p = mkfilename(radpid_dir, name);
850          server_stat.auth.status = serv_running;          FILE *fp = fopen(p, "r");
851          server_stat.acct.status = serv_running;          if (!fp)
852  #endif                    return -1;
853            if (fscanf(fp, "%lu", &val) != 1)
854                    val = -1;
855            fclose(fp);
856            efree(p);
857            return (pid_t) val;
858  }  }
859    
860  void  void
861  radiusd_schedule_restart()  radiusd_pidfile_remove(char *name)
862  {  {
863          daemon_command = CMD_RESTART;          char *p = mkfilename(radpid_dir, name);
864            unlink(p);
865            efree(p);
866  }  }
867    
 /* Clean up and exit. */  
 void  
 radiusd_exit()  
 {  
         stat_done();  
         radiusd_pidfile_remove(RADIUSD_PID_FILE);  
868    
869          radiusd_flush_queues();  
870          radlog(L_CRIT, _("Normal shutdown."));  /* ************************************************************************* */
871    static u_char recv_buffer[RAD_BUFFER_SIZE];
872    
873  #ifdef USE_SQL  struct udp_data {
874          radiusd_sql_shutdown();          int type;
875  #endif          struct sockaddr_in addr;
876          exit(0);  };
 }  
877    
878  void  int
879  radiusd_abort()  udp_input_handler(int fd, void *data)
880  {  {
881          stat_done();          struct sockaddr sa;
882          radiusd_pidfile_remove(RADIUSD_PID_FILE);          socklen_t salen = sizeof (sa);
883          exit(1);          int size;
884            struct udp_data *sd = data;
885            
886            size = recvfrom(fd, (char *) recv_buffer, sizeof(recv_buffer),
887                            0, &sa, &salen);
888            if (size < 0)
889                    request_fail(sd->type, (struct sockaddr_in*)&sa);
890            else {
891                    REQUEST *req = request_create(sd->type,
892                                                  fd,
893                                                  (struct sockaddr_in*)&sa,
894                                                  recv_buffer, size);
895    
896                    if (request_handle(req,
897                                       spawn_flag ?
898                                       rpp_forward_request : request_respond))
899                            request_free(req);
900            }
901  }  }
902    
903  int  int
904  radiusd_flush_queues()  udp_input_close(int fd, void *data)
905  {  {
906          /* Flush request queues */          close(fd);
907          radlog(L_NOTICE, _("flushing request queues"));          efree(data);
908            return 0;
         while (request_flush_list())  
                 /*nothing:FIXME*/sleep(1);  
   
         return 0;  
909  }  }
910    
 /* Restart RADIUS process  
  */  
911  int  int
912  radiusd_restart()  udp_input_cmp(const void *a, const void *b)
913  {  {
914          radlog(L_NOTICE, _("restart initiated"));          const struct udp_data *sda = a;
915          if (xargv[0][0] != '/') {          const struct udp_data *sdb = b;
916                  radlog(L_ERR,  
917                         _("can't restart: not started as absolute pathname"));          if (sda->addr.sin_port != sdb->addr.sin_port)
918                  return -1;                  return 1;
919          }          if (sda->addr.sin_addr.s_addr == INADDR_ANY
920                        || sdb->addr.sin_addr.s_addr == INADDR_ANY)
921          /* Flush request queues */                  return 0;
922          radiusd_flush_queues();          return sda->addr.sin_addr.s_addr != sdb->addr.sin_addr.s_addr;
 #ifdef USE_SQL  
         radiusd_sql_shutdown();  
 #endif  
         return radiusd_primitive_restart(0);  
923  }  }
924    
925  int  int
926  radiusd_primitive_restart(cont)  udp_open(int type, UINT4 ipaddr, int port)
         int cont;  
927  {  {
928          int i;          int fd;
929          pid_t pid;          struct sockaddr_in s;
930                    struct udp_data *p;
931          if (foreground)          
932                  pid = 0; /* make-believe we're child */          s.sin_family = AF_INET;
933          else          s.sin_addr.s_addr = htonl(ipaddr);
934                  pid = fork();          s.sin_port = htons(port);
935                    if (p = input_find_channel(radius_input, "udp", &s)) {
936          if (pid < 0) {                  char buffer[DOTTED_QUAD_LEN];
937                  radlog(L_CRIT|L_PERROR, "fork");                  radlog(L_ERR,
938                  return -1;                         _("socket %s:%d is already assigned for %s"),
939          }                         ip_iptostr(ipaddr, buffer),
940                           port,
941          /* Close all channels we were listening to */                         request_class[p->type].name);
942          socket_list_close(&socket_first);                  return 1;
943            }
944    
945          if (pid > 0) {          fd = socket(PF_INET, SOCK_DGRAM, 0);
946                  /* Parent */          if (fd < 0) {
947                  if (!cont) {                  radlog(L_CRIT|L_PERROR, "%s socket",
948                          sleep(10);                         request_class[type].name);
949                          exit(0);                  return 1;
                 }  
                 return 0;  
950          }          }
951            if (bind(fd, (struct sockaddr*) &s, sizeof(s)) < 0) {
952                    radlog(L_CRIT|L_PERROR, "%s bind", request_class[type].name);
953                    close(fd);
954                    return 1;
955            }
956    
957          /* Restore signals */          p = emalloc(sizeof(*p));
958          for (i = 0; i < NITEMS(rad_signal_list); i++)          p->type = type;
959                  install_signal(rad_signal_list[i].sig, SIG_DFL);          p->addr = s;
960                    input_register_channel(radius_input, "udp", fd, p);
961          /* Let the things settle */          return 0;
         sleep(10);  
   
         /* Child */  
         radlog(L_NOTICE, _("restarting radius"));  
         execvp(xargv[0], xargv);  
         radlog(L_CRIT|L_PERROR, _("RADIUS NOT RESTARTED: exec failed"));  
         exit(1);  
         /*NOTREACHED*/  
962  }  }
963    
964    
965    /* ************************************************************************* */
966    
967  static int _opened_auth_sockets;  static int _opened_auth_sockets;
968  int  static int _opened_acct_sockets;
 auth_stmt_begin(finish, block_data, handler_data)  
         int finish;  
         void *block_data;  
         void *handler_data;  
 {  
         if (!finish)  
                 _opened_auth_sockets = 0;  
         else if (radius_mode == MODE_DAEMON && !_opened_auth_sockets)  
                 socket_list_add(&socket_first,  
                                 R_AUTH,  
                                 INADDR_ANY, auth_port);  
         return 0;  
 }  
969    
970  /* Open authentication sockets. */  static int
971  int  rad_cfg_listen_auth(int argc, cfg_value_t *argv,
972  rad_cfg_listen_auth(argc, argv, block_data, handler_data)                      void *block_data, void *handler_data)
         int argc;  
         cfg_value_t *argv;  
         void *block_data;  
         void *handler_data;  
973  {  {
974          int i, errcnt = 0;          int i, errcnt = 0;
975                    
# Line 880  rad_cfg_listen_auth(argc, argv, block_da Line 979  rad_cfg_listen_auth(argc, argv, block_da
979                          errcnt++;                          errcnt++;
980                  }                  }
981                    
982          if (errcnt == 0 && radius_mode == MODE_DAEMON)          if (errcnt == 0 && radius_mode == MODE_DAEMON) {
983                  for (i = 1; i < argc; i++)                  for (i = 1; i < argc; i++)
984                          socket_list_add(&socket_first,                          if (udp_open(R_AUTH,
985                                          R_AUTH,                                       argv[i].v.host.ipaddr,
986                                          argv[i].v.host.ipaddr,                                       argv[i].v.host.port > 0 ?
987                                          argv[i].v.host.port > 0 ?                                       argv[i].v.host.port : auth_port))
988                                          argv[i].v.host.port : auth_port);                                  errcnt++;
989          _opened_auth_sockets++;          }
990            if (errcnt == 0)
991                    _opened_auth_sockets++;
992          return 0;          return 0;
993  }  }
994    
 static int _opened_acct_sockets;  
995  int  int
996  acct_stmt_begin(finish, block_data, handler_data)  auth_stmt_begin(int finish, void *block_data, void *handler_data)
         int finish;  
         void *block_data;  
         void *handler_data;  
997  {  {
998          if (!finish)          if (!finish)
999                  _opened_acct_sockets = 0;                  _opened_auth_sockets = 0;
1000          else if (radius_mode == MODE_DAEMON && !_opened_acct_sockets)          else if (radius_mode == MODE_DAEMON && !_opened_auth_sockets)
1001                  socket_list_add(&socket_first,                  udp_open(R_AUTH, INADDR_ANY, auth_port);
                                 R_ACCT,  
                                 INADDR_ANY, acct_port);  
1002          return 0;          return 0;
1003  }  }
1004    
1005  /* Open accounting sockets. */  static int
1006  int  rad_cfg_listen_acct(int argc, cfg_value_t *argv,
1007  rad_cfg_listen_acct(argc, argv, block_data, handler_data)                      void *block_data, void *handler_data)
         int argc;  
         cfg_value_t *argv;  
         void *block_data;  
         void *handler_data;  
1008  {  {
1009          int i, errcnt = 0;          int i, errcnt = 0;
1010                    
1011          for (i = 1; i < argc; i++)          for (i = 1; i < argc; i++)  
1012                  if (argv[i].type != CFG_HOST) {                  if (argv[i].type != CFG_HOST) {
1013                          cfg_type_error(CFG_HOST);                          cfg_type_error(CFG_HOST);
1014                          errcnt++;                          errcnt++;
1015                  }                  }
1016                    
1017          if (errcnt == 0 && open_acct && radius_mode == MODE_DAEMON)          if (errcnt == 0 && radius_mode == MODE_DAEMON) {
1018                  for (i = 1; i < argc; i++)                  for (i = 1; i < argc; i++)
1019                          socket_list_add(&socket_first,                          udp_open(R_ACCT,
1020                                          R_ACCT,                                   argv[i].v.host.ipaddr,
1021                                          argv[i].v.host.ipaddr,                                   argv[i].v.host.port > 0 ?
1022                                          argv[i].v.host.port > 0 ?                                   argv[i].v.host.port : acct_port);
1023                                          argv[i].v.host.port : acct_port);          }
1024          _opened_acct_sockets++;          _opened_acct_sockets++;
1025          return 0;          return 0;
1026  }  }
1027                    
1028    int
1029    acct_stmt_begin(int finish, void *block_data, void *handler_data)
1030    {
1031            if (!finish)
1032                    _opened_acct_sockets = 0;
1033            else if (radius_mode == MODE_DAEMON && !_opened_acct_sockets)
1034                    udp_open(R_ACCT, INADDR_ANY, acct_port);
1035            return 0;
1036    }
1037    
1038  struct cfg_stmt option_stmt[] = {  struct cfg_stmt option_stmt[] = {
1039          { "source-ip", CS_STMT, NULL, cfg_get_ipaddr, &myip,          { "source-ip", CS_STMT, NULL, cfg_get_ipaddr, &myip,
1040            NULL, NULL },            NULL, NULL },
1041          { "max-requests", CS_STMT, NULL, cfg_get_integer, &max_requests,          { "max-requests", CS_STMT, NULL, cfg_get_integer, &max_requests,
1042            NULL, NULL },            NULL, NULL },
1043          { "max-threads", CS_STMT, NULL, cfg_get_integer, &max_threads,          { "max-threads", CS_STMT, NULL, cfg_get_integer, &max_children,
1044              NULL, NULL },
1045            { "max-processes", CS_STMT, NULL, cfg_get_integer, &max_children,
1046            NULL, NULL },            NULL, NULL },
1047          { "exec-program-user", CS_STMT, NULL, cfg_get_string, &exec_user,          { "exec-program-user", CS_STMT, NULL, cfg_get_string, &exec_user,
1048            NULL, NULL },            NULL, NULL },
# Line 1060  struct cfg_stmt config_syntax[] = { Line 1163  struct cfg_stmt config_syntax[] = {
1163  #endif  #endif
1164          { NULL, },          { NULL, },
1165  };        };      
   
 /* ************************************************************************* */  
   
 struct config_hook_list {  
         struct config_hook_list *next;  
         config_hook_fp fun;  
         void *data;  
 };  
   
 static struct config_hook_list *before_list;  
 static struct config_hook_list *after_list;  
   
 static void run_config_hooks(struct config_hook_list *list,  
                              void *data);  
 static void register_config_hook(struct config_hook_list **list,  
                                  config_hook_fp fp, void *data);  
   
   
 void  
 register_config_hook(listp, fp, data)  
         struct config_hook_list **listp;  
         config_hook_fp fp;  
         void *data;  
 {  
         struct config_hook_list *p = emalloc(sizeof(*p));  
         p->fun = fp;  
         p->data = data;  
         p->next = *listp;  
         *listp = p;  
 }  
   
 void  
 run_config_hooks(list, data)  
         struct config_hook_list *list;  
         void *data;  
 {  
         for (; list; list = list->next)  
                 list->fun(list->data, data);  
 }  
   
 void  
 run_before_config_hooks(data)  
         void *data;  
 {  
         run_config_hooks(before_list, data);  
 }  
   
 void  
 run_after_config_hooks(data)  
         void *data;  
 {  
         run_config_hooks(after_list, data);  
 }  
   
 void  
 register_before_config_hook(fp, data)  
         config_hook_fp fp;  
         void *data;  
 {  
         register_config_hook(&before_list, fp, data);  
 }  
   
 void  
 register_after_config_hook(fp, data)  
         config_hook_fp fp;  
         void *data;  
 {  
         register_config_hook(&after_list, fp, data);  
 }  
   
 /* ************************************************************************* */  
   
 void  
 socket_after_reconfig(type, fd)  
         int type;  
         int fd;  
 {  
 #ifdef USE_SNMP  
         if (type == R_SNMP)  
                 set_nonblocking(fd);  
 #endif  
 }  
   
 void  
 radiusd_before_config_hook(unused1, unused2)  
         void *unused1;  
         void *unused2;  
 {  
         radiusd_flush_queues();  
         socket_list_init(socket_first);  
 }  
   
 void  
 radiusd_after_config_hook(unused1, unused2)  
         void *unused1;  
         void *unused2;  
 {  
         if (radius_mode == MODE_DAEMON) {  
                 if (socket_list_open(&socket_first) == 0) {  
                         radlog(L_ALERT,  
                                _("Radiusd is not listening on any port. Trying to continue anyway..."));  
                 }  
                 socket_list_iterate(socket_first, socket_after_reconfig);  
         }  
 }  
   
 void  
 reconfigure()  
 {  
         int res = 0;  
         char *filename;  
           
         radlog(L_INFO, _("Loading configuration files."));  
   
         run_before_config_hooks(NULL);  
   
         /* Read the options */  
         filename = mkfilename(radius_dir, RADIUS_CONFIG);  
         cfg_read(filename, config_syntax, NULL);  
         efree(filename);  
   
         res = reload_config_file(reload_all);  
           
         if (res != 0) {  
                 radlog(L_CRIT,  
                        _("Errors reading config file - EXITING"));  
                 exit(1);  
         }  
   
         run_after_config_hooks(NULL);  
 }  
   
 void  
 check_reload()  
 {  
         switch (daemon_command) {  
         case CMD_RELOAD:  
                 radlog(L_INFO, _("Reloading configuration now"));  
                 reconfigure();  
                 break;  
                   
         case CMD_RESTART:  
                 radiusd_restart();  
                 break;  
                   
         case CMD_MEMINFO:  
                 meminfo();  
                 break;  
                   
         case CMD_DUMPDB:  
                 radlog(L_INFO, _("Dumping users db to `%s'"),  
                        RADIUS_DUMPDB_NAME);  
                 dump_users_db();  
                 break;  
                   
         case CMD_SHUTDOWN:  
                 radiusd_exit();  
                   
         default:  
                 check_snmp_request();  
                 break;  
         }  
         daemon_command = CMD_NONE;  
 }  
   
 void  
 check_snmp_request()  
 {  
 #ifdef USE_SNMP  
         if (server_stat.auth.status != saved_status) {  
                 switch (server_stat.auth.status) {  
                 case serv_reset: /* Hard reset */  
                         if (xargv[0][0] != '/') {  
                                 radlog(L_NOTICE,  
                                        _("can't restart: radiusd not started as absolute pathname"));  
                                 break;  
                         }  
                         radiusd_restart();  
                         break;  
                           
                 case serv_init:  
                         reconfigure();  
                         break;  
                           
                 case serv_running:  
                         if (suspend_flag) {  
                                 suspend_flag = 0;  
                                 radlog(L_NOTICE, _("RADIUSD RUNNING"));  
                                 radiusd_continue();  
                         }  
                         break;  
                           
                 case serv_suspended:  
                         if (!suspend_flag) {  
                                 radlog(L_NOTICE, _("RADIUSD SUSPENDED"));  
                                 radiusd_suspend();  
                         }  
                         break;  
                           
                 case serv_shutdown:  
                         radiusd_exit();  
                         break;  
                 }  
                 saved_status = server_stat.auth.status;  
         }  
 #endif  
 }        
   
 int  
 meminfo_report(stat)  
         CLASS_STAT *stat;  
 {  
         radlog(L_INFO,  
                "%9d   %1d    %9d %9d %9d %9d",  
                stat->elsize,  
                stat->cont,  
                stat->elcnt,  
                stat->bucket_cnt,  
                stat->allocated_cnt,  
                stat->bucket_cnt * stat->elcnt);  
         return 0;  
 }  
   
 void  
 meminfo()  
 {  
         MEM_STAT stat;  
           
         mem_get_stat(&stat);  
   
         radlog(L_INFO,  
                _("%u classes, %u buckets are using %u bytes of memory"),  
                stat.class_cnt,  
                stat.bucket_cnt,  
                stat.bytes_allocated);  
           
         if (stat.bytes_allocated)  
                 radlog(L_INFO,  
                        _("memory utilization: %u.%1u%%"),  
                        stat.bytes_used * 100 / stat.bytes_allocated,  
                        (stat.bytes_used * 1000 / stat.bytes_allocated) % 10);  
   
         radlog(L_INFO,  
                _("    Class Cont  Els/Bucket   Buckets   ElsUsed  ElsTotal"));  
           
         mem_stat_enumerate(meminfo_report, NULL);  
   
 #ifdef LEAK_DETECTOR  
         radlog(L_INFO, _("malloc statistics: %d blocks, %d bytes"),  
                mallocstat.count, mallocstat.size);  
 #endif  
 }  
   
 /* ************************************************************************* */  
 /* Signal handling */  
   
 static int  
 sig_fatal(sig, data, id, owner)  
         int sig;  
         void *data;  
         rad_sigid_t id;  
         const void *owner;  
 {  
         radlog(L_CRIT, _("exit on signal %d"), sig);  
         abort();  
         return 0;  
 }  
   
 static int  
 sig_exit(sig, data, id, owner)  
         int sig;  
         void *data;  
         rad_sigid_t id;  
         const void *owner;  
 {  
         daemon_command = CMD_SHUTDOWN;  
         return 0;  
 }  
   
 /*ARGSUSED*/  
 static int  
 sig_hup(sig, data, id, owner)  
         int sig;  
         void *data;  
         rad_sigid_t id;  
         const void *owner;  
 {  
         daemon_command = CMD_RELOAD;  
         return 0;  
 }  
   
 /*ARGSUSED*/  
 static int  
 sig_dumpdb(sig, data, id, owner)  
         int sig;  
         void *data;  
         rad_sigid_t id;  
         const void *owner;  
 {  
         daemon_command = CMD_DUMPDB;  
         return 0;  
 }  
   
 /* ************************************************************************* */  
 /* RADIUS request handling functions */  
   
 VALUE_PAIR *  
 rad_req_recode(req, prop)  
         RADIUS_REQ *req;  
         int prop;  
 {  
         static int attrlist[] = { DA_USER_PASSWORD, DA_CHAP_PASSWORD };  
         int i;  
         VALUE_PAIR *newlist = NULL;  
         VALUE_PAIR *pair;  
         char password[AUTH_STRING_LEN+1];  
   
         for (pair = req->request; pair; pair = pair->next)  
                 for (i = 0; i < NITEMS(attrlist); i++) {  
                         if (pair->attribute == attrlist[i]  
                             && (pair->prop & prop))  
                                 break;  
                 }  
   
         if (!pair)  
                 return NULL;  
   
         newlist = avl_dup(req->request);  
         for (pair = newlist; pair; pair = pair->next)  
                 for (i = 0; i < NITEMS(attrlist); i++) {  
                         if (pair->attribute == attrlist[i]  
                             && (pair->prop & prop)) {  
                                 req_decrypt_password(password, req, pair);  
                                 string_free(pair->avp_strvalue);  
                                 pair->avp_strvalue = string_create(password);  
                                 pair->avp_strlength = strlen(pair->avp_strvalue);  
                         }  
                 }  
         return newlist;  
 }  
   
 int  
 rad_req_cmp(a, b)  
         RADIUS_REQ *a, *b;  
 {  
         int prop = 0;  
         VALUE_PAIR *alist = NULL, *blist = NULL, *ap, *bp;  
         int rc;  
         NAS *nas;  
           
         if (a->ipaddr != b->ipaddr || a->code != b->code)  
                 return 1;  
           
         if (a->id == b->id  
             && memcmp(a->vector, b->vector, sizeof(a->vector)) == 0)  
                 return 0;  
   
         if (nas = nas_request_to_nas(a))  
                 prop = envar_lookup_int(nas->args, "compare-atribute-flag", 0);  
   
         if (!prop) {  
                 switch (a->code) {  
                 case RT_AUTHENTICATION_REQUEST:  
                 case RT_AUTHENTICATION_ACK:  
                 case RT_AUTHENTICATION_REJECT:  
                 case RT_ACCESS_CHALLENGE:  
                         prop = auth_comp_flag;  
                         break;  
                 case RT_ACCOUNTING_REQUEST:  
                 case RT_ACCOUNTING_RESPONSE:  
                 case RT_ACCOUNTING_STATUS:  
                 case RT_ACCOUNTING_MESSAGE:  
                         prop = acct_comp_flag;  
                         break;  
                 }  
         }  
   
         if (prop == 0)  
                 return 1;  
   
         prop |= AP_REQ_CMP;  
         alist = rad_req_recode(a, prop);  
         blist = rad_req_recode(b, prop);  
   
         ap = alist ? alist : a->request;  
         bp = blist ? blist : b->request;  
           
         rc = avl_cmp(ap, bp, prop) || avl_cmp(bp, ap, prop);  
   
         avl_free(alist);  
         avl_free(blist);  
         return rc;  
 }  
   
 void  
 rad_req_free(req)  
         RADIUS_REQ *req;  
 {  
         debug(1,("enter: %p",req));  
         if (req->data_alloced)  
                 efree(req->data);  
         radreq_free(req);  
         debug(1,("exit"));  
 }  
   
 /*ARGSUSED*/  
 void  
 rad_req_drop(type, radreq, origreq, fd, status_str)  
         int type;  
         RADIUS_REQ *radreq, *origreq;  
         int fd;  
         char *status_str;  
 {  
         char buf[MAX_LONGNAME];  
   
         if (!radreq)  
                 radreq = origreq;  
           
         radlog_req(L_NOTICE, radreq,  
                    "%s: %s", _("Dropping packet"),  status_str);  
   
         switch (type) {  
         case R_AUTH:  
                 stat_inc(auth, radreq->ipaddr, num_dropped);  
                 break;  
         case R_ACCT:  
                 stat_inc(acct, radreq->ipaddr, num_dropped);  
         }  
 }  
   
 /*ARGSUSED*/  
 void  
 rad_req_xmit(type, code, data, fd)  
         int type;  
         int code;  
         void *data;  
         int fd;  
 {  
         RADIUS_REQ *req = (RADIUS_REQ*)data;  
   
         if (code == 0) {  
                 rad_send_reply(0, req, NULL, NULL, fd);  
                 radlog_req(L_NOTICE, req, _("Retransmitting %s reply"),  
                             request_class[type].name);  
         } else {  
                 /* We are here if the handling thread of the request  
                    had been cancelled while processing it. */  
                 rad_req_drop(type, NULL, req, fd, _("request failed"));  
         }  
 }  
   
 /*ARGSUSED*/  
 int  
 auth_respond(fd, sa, salen, buf, size)  
         int fd;  
         struct sockaddr *sa;  
         int salen;  
         u_char *buf;  
         int size;  
 {  
         RADIUS_REQ *radreq;  
         struct sockaddr_in *sin = (struct sockaddr_in *) sa;  
           
         radreq = rad_decode_pdu(ntohl(sin->sin_addr.s_addr),  
                                 ntohs(sin->sin_port),  
                                 buf,  
                                 size);  
         if (radiusd_respond(fd, radreq, buf, size))  
                 radreq_free(radreq);  
   
         return 0;  
 }  
   
 /*ARGSUSED*/  
 int  
 acct_success(sa, salen)  
         struct sockaddr *sa;  
         int salen;  
 {  
         struct sockaddr_in *sin = (struct sockaddr_in *) sa;  
         stat_inc(acct, ntohl(sin->sin_addr.s_addr), num_req);  
         return 0;  
 }  
   
 /*ARGSUSED*/  
 int  
 acct_failure(sa, salen)  
         struct sockaddr *sa;  
         int salen;  
 {  
         struct sockaddr_in *sin = (struct sockaddr_in *) sa;  
         stat_inc(acct, ntohl(sin->sin_addr.s_addr), num_bad_req);  
         return 0;  
 }  
   
 int  
 rad_request_handle(type, data, fd)  
         int type;  
         void *data;  
         int fd;  
 {  
         int num_active;  
         REQUEST *req = request_put(type, data, fd, &num_active);  
         if (!req)  
                 return -1;  
   
         if (spawn_flag) {  
                 if (num_active == num_threads) {  
                         if (num_threads == max_threads) {  
                                 radlog(L_NOTICE,  
                                        "Maximum number of threads active");  
                         } else  
                                 request_start_thread();  
                         return 0;  
                 }  
                 debug(100,("Signalling"));  
                 request_signal();  
                 debug(100,("SIGNALLED"));  
         } else  
                 request_handle(req);  
         return 0;  
 }  
   
 /* Respond to supported requests:  
    RT_AUTHENTICATION_REQUEST - Authentication request from  
                                a client network access server.  
    RT_ACCOUNTING_REQUEST -     Accounting request from  
                                a client network access server.  
   
    RT_AUTHENTICATION_ACK  
    RT_AUTHENTICATION_REJECT  
    RT_ACCOUNTING_RESPONSE -    Reply from a remote Radius server.  
                                Relay reply back to original NAS. */  
   
 int  
 radiusd_respond(activefd, radreq, buf, size)  
         int activefd;  
         RADIUS_REQ *radreq;  
         u_char *buf;  
         size_t size;  
 {  
         int type;  
           
         if (suspend_flag)  
                 return 1;  
           
         if (validate_client(radreq)) {  
                 /*FIXME: update stats */  
                 return -1;  
         }  
   
         /* Check if we support this request */  
         switch (radreq->code) {  
         case RT_AUTHENTICATION_REQUEST:  
         case RT_AUTHENTICATION_ACK:  
         case RT_AUTHENTICATION_REJECT:  
         case RT_ACCESS_CHALLENGE:  
                 type = R_AUTH;  
                 break;  
         case RT_ACCOUNTING_REQUEST:  
         case RT_ACCOUNTING_RESPONSE:  
 #if defined(RT_ASCEND_EVENT_REQUEST)              
         case RT_ASCEND_EVENT_REQUEST:  
 #endif  
                 type = R_ACCT;  
                 break;  
         default:  
                 stat_inc(acct, radreq->ipaddr, num_unknowntypes);  
                 radlog_req(L_NOTICE, radreq, _("unknown request code %d"),  
                            radreq->code);  
                 return -1;  
         }        
           
         /* Copy the static data into malloc()ed memory. */  
         radreq->data = emalloc(radreq->data_len);  
         memcpy(radreq->data, buf, radreq->data_len);  
         radreq->data_alloced = 1;  
   
         return rad_request_handle(type, radreq, activefd);  
 }  
   
 int  
 rad_req_setup(req)  
         REQUEST *req;  
 {  
         RADIUS_REQ *radreq = req->data;  
           
         debug(1, ("called"));  
   
         switch (radreq->code) {  
   
         case RT_AUTHENTICATION_REQUEST:  
                 /*  
                  *      Check request against hints and huntgroups.  
                  */  
                 stat_inc(auth, radreq->ipaddr, num_access_req);  
                 if (rad_auth_init(radreq, req->fd) < 0)  
                         return 1;  
                 /*FALLTHRU*/  
         case RT_ACCOUNTING_REQUEST:  
                 if (avl_find(radreq->request, DA_USER_NAME) == NULL)  
                         break;  
                 if (proxy_send(radreq, req->fd) != 0) {  
                         req->type = R_PROXY;  
                         return 0;  
                 }  
                 break;  
   
         case RT_AUTHENTICATION_ACK:  
         case RT_AUTHENTICATION_REJECT:  
         case RT_ACCOUNTING_RESPONSE:  
         case RT_ACCESS_CHALLENGE:  
                 if (proxy_receive(radreq, req->fd) < 0)  
                         return 1;  
                 break;  
         }  
         return 0;  
 }  
   
 /* ************************************************************************* */  
 /* SNMP request handling functions */  
 #ifdef USE_SNMP  
   
 /*ARGSUSED*/  
 int  
 snmp_respond(fd, sa, salen, buf, size)  
         int fd;  
         struct sockaddr *sa;  
         int salen;  
         u_char *buf;  
         int size;  
 {  
         struct snmp_req *snmp_req;  
         struct sockaddr_in *sin = (struct sockaddr_in *) sa;  
           
         if (snmp_req = rad_snmp_respond(buf, size, sin))  
                 return rad_request_handle(R_SNMP, snmp_req, fd);  
   
         return 0;  
 }  
   
 #endif  
   
 /* ************************************************************************* */  
   
 int  
 radiusd_mutex_lock(mutex, type)  
         pthread_mutex_t *mutex;  
         int type;  
 {  
         int rc;  
         struct timeval now, end, tv;  
   
         radiusd_get_timeout(type, &end);  
         while ((rc = pthread_mutex_trylock(mutex)) == EBUSY) {  
                 gettimeofday(&now, NULL);  
                 if (timercmp(&now, &end, >=))  
                         break;  
                 tv.tv_sec = 0;  
                 tv.tv_usec = 10;  
                 select(0, NULL, NULL, NULL, &tv);  
         }  
         return rc;  
 }  
   
 int  
 radiusd_mutex_unlock(mutex)  
         pthread_mutex_t *mutex;  
 {  
         return pthread_mutex_unlock(mutex);  
 }  
   
 void  
 radiusd_pidfile_write(name)  
         char *name;  
 {  
         pid_t pid = getpid();  
         char *p = mkfilename(radpid_dir, name);  
         FILE *fp = fopen(p, "w");  
         if (fp) {  
                 fprintf(fp, "%d\n", pid);  
                 fclose(fp);  
         }  
         efree(p);  
 }        
   
 pid_t  
 radiusd_pidfile_read(name)  
         char *name;  
 {  
         long val;  
         char *p = mkfilename(radpid_dir, name);  
         FILE *fp = fopen(p, "r");  
         if (!fp)  
                 return -1;  
         if (fscanf(fp, "%ld", &val) != 1)  
                 val = -1;  
         fclose(fp);  
         efree(p);  
         return (pid_t) val;  
 }  
   
 void  
 radiusd_pidfile_remove(name)  
         char *name;  
 {  
         char *p = mkfilename(radpid_dir, name);  
         unlink(p);  
         efree(p);  
 }  
   
 int  
 radiusd_get_timeout(type, tv)  
         int type;  
         struct timeval *tv;  
 {  
         gettimeofday(tv, NULL);  
         tv->tv_sec += request_class[type].ttl;  
         return 0;  
 }  
   

Legend:
Removed from v.1.115  
changed lines
  Added in v.1.116

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26