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

Diff of /radius/radiusd/exec.c

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

revision 1.48 by gray, Thu Feb 6 09:47:53 2003 UTC revision 1.49 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) 2002,2003 Sergey Poznyakoff
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_EXEC_C  #define RADIUS_MODULE_EXEC_C
 #ifndef lint  
 static char rcsid[] =  
 "@(#) $Id$";  
 #endif  
19    
20  #ifdef HAVE_CONFIG_H  #ifdef HAVE_CONFIG_H
21  # include <config.h>  # include <config.h>
# Line 48  static char rcsid[] = Line 44  static char rcsid[] =
44  #include <symtab.h>  #include <symtab.h>
45  #include <rewrite.h>  #include <rewrite.h>
46    
 struct cleanup_data {  
         VALUE_PAIR **vp;  
         FILE *fp;  
         pid_t pid;  
 };  
   
 void  
 rad_exec_cleanup(arg)  
         void *arg;  
 {  
         struct cleanup_data *p = arg;  
   
         fclose(p->fp);  
         avl_free(*p->vp);  
         if (p->pid > 0)  
                 kill(p->pid, SIGKILL);  
 }  
47    
48  int  int
49  radius_change_uid(pwd)  radius_change_uid(struct passwd *pwd)
         struct passwd *pwd;  
50  {  {
51          if (pwd->pw_gid != 0 && setgid(pwd->pw_gid)) {          if (pwd->pw_gid != 0 && setgid(pwd->pw_gid)) {
52                  radlog(L_ERR|L_PERROR,                  radlog(L_ERR|L_PERROR,
# Line 91  radius_change_uid(pwd) Line 69  radius_change_uid(pwd)
69          }          }
70  }  }
71    
 static int  
 exec_sigchld(sig, data, id, owner)  
         int sig;  
         void *data;  
         rad_sigid_t id;  
         const void *owner;  
 {  
         int status;  
         pid_t pid = *(pid_t*)data;  
         if (waitpid(pid, &status, 0) == pid) {  
                 rad_signal_remove(sig, id, owner);  
                 return 0;  
         }  
         return 1;  
 }  
   
72  /* Execute a program on successful authentication.  /* Execute a program on successful authentication.
73     Return 0 if exec_wait == 0.     Return 0 if exec_wait == 0.
74     Return the exit code of the called program if exec_wait != 0.     Return the exit code of the called program if exec_wait != 0. */
    NOTE: The routine relies upon SIGCHLD being set ti SIG_IGN and  
    SIGPIPE being set to SIG_DFL. */  
75  int  int
76  radius_exec_program(cmd, req, reply, exec_wait, user_msg)  radius_exec_program(char *cmd, RADIUS_REQ *req, VALUE_PAIR **reply,
77          char *cmd;                      int exec_wait, char **user_msg)
         RADIUS_REQ *req;  
         VALUE_PAIR **reply;  
         int exec_wait;  
         char **user_msg;  
78  {  {
79          int p[2];          int p[2];
80          int n;          int n;
# Line 127  radius_exec_program(cmd, req, reply, exe Line 83  radius_exec_program(cmd, req, reply, exe
83          FILE *fp;          FILE *fp;
84          int line_num;          int line_num;
85          char buffer[RAD_BUFFER_SIZE];          char buffer[RAD_BUFFER_SIZE];
86          struct passwd pw, *pwd;          struct passwd *pwd;
         struct cleanup_data cleanup_data;  
87          pid_t pid;          pid_t pid;
88          int status;          int status;
89          rad_sigid_t id = NULL;          RETSIGTYPE (*oldsig)();
90                    
91          if (cmd[0] != '/') {          if (cmd[0] != '/') {
92                  radlog(L_ERR,                  radlog(L_ERR,
# Line 143  radius_exec_program(cmd, req, reply, exe Line 98  radius_exec_program(cmd, req, reply, exe
98          /* Check user/group          /* Check user/group
99             FIXME: This should be checked *once* after re-reading the             FIXME: This should be checked *once* after re-reading the
100             configuration */             configuration */
101          pwd = rad_getpwnam_r(exec_user, &pw, buffer, sizeof buffer);          pwd = getpwnam(exec_user);
102          if (!pwd) {          if (!pwd) {
103                  radlog(L_ERR,                  radlog(L_ERR,
104      _("radius_exec_program(): won't execute, no such user: %s"),      _("radius_exec_program(): won't execute, no such user: %s"),
# Line 156  radius_exec_program(cmd, req, reply, exe Line 111  radius_exec_program(cmd, req, reply, exe
111                          radlog(L_ERR|L_PERROR, _("couldn't open pipe"));                          radlog(L_ERR|L_PERROR, _("couldn't open pipe"));
112                          return -1;                          return -1;
113                  }                  }
114          } else                  if ((oldsig = signal(SIGCHLD, SIG_DFL)) == SIG_ERR) {
115                  id = rad_signal_install(SIGCHLD, SH_SYNC, exec_sigchld, &pid);                          radlog(L_ERR|L_PERROR, _("can't reset SIGCHLD"));
116                            return -1;
117                    }
118            }
119    
120          if ((pid = fork()) == 0) {          if ((pid = fork()) == 0) {
121                  int argc;                  int argc;
# Line 201  radius_exec_program(cmd, req, reply, exe Line 159  radius_exec_program(cmd, req, reply, exe
159          /* Parent branch */          /* Parent branch */
160          if (pid < 0) {          if (pid < 0) {
161                  radlog(L_ERR|L_PERROR, "fork");                  radlog(L_ERR|L_PERROR, "fork");
                 if (id)  
                         rad_signal_remove (SIGCHLD, id, NULL);  
162                  return -1;                  return -1;
163          }          }
164          if (!exec_wait)          if (!exec_wait)
# Line 216  radius_exec_program(cmd, req, reply, exe Line 172  radius_exec_program(cmd, req, reply, exe
172          vp = NULL;          vp = NULL;
173          line_num = 0;          line_num = 0;
174    
         cleanup_data.vp = &vp;  
         cleanup_data.fp = fp;  
         cleanup_data.pid = pid;  
         pthread_cleanup_push((void (*)(void*))rad_exec_cleanup, &cleanup_data);  
   
175          while (ptr = fgets(buffer, sizeof(buffer), fp)) {          while (ptr = fgets(buffer, sizeof(buffer), fp)) {
176                  line_num++;                  line_num++;
177                  debug(1, ("got `%s'", buffer));                  debug(1, ("got `%s'", buffer));
# Line 233  radius_exec_program(cmd, req, reply, exe Line 184  radius_exec_program(cmd, req, reply, exe
184                  }                  }
185          }          }
186    
         waitpid(pid, &status, 0);  
   
         pthread_cleanup_pop(0);  
   
187          fclose(fp);          fclose(fp);
188    
189          if (vp) {          if (vp) {
# Line 244  radius_exec_program(cmd, req, reply, exe Line 191  radius_exec_program(cmd, req, reply, exe
191                  avl_free(vp);                  avl_free(vp);
192          }          }
193    
194            waitpid(pid, &status, 0);
195            if (signal(SIGCHLD, oldsig) == SIG_ERR)
196                    radlog(L_CRIT|L_PERROR,
197                            _("can't restore SIGCHLD"));
198    
199          if (WIFEXITED(status)) {          if (WIFEXITED(status)) {
200                  status = WEXITSTATUS(status);                  status = WEXITSTATUS(status);
201                  debug(1, ("returned: %d", status));                  debug(1, ("returned: %d", status));
# Line 263  radius_exec_program(cmd, req, reply, exe Line 215  radius_exec_program(cmd, req, reply, exe
215  }  }
216    
217  pid_t  pid_t
218  radius_run_filter(argc, argv, errfile, p)  radius_run_filter(int argc, char **argv, char *errfile, int *p)
         int  argc;  
         char **argv;  
         char *errfile;  
         int  *p;  
219  {  {
220          pid_t  pid;          pid_t  pid;
221          int    rightp[2], leftp[2];          int    rightp[2], leftp[2];
222          struct passwd pw, *pwd;          struct passwd *pwd;
         char buffer[512];  
223          int i;          int i;
224    
225          pwd = rad_getpwnam_r(exec_user, &pw, buffer, sizeof buffer);          pwd = getpwnam(exec_user);
226          if (!pwd) {          if (!pwd) {
227                  radlog(L_ERR,                  radlog(L_ERR,
228                         _("won't execute, no such user: %s"),                         _("won't execute, no such user: %s"),
# Line 345  radius_run_filter(argc, argv, errfile, p Line 292  radius_run_filter(argc, argv, errfile, p
292          return pid;          return pid;
293  }  }
294    
295  int  typedef struct filter_symbol Filter;
 timed_readline(fd, buffer, buflen, abstime)  
         int fd;  
         char *buffer;  
         size_t buflen;  
         struct timeval *abstime;  
 {  
         struct timeval tv;  
         fd_set rset;  
         int rc;  
         int rbytes = 0;  
           
         while (1) {  
                 rc = -1;  
                 if (rbytes >= buflen-1) {  
                         errno = ENOMEM;  
                         break;  
                 }  
                 gettimeofday(&tv, NULL);  
                 if (timercmp(&tv, abstime, >)) {  
                         errno = ETIMEDOUT;  
                         break;  
                 }  
                 tv.tv_sec = abstime->tv_sec - tv.tv_sec;  
                 if (abstime->tv_usec > tv.tv_usec)  
                         tv.tv_usec = abstime->tv_usec - tv.tv_usec;  
                 else {  
                         tv.tv_usec = 1000000 + abstime->tv_usec - tv.tv_usec;  
                         tv.tv_sec++;  
                 }  
                 FD_ZERO(&rset);  
                 FD_SET(fd, &rset);  
                 rc = select(fd + 1, &rset, NULL, NULL, &tv);  
                 if (rc < 0) {  
                         if (errno == EINTR)  
                                 continue;  
                         else  
                                 break;  
                 }  
                 if (FD_ISSET(fd, &rset)) {  
                         if (read(fd, buffer + rbytes, 1) != 1)  
                                 break;  
                         rbytes++;  
                         if (buffer[rbytes-1] == '\n') {  
                                 rc = 0;  
                                 break;  
                         }  
                 }  
         }  
                                   
         buffer[rbytes] = 0;  
         return rc == 0 ? rbytes : rc;  
 }  
   
 typedef struct filter_symbol Filter_symbol;  
 typedef struct filter_runtime_data Filter;  
   
 struct filter_runtime_data {  
         Filter *next;  
         Filter_symbol *sym;  
   
         pthread_mutex_t mutex;      /* Mutex for sigid */  
         rad_sigid_t id;             /* Signal handler */  
         pid_t  oldpid;              /* Pid of the exited filter process */  
         int    status;              /* Exit status of it */  
         int    stopped;             /* SIGKILL has been sent to the filter */  
           
         pthread_t tid;              /* Thread ID of the thread this filter  
                                        belongs to */  
         pid_t  pid;                 /* Pid of the filter process */  
         size_t lines_input;         /* Number of lines read from the filter */  
         size_t lines_output;        /* Number of lines written to the filter */  
         int    input;               /* Input file descriptor */  
         int    output;              /* Output file descriptor */  
 };  
296    
297  /* NOTE,NOTE,NOTE: The code below works on the assumption that  /* NOTE,NOTE,NOTE: The code below works on the assumption that
298     R_AUTH=0, R_ACCT=1 */     R_AUTH=0, R_ACCT=1 */
# Line 427  struct filter_runtime_data { Line 300  struct filter_runtime_data {
300  #define FILTER_MAX  2  #define FILTER_MAX  2
301    
302  struct filter_symbol {  struct filter_symbol {
303          struct user_symbol *next;          struct filter_symbol *next;
304          char *name;                 /* Name of the filter */          char *name;                 /* Name of the filter */
305          /* Configuration data */          /* Configuration data */
306          int line_num;               /* Number of line in raddb/config where          int line_num;               /* Number of line in raddb/config where
# Line 435  struct filter_symbol { Line 308  struct filter_symbol {
308          int  argc;                  /* Number of entries in the argv */          int  argc;                  /* Number of entries in the argv */
309          char **argv;                /* Invocation vector */          char **argv;                /* Invocation vector */
310          char *errfile;              /* Filename for error output (fd 2) */          char *errfile;              /* Filename for error output (fd 2) */
         int common;                 /* Is the filter common for all threads */  
         int max_percent;            /* For common filters, maximum percentage  
                                        of threads allowed to wait on the mutex.  
                                        When this number of threads is reached,  
                                        the filter is deemed to have hung */  
311          struct {          struct {
312                  char *input_fmt;                      char *input_fmt;    
313                  int wait_reply;                  int wait_reply;
314                  int on_fail;                  int on_fail;
315          } descr[FILTER_MAX];          } descr[FILTER_MAX];
316                    
317          Filter *filter;             /* Runtime data */          /* Runtime data */
318          int counter;                /* Number of threads currently waiting          pid_t  pid;                 /* Pid of the filter process */
319                                         on the mutex */          size_t lines_input;         /* Number of lines read from the filter */
320          pthread_mutex_t mutex;      /* Prevent concurrent access */          size_t lines_output;        /* Number of lines written to the filter */
321            int    input;               /* Input file descriptor */
322            int    output;              /* Output file descriptor */
323  };  };
324    
325  static Symtab *filter_tab;  static Symtab *filter_tab;
 static Filter_symbol filter_symbol;  
326    
327  static void filter_lock(Filter *filter);  struct cleanup_info {
328  static void filter_unlock(Filter *filter);          pid_t pid;
329  static void filter_close(Filter *filter);          int status;
330  static Filter *filter_open(char *name, RADIUS_REQ *req, int type, int *errp);  };
 static char *filter_xlate(struct obstack *sp, char *fmt, RADIUS_REQ *radreq);  
 static int filter_write(Filter *filter, char *fmt, RADIUS_REQ *radreq);  
 static int filter_read(Filter *filter, int type, char *buffer, size_t buflen);  
 static int filter_stmt_handler(int argc, cfg_value_t *argv, void *block_data,  
                                void *handler_data);  
 static int filter_stmt_end(void *block_data, void *handler_data);  
 static int exec_path_handler(int argc, cfg_value_t *argv, void *block_data,  
                              void *handler_data);  
 static int error_log_handler(int argc, cfg_value_t *argv, void *block_data,  
                              void *handler_data);  
 static int _store_format_ptr(int argc, cfg_value_t *argv, void *block_data,  
                              void *handler_data);  
   
   
 static int  
 filter_cleanup_proc(unused, sym)  
         void *unused;  
         Filter_symbol *sym;  
 {  
         Filter *filter;  
         pthread_t tid = pthread_self();  
331                    
         for (filter = sym->filter; filter; filter = filter->next) {  
                 if (filter->tid == tid)  
                         filter_close(filter);  
         }  
 }  
   
 /* Called from the first thread cleanup handler */  
 void  
 filter_cleanup()  
 {  
         symtab_iterate(filter_tab, filter_cleanup_proc, NULL);  
 }  
   
332  static int  static int
333  filter_symbol_lock(sym, type)  filter_cleanup_proc(void *ptr, Filter *filter)
         Filter_symbol *sym;  
         int type;  
334  {  {
335          int rc;          struct cleanup_info *info = ptr;
         int counter = sym->counter;  
           
         if (sym->common  
             && sym->max_percent  
             && num_threads > max_threads * sym->max_percent / 100  
             && counter > num_threads * sym->max_percent / 100) {  
                 radlog(L_NOTICE,  
                        _("Too many (%d) threads waiting for filter %s."),  
                        counter,  
                        sym->name);  
                 return 1;  
         }  
336    
337          sym->counter++;          if (filter->pid == info->pid) {
338          rc = radiusd_mutex_lock(&sym->mutex, type);                  static char buffer[512];
339          sym->counter--;                  
340          return 0;                  format_exit_status(buffer, sizeof buffer, info->status);
341  }                  radlog(L_ERR,
342                           _("filter %s (pid %d) %s (in: %u, out: %u)"),
343  static void                         filter->name, filter->pid,
344  filter_symbol_unlock(sym)                         buffer,
345          Filter_symbol *sym;                         filter->lines_input, filter->lines_output);
346  {                  filter->pid = 0;
347          radiusd_mutex_unlock(&sym->mutex);          }
 }  
   
 static void  
 filter_lock(filter)  
         Filter *filter;  
 {  
         if (filter->sym->common)  
                 Pthread_mutex_lock(&filter->sym->mutex);  
348  }  }
349    
350  static void  void
351  filter_unlock(filter)  filter_cleanup(pid_t pid, int status)
352          Filter *filter;  {      
353  {          struct cleanup_info info;
354          if (filter->sym->common)          info.pid = pid;
355                  Pthread_mutex_unlock(&filter->sym->mutex);          info.status = status;
356            symtab_iterate(filter_tab, filter_cleanup_proc, &info);
357  }  }
358    
 int  
 filter_sigchld(sig, data, id, owner)  
         int sig;  
         void *data;  
         rad_sigid_t id;  
         void *owner;  
 {  
         Filter *filter = data;  
         int status;  
           
         if (waitpid(filter->pid, &filter->status, WNOHANG) == filter->pid) {  
                 if (filter->input >= 0) {  
                         close(filter->input);  
                         filter->input = -1;  
                 }  
                 if (filter->output >= 0) {  
                         close(filter->output);  
                         filter->output = -1;  
                 }  
   
                 filter->oldpid = filter->pid;  
                 filter->pid = -1;  
                 rad_signal_remove(SIGCHLD, filter->id, owner);  
                 filter->id = 0;  
                 filter->stopped = 0;  
                   
                 return 0;  
         }  
         return 1;  
 }  
           
359  void  void
360  filter_close(filter)  filter_close(Filter *filter)
         Filter *filter;  
361  {  {
362          if (filter->pid == -1)          if (filter->pid == -1)
363                  return;                  return;
# Line 588  filter_close(filter) Line 370  filter_close(filter)
370                  close(filter->output);                  close(filter->output);
371                  filter->output = -1;                  filter->output = -1;
372          }          }
373          if (filter->pid > 0)          if (filter->pid > 0) {
374                  kill(filter->pid, SIGTERM);                  kill(filter->pid, SIGTERM);
375                    filter->pid = 0;
376          filter->stopped = 1;          }
377  }  }
378    
379  void  void
380  filter_kill(filter)  filter_kill(Filter *filter)
         Filter *filter;  
381  {  {
382          if (filter->pid == -1 || !filter->stopped)            if (filter->pid == 0)  
383                  return;                  return;
384          do {          kill(filter->pid, SIGKILL);
                 kill(filter->pid, SIGKILL);  
                 sleep(2);  
         } while (filter->pid != -1);  
385  }  }
386    
387  static Filter *  static Filter *
388  filter_open(name, req, type, errp)  filter_open(char *name, RADIUS_REQ *req, int type, int *errp)
         char *name;  
         RADIUS_REQ *req;  
         int type;  
         int *errp;  
389  {  {
390          Filter *filter;          Filter *filter = sym_lookup(filter_tab, name);
391          Filter_symbol *sym = sym_lookup(filter_tab, name);          if (!filter) {
         if (!sym) {  
392                  radlog_req(L_ERR, req,                  radlog_req(L_ERR, req,
393                             _("filter %s is not declared"),                             _("filter %s is not declared"),
394                             name);                             name);
# Line 623  filter_open(name, req, type, errp) Line 396  filter_open(name, req, type, errp)
396                  return NULL;                  return NULL;
397          }          }
398    
399          *errp = sym->descr[type].on_fail;          *errp = filter->descr[type].on_fail;
         pthread_cleanup_push((void (*)(void*))filter_symbol_unlock, sym);  
         if (filter_symbol_lock(sym, type))  
                 return NULL;  
           
         if (!sym->common) {  
                 pthread_t tid = pthread_self();  
                 for (filter = sym->filter; filter; filter = filter->next)  
                         if (filter->tid == tid)  
                                 break;  
         } else  
                 filter = sym->filter;  
         if (!filter) {  
                 filter = mem_alloc(sizeof(*filter));  
                 filter->tid = pthread_self();  
                 filter->sym = sym;  
                 filter->input = filter->output = -1;  
                 pthread_mutex_init(&filter->mutex, NULL);  
                 filter->next = sym->filter;  
                 sym->filter = filter;  
         } else {  
                 if (filter->stopped) {  
                         radlog(L_ERR,  
                                _("Killing unresponsive filter %s (pid %d)"),  
                                filter->sym->name, filter->pid);  
                         filter_kill(filter);  
                 }  
                   
                 if (filter->pid <= 0) {  
                         char buffer[80];  
                         Filter_symbol *sym = filter->sym;  
                   
                         format_exit_status(buffer, sizeof buffer,  
                                            filter->status);  
                         radlog(L_ERR,  
                                _("filter %s (pid %d) %s (in: %u, out: %u)"),  
                                sym->name, filter->oldpid,  
                                buffer,  
                                filter->lines_input, filter->lines_output);  
                 }  
         }  
           
400          if (filter && filter->pid <= 0) {          if (filter && filter->pid <= 0) {
401                  int pipe[2];                  int pipe[2];
402    
403                  pthread_mutex_lock(&filter->mutex);                  filter->pid = radius_run_filter(filter->argc,
404                  filter->id = rad_signal_install(SIGCHLD, SH_SYNC,                                                  filter->argv,
405                                                  filter_sigchld,                                                  filter->errfile,
                                                 filter);  
                 filter->pid = radius_run_filter(sym->argc, sym->argv,  
                                                 sym->errfile,  
406                                                  pipe);                                                  pipe);
                 pthread_mutex_unlock(&filter->mutex);  
407                                    
408                  if (filter->pid < 0) {                  if (filter->pid <= 0) {
409                          radlog_req(L_ERR|L_PERROR, req,                          radlog_req(L_ERR|L_PERROR, req,
410                                     _("cannot run filter %s"),                                     _("cannot run filter %s"),
411                                     name);                                     name);
                         rad_signal_remove(SIGCHLD, filter->id, NULL);  
                         filter->id = 0;  
412                          filter = NULL;                          filter = NULL;
413                  } else {                  } else {
414                          if (!sym->descr[R_AUTH].wait_reply                          if (!filter->descr[R_AUTH].wait_reply
415                              && !sym->descr[R_ACCT].wait_reply) {                              && !filter->descr[R_ACCT].wait_reply) {
416                                  close(pipe[0]);                                  close(pipe[0]);
417                                  filter->input = -1;                                  filter->input = -1;
418                          } else                          } else
# Line 702  filter_open(name, req, type, errp) Line 428  filter_open(name, req, type, errp)
428                  filter_close(filter);                  filter_close(filter);
429                  filter = NULL;                  filter = NULL;
430          }          }
         pthread_cleanup_pop(1);  
431    
432          return filter;          return filter;
433  }  }
434    
 static void  
 cleanup_obstack(arg)  
         void *arg;  
 {  
         struct obstack *stk = arg;  
         obstack_free(stk, NULL);  
 }  
   
435  static char *  static char *
436  filter_xlate(sp, fmt, radreq)  filter_xlate(struct obstack *sp, char *fmt, RADIUS_REQ *radreq)
         struct obstack *sp;  
         char *fmt;  
         RADIUS_REQ *radreq;  
437  {  {
438          char *str;          char *str;
439            
440          if (fmt[0] == '=') {          if (fmt[0] == '=') {
441                  Datatype type;                  Datatype type;
442                  Datum datum;                  Datum datum;
# Line 743  filter_xlate(sp, fmt, radreq) Line 458  filter_xlate(sp, fmt, radreq)
458  }  }
459    
460  static int  static int
461  filter_write(filter, fmt, radreq)  filter_write(Filter *filter, char *fmt, RADIUS_REQ *radreq)
         Filter *filter;  
         char *fmt;  
         RADIUS_REQ *radreq;  
462  {  {
463          int rc, length;          int rc, length;
464          struct obstack stack;          struct obstack stack;
# Line 756  filter_write(filter, fmt, radreq) Line 468  filter_write(filter, fmt, radreq)
468                  return -1;                  return -1;
469                    
470          obstack_init(&stack);          obstack_init(&stack);
         pthread_cleanup_push((void (*)(void*))cleanup_obstack, &stack);  
471          str = filter_xlate(&stack, fmt, radreq);          str = filter_xlate(&stack, fmt, radreq);
472          if (!str) {          if (!str) {
473                  rc = length = 0;                  rc = length = 0;
474          } else {          } else {
475                  char nl = '\n';                  char nl = '\n';
476                  length = strlen(str);                  length = strlen(str);
477                  debug(1,("%s < \"%s\"", filter->sym->name, str));                  debug(1,("%s < \"%s\"", filter->name, str));
478                  rc = write(filter->output, str, length);                  rc = write(filter->output, str, length);
479                  if (rc == length) {                  if (rc == length) {
480                          if (write(filter->output, &nl, 1) == 1)                          if (write(filter->output, &nl, 1) == 1)
# Line 771  filter_write(filter, fmt, radreq) Line 482  filter_write(filter, fmt, radreq)
482                  }                  }
483    
484          }          }
485          pthread_cleanup_pop(1);          obstack_free(&stack, NULL);
486          filter->lines_output++;          filter->lines_output++;
487          return rc != length + 1;          return rc != length + 1;
488  }  }
489    
490  static int  static int
491  filter_read(filter, type, buffer, buflen)  filter_read(Filter *filter, int type, char *buffer, size_t buflen)
         Filter *filter;  
         int type;  
         char *buffer;  
         size_t buflen;  
492  {  {
493          struct timeval abstime;          int rc;
494          int status;          int rbytes = 0;
495                    
496          radiusd_get_timeout(type, &abstime);          while (1) {
497          status = timed_readline(filter->input, buffer, buflen, &abstime);                  rc = -1;
498          filter->lines_input++;                  if (rbytes >= buflen-1) {
499          return status;                          errno = ENOMEM;
500                            break;
501                    }
502                    if (read(filter->input, buffer + rbytes, 1) != 1) {
503                            if (errno == EINTR)
504                                    continue;
505                            break;
506                    }
507                    rbytes++;
508                    if (buffer[rbytes-1] == '\n') {
509                            rc = 0;
510                            break;
511                    }
512            }
513    
514            if (rc == 0) {
515                    buffer[rbytes] = 0;
516                    filter->lines_input++;
517                    return rbytes;
518            }
519            return rc;
520  }  }
521    
522  /* Interface triggered by Auth-External-Filter.  /* Interface triggered by Auth-External-Filter.
523     Returns: 0   -- Authentication succeeded     Returns: 0   -- Authentication succeeded
524              !0  -- Authentication failed */              !0  -- Authentication failed */
525  int  int
526  filter_auth(name, req, reply_pairs)  filter_auth(char *name, RADIUS_REQ *req, VALUE_PAIR **reply_pairs)
         char *name;  
         RADIUS_REQ *req;  
         VALUE_PAIR **reply_pairs;  
527  {  {
528          Filter *filter;          Filter *filter;
529          int rc = -1;          int rc = -1;
# Line 808  filter_auth(name, req, reply_pairs) Line 532  filter_auth(name, req, reply_pairs)
532          filter = filter_open(name, req, R_AUTH, &err);          filter = filter_open(name, req, R_AUTH, &err);
533          if (!filter)          if (!filter)
534                  return err;                  return err;
         pthread_cleanup_push((void (*)(void*)) filter_unlock, filter);  
         filter_lock(filter);  
535          if (filter->pid == -1)          if (filter->pid == -1)
536                  rc = err;                  rc = err;
537          else if (filter_write(filter,          else if (filter_write(filter, filter->descr[R_AUTH].input_fmt, req))
                               filter->sym->descr[R_AUTH].input_fmt, req))  
538                  rc = err;                  rc = err;
539          else if (!filter->sym->descr[R_AUTH].wait_reply)          else if (!filter->descr[R_AUTH].wait_reply)
540                  rc = 0;                  rc = 0;
541          else {          else {
542                  int status;                  int status;
# Line 826  filter_auth(name, req, reply_pairs) Line 547  filter_auth(name, req, reply_pairs)
547                  if (status <= 0) {                  if (status <= 0) {
548                          radlog(L_ERR|L_PERROR,                          radlog(L_ERR|L_PERROR,
549                                 _("reading from filter %s"),                                 _("reading from filter %s"),
550                                 filter->sym->name);                                 filter->name);
551                          filter_close(filter);                          filter_close(filter);
552                          rc = err;                          rc = err;
553                  } else if (isdigit(buffer[0])) {                  } else if (isdigit(buffer[0])) {
# Line 834  filter_auth(name, req, reply_pairs) Line 555  filter_auth(name, req, reply_pairs)
555                          VALUE_PAIR *vp = NULL;                          VALUE_PAIR *vp = NULL;
556                          char *errp;                          char *errp;
557    
558                          debug(1, ("%s > \"%s\"", filter->sym->name,                          debug(1, ("%s > \"%s\"", filter->name, buffer));
                                   buffer));  
559                          rc = strtoul(buffer, &ptr, 0);                          rc = strtoul(buffer, &ptr, 0);
560                          if (userparse(ptr, &vp, &errp)) {                          if (userparse(ptr, &vp, &errp)) {
561                                  radlog(L_ERR,                                  radlog(L_ERR,
562                                         _("<stdout of %s>:%d: %s"),                                         _("<stdout of %s>:%d: %s"),
563                                         filter->sym->name,                                         filter->name,
564                                         filter->lines_output,                                         filter->lines_output,
565                                         errp);                                         errp);
566                                  avl_free(vp);                                  avl_free(vp);
# Line 849  filter_auth(name, req, reply_pairs) Line 569  filter_auth(name, req, reply_pairs)
569                  } else {                  } else {
570                          radlog(L_ERR,                          radlog(L_ERR,
571                                 _("filter %s (auth): bad output: %s"),                                 _("filter %s (auth): bad output: %s"),
572                                 filter->sym->name, buffer);                                 filter->name, buffer);
573                          rc = err;                          rc = err;
574                  }                  }
575          }          }
576    
         pthread_cleanup_pop(1);  
577          return rc;          return rc;
578  }  }
579    
580  int  int
581  filter_acct(name, req)  filter_acct(char *name, RADIUS_REQ *req)
         char *name;  
         RADIUS_REQ *req;  
582  {  {
583          Filter *filter;          Filter *filter;
584          int rc = -1;          int rc = -1;
# Line 875  filter_acct(name, req) Line 592  filter_acct(name, req)
592          filter = filter_open(name, req, R_ACCT, &err);          filter = filter_open(name, req, R_ACCT, &err);
593          if (!filter)          if (!filter)
594                  return err;                  return err;
         pthread_cleanup_push((void (*)(void*)) filter_unlock, filter);  
         filter_lock(filter);  
595          if (filter->pid == -1)          if (filter->pid == -1)
596                  rc = err;                  rc = err;
597          else if (filter_write(filter,          else if (filter_write(filter, filter->descr[R_ACCT].input_fmt, req))
                               filter->sym->descr[R_ACCT].input_fmt, req))  
598                  rc = err;                  rc = err;
599          else if (!filter->sym->descr[R_ACCT].wait_reply)          else if (!filter->descr[R_ACCT].wait_reply)
600                  rc = 0;                  rc = 0;
601          else {          else {
602                  int status;                  int status;
# Line 893  filter_acct(name, req) Line 607  filter_acct(name, req)
607                  if (status <= 0) {                  if (status <= 0) {
608                          radlog(L_ERR|L_PERROR,                          radlog(L_ERR|L_PERROR,
609                                 _("reading from filter %s"),                                 _("reading from filter %s"),
610                                 filter->sym->name);                                 filter->name);
611                          rc = err;                          rc = err;
612                          filter_close(filter);                          filter_close(filter);
613                  } else if (isdigit(buffer[0])) {                  } else if (isdigit(buffer[0])) {
614                          char *ptr;                          char *ptr;
615                          char *errp;                          char *errp;
616    
617                          debug(1, ("%s > \"%s\"",                          debug(1, ("%s > \"%s\"", filter->name, buffer));
                                   filter->sym->name, buffer));  
618                          rc = strtoul(buffer, &ptr, 0);                          rc = strtoul(buffer, &ptr, 0);
619                  } else {                  } else {
620                          radlog(L_ERR,                          radlog(L_ERR,
621                                 _("filter %s (acct): bad output: %s"),                                 _("filter %s (acct): bad output: %s"),
622                                 filter->sym->name, buffer);                                 filter->name, buffer);
623                          rc = err;                          rc = err;
624                  }                  }
625          }          }
626    
         pthread_cleanup_pop(1);  
627          return rc;          return rc;
628  }  }
629            
630    
631    /* ***************************** Configuration ***************************** */
632    
633    static struct filter_symbol filter_symbol;
634    
635  static int  static int
636  free_symbol_entry(sym)  free_symbol_entry(Filter *filter)
         Filter_symbol *sym;  
637  {  {
638          Filter *filter;          efree(filter->descr[R_AUTH].input_fmt);
639          efree(sym->descr[R_AUTH].input_fmt);          efree(filter->descr[R_ACCT].input_fmt);
640          efree(sym->descr[R_ACCT].input_fmt);          argcv_free(filter->argc, filter->argv);
641          argcv_free(sym->argc, sym->argv);          efree(filter->errfile);
642          efree(sym->errfile);          if (filter->pid > 0)
643          filter = sym->filter;                  filter_close(filter);
         while (filter) {  
                 Filter *next = filter->next;  
                 if (filter->pid > 0)  
                         filter_close(filter);  
                 pthread_mutex_destroy(&filter->mutex);  
                 mem_free(filter);  
                 filter = next;  
         }  
         pthread_mutex_destroy(&sym->mutex);  
644          return 0;          return 0;
645  }  }
646    
647  int  int
648  filters_stmt_term(finish, block_data, handler_data)  filters_stmt_term(int finish, void *block_data, void *handler_data)
         int finish;  
         void *block_data;  
         void *handler_data;  
649  {  {
650          if (!finish) {          if (!finish) {
651                  if (filter_tab)                  if (filter_tab)
652                          symtab_clear(filter_tab);                          symtab_clear(filter_tab);
653                  else                  else
654                          filter_tab = symtab_create(sizeof(Filter_symbol),                          filter_tab = symtab_create(sizeof(Filter),
655                                                     free_symbol_entry);                                                     free_symbol_entry);
656          }          }
657          return 0;          return 0;
658  }  }
659    
660  static int  static int
661  filter_stmt_handler(argc, argv, block_data, handler_data)  filter_stmt_handler(int argc, cfg_value_t *argv, void *block_data,
662          int argc;                      void *handler_data)
         cfg_value_t *argv;  
         void *block_data;  
         void *handler_data;  
663  {  {
664          if (argc > 2) {          if (argc > 2) {
665                  cfg_argc_error(0);                  cfg_argc_error(0);
# Line 976  filter_stmt_handler(argc, argv, block_da Line 677  filter_stmt_handler(argc, argv, block_da
677          filter_symbol.errfile = NULL;          filter_symbol.errfile = NULL;
678          filter_symbol.descr[R_AUTH].wait_reply = 1;          filter_symbol.descr[R_AUTH].wait_reply = 1;
679          filter_symbol.descr[R_ACCT].wait_reply = 1;          filter_symbol.descr[R_ACCT].wait_reply = 1;
         filter_symbol.common = 0;  
680          return 0;          return 0;
681  }  }
682    
683  static int  static int
684  filter_stmt_end(block_data, handler_data)  filter_stmt_end(void *block_data, void *handler_data)
         void *block_data;  
         void *handler_data;  
685  {  {
686          if (filter_symbol.argc) {          if (filter_symbol.argc) {
687                  Filter_symbol *sym = sym_lookup_or_install(filter_tab,                  Filter *sym = sym_lookup_or_install(filter_tab,
688                                                             filter_symbol.name,                                                      filter_symbol.name,
689                                                             1);                                                      1);
690                  if (sym->argc) {                  if (sym->argc) {
691                          radlog(L_ERR,                          radlog(L_ERR,
692                                 _("%s:%d: filter already declared at %s:%d"),                                 _("%s:%d: filter already declared at %s:%d"),
# Line 1013  filter_stmt_end(block_data, handler_data Line 711  filter_stmt_end(block_data, handler_data
711                  sym->descr[R_ACCT].on_fail =                  sym->descr[R_ACCT].on_fail =
712                          !filter_symbol.descr[R_ACCT].on_fail;                          !filter_symbol.descr[R_ACCT].on_fail;
713                  sym->errfile  = estrdup(filter_symbol.errfile);                  sym->errfile  = estrdup(filter_symbol.errfile);
714                  sym->common   = filter_symbol.common;                  sym->pid = 0;
                 sym->max_percent = filter_symbol.max_percent;  
                 sym->filter = NULL;  
                 pthread_mutex_init(&sym->mutex, NULL);  
715          }          }
716          return 0;          return 0;
717  }  }
718    
719  static int  static int
720  exec_path_handler(argc, argv, block_data, handler_data)  exec_path_handler(int argc, cfg_value_t *argv,
721          int argc;                    void *block_data, void *handler_data)
         cfg_value_t *argv;  
         void *block_data;  
         void *handler_data;  
722  {  {
723          if (argc > 2) {          if (argc > 2) {
724                  cfg_argc_error(0);                  cfg_argc_error(0);
# Line 1047  exec_path_handler(argc, argv, block_data Line 739  exec_path_handler(argc, argv, block_data
739  }  }
740    
741  static int  static int
742  common_handler(argc, argv, block_data, handler_data)  error_log_handler(int argc, cfg_value_t *argv,
743          int argc;                    void *block_data, void *handler_data)
         cfg_value_t *argv;  
         void *block_data;  
         void *handler_data;  
 {  
         if (argc > 3) {  
                 cfg_argc_error(0);  
                 return 0;  
         }  
   
         if (argv[1].type != CFG_BOOLEAN) {  
                 cfg_type_error(CFG_BOOLEAN);  
                 return 0;  
         }  
   
         filter_symbol.common = argv[1].v.bool;  
   
         if (argc > 2) {  
                 if (argv[2].type != CFG_INTEGER || !filter_symbol.common)  
                         return 1;  
                 filter_symbol.max_percent = argv[2].v.number;  
                 if (filter_symbol.max_percent < 0  
                     || filter_symbol.max_percent > 100)  
                         return 1;  
         }  
         return 0;  
 }  
           
 static int  
 error_log_handler(argc, argv, block_data, handler_data)  
         int argc;  
         cfg_value_t *argv;  
         void *block_data;  
         void *handler_data;  
744  {  {
745          if (argc > 2) {          if (argc > 2) {
746                  cfg_argc_error(0);                  cfg_argc_error(0);
# Line 1107  error_log_handler(argc, argv, block_data Line 766  error_log_handler(argc, argv, block_data
766  }  }
767    
768  static int  static int
769  _store_format_ptr(argc, argv, block_data, handler_data)  _store_format_ptr(int argc, cfg_value_t *argv, void *block_data,
770          int argc;                    void *handler_data)
         cfg_value_t *argv;  
         void *block_data;  
         void *handler_data;  
771  {  {
772          if (argc > 2) {          if (argc > 2) {
773                  cfg_argc_error(0);                  cfg_argc_error(0);
# Line 1157  static struct cfg_stmt filter_acct_stmt[ Line 813  static struct cfg_stmt filter_acct_stmt[
813  static struct cfg_stmt filter_stmt[] = {  static struct cfg_stmt filter_stmt[] = {
814          { "exec-path", CS_STMT, NULL, exec_path_handler, NULL, NULL, NULL },          { "exec-path", CS_STMT, NULL, exec_path_handler, NULL, NULL, NULL },
815          { "error-log", CS_STMT, NULL, error_log_handler, NULL, NULL, NULL },          { "error-log", CS_STMT, NULL, error_log_handler, NULL, NULL, NULL },
         { "common", CS_STMT, NULL, common_handler, NULL,  
           NULL, NULL },  
816          { "auth", CS_BLOCK, NULL, NULL, NULL, filter_auth_stmt, NULL },          { "auth", CS_BLOCK, NULL, NULL, NULL, filter_auth_stmt, NULL },
817          { "acct", CS_BLOCK, NULL, NULL, NULL, filter_acct_stmt, NULL },          { "acct", CS_BLOCK, NULL, NULL, NULL, filter_acct_stmt, NULL },
818          { NULL },          { NULL },

Legend:
Removed from v.1.48  
changed lines
  Added in v.1.49

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