Massively cleaned up #include's, so they're in a consistent
[freeradius.git] / src / main / exec.c
index d472bc2..aa982b0 100644 (file)
  *
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  *
- * Copyright 2000  The FreeRADIUS server project
- * Copyright 2000  Michael J. Hartwick <hartwick@hartwick.com>
+ * Copyright 2000-2004,2006  The FreeRADIUS server project
  */
-static const char rcsid[] = "$Id$";
 
-#include "autoconf.h"
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
+
+#include <freeradius-devel/radiusd.h>
+#include <freeradius-devel/rad_assert.h>
 
 #include <sys/file.h>
 
-#include <stdlib.h>
-#include <string.h>
 #include <fcntl.h>
 #include <ctype.h>
-#include <unistd.h>
 #include <signal.h>
 
 #ifdef HAVE_SYS_WAIT_H
@@ -43,98 +42,6 @@ static const char rcsid[] = "$Id$";
 #      define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
 #endif
 
-#include "radiusd.h"
-#include "rad_assert.h"
-
-/*
- *     Copy a quoted string.
- */
-static int rad_copy_string(char *to, const char *from)
-{
-       int length = 0;
-       char quote = *from;
-
-       do {
-               if (*from == '\\') {
-                       *(to++) = *(from++);
-                       length++;
-               }
-               *(to++) = *(from++);
-               length++;
-       } while (*from && (*from != quote));
-
-       if (*from != quote) return -1; /* not properly quoted */
-
-       *(to++) = quote;
-       length++;
-       *to = '\0';
-
-       return length;
-}
-
-
-/*
- *     Copy a %{} string.
- */
-static int rad_copy_variable(char *to, const char *from)
-{
-       int length = 0;
-       int sublen;
-
-       *(to++) = *(from++);
-       length++;
-
-       while (*from) {
-               switch (*from) {
-               case '"':
-               case '\'':
-                       sublen = rad_copy_string(to, from);
-                       if (sublen < 0) return sublen;
-                       from += sublen;
-                       to += sublen;
-                       break;
-
-               case '}':       /* end of variable expansion */
-                       *(to++) = *(from++);
-                       *to = '\0';
-                       length++;
-                       return length; /* proper end of variable */
-
-               case '\\':
-                       *(to++) = *(from++);
-                       *(to++) = *(from++);
-                       length += 2;
-                       break;
-
-               case '%':       /* start of variable expansion */
-                       if (from[1] == '{') {
-                               *(to++) = *(from++);
-                               length++;
-                               
-                               sublen = rad_copy_variable(to, from);
-                               if (sublen < 0) return sublen;
-                               from += sublen;
-                               to += sublen;
-                               length += sublen;
-                       } /* else FIXME: catch %%{ ?*/
-
-                       /* FALL-THROUGH */
-                       break;
-
-               default:
-                       *(to++) = *(from++);
-                       length++;
-                       break;
-               }
-       } /* loop over the input string */
-
-       /*
-        *      We ended the string before a trailing '}'
-        */
-
-       return -1;
-}
-
 #define MAX_ARGV (256)
 /*
  *     Execute a program on successful authentication.
@@ -146,7 +53,8 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                        int exec_wait,
                        char *user_msg, int msg_len,
                        VALUE_PAIR *input_pairs,
-                       VALUE_PAIR **output_pairs)
+                       VALUE_PAIR **output_pairs,
+                       int shell_escape)
 {
        VALUE_PAIR *vp;
        char mycmd[1024];
@@ -179,7 +87,7 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                return -1;
        }
 
-       strNcpy(mycmd, cmd, sizeof(mycmd));
+       strlcpy(mycmd, cmd, sizeof(mycmd));
 
        /*
         *      Split the string into argv's BEFORE doing radius_xlat...
@@ -293,8 +201,7 @@ int radius_exec_program(const char *cmd, REQUEST *request,
        argv[argc] = NULL;
 
        /*
-        *      Open a pipe for child/parent communication, if
-        *      necessary.
+        *      Open a pipe for child/parent communication, if necessary.
         */
        if (exec_wait) {
                if (pipe(pd) != 0) {
@@ -311,7 +218,13 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                output_pairs = NULL;
        }
 
-       if ((pid = rad_fork(exec_wait)) == 0) {
+       if (exec_wait) {
+               pid = rad_fork();       /* remember PID */
+       } else {
+               pid = fork();           /* don't wait */
+       }
+
+       if (pid == 0) {
 #define MAX_ENVP 1024
                int devnull;
                char *envp[MAX_ENVP];
@@ -321,7 +234,7 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                /*
                 *      Child process.
                 *
-                *      We try to be fail-safe here.  So if ANYTHING
+                *      We try to be fail-safe here. So if ANYTHING
                 *      goes wrong, we exit with status 1.
                 */
 
@@ -399,16 +312,18 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                         *      variable...
                         */
                        snprintf(buffer, sizeof(buffer), "%s=", vp->name);
-                       for (p = buffer; *p != '='; p++) {
-                               if (*p == '-') {
-                                       *p = '_';
-                               } else if (isalpha((int) *p)) {
-                                       *p = toupper(*p);
+                       if (shell_escape) {
+                               for (p = buffer; *p != '='; p++) {
+                                       if (*p == '-') {
+                                               *p = '_';
+                                       } else if (isalpha((int) *p)) {
+                                               *p = toupper(*p);
+                                       }
                                }
                        }
 
                        n = strlen(buffer);
-                       vp_prints_value(buffer+n, sizeof(buffer) - n, vp, 1);
+                       vp_prints_value(buffer+n, sizeof(buffer) - n, vp, shell_escape);
 
                        envp[envlen++] = strdup(buffer);
 
@@ -418,6 +333,7 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                        if (envlen == (MAX_ENVP - 1)) break;
                }
                envp[envlen] = NULL;
+
                execve(argv[0], argv, envp);
                radlog(L_ERR, "Exec-Program: FAILED to execute %s: %s",
                       argv[0], strerror(errno));
@@ -434,8 +350,7 @@ int radius_exec_program(const char *cmd, REQUEST *request,
        }
 
        /*
-        *      We're not waiting, exit, and ignore any child's
-        *      status.
+        *      We're not waiting, exit, and ignore any child's status.
         */
        if (!exec_wait) {
                return 0;
@@ -505,7 +420,7 @@ int radius_exec_program(const char *cmd, REQUEST *request,
         *      Parse the output, if any.
         */
        if (done) {
-               n = T_INVALID;
+               n = T_OP_INVALID;
                if (output_pairs) {
                        /*
                         *      For backwards compatibility, first check
@@ -518,10 +433,10 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                        }
                }
 
-               if (n == T_INVALID) {
-                       radlog(L_DBG, "Exec-Program-Wait: plaintext: %s", answer);
+               if (n == T_OP_INVALID) {
+                       DEBUG("Exec-Program-Wait: plaintext: %s", answer);
                        if (user_msg) {
-                               strNcpy(user_msg, answer, msg_len);
+                               strlcpy(user_msg, answer, msg_len);
                        }
                } else {
                        /*
@@ -540,14 +455,14 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                        }
 
                        /*
-                        *  Replace any trailing comma by a NUL.
+                        *      Replace any trailing comma by a NUL.
                         */
                        if (answer[strlen(answer) - 1] == ',') {
                                answer[strlen(answer) - 1] = '\0';
                        }
 
                        radlog(L_DBG,"Exec-Program-Wait: value-pairs: %s", answer);
-                       if (userparse(answer, &vp) == T_INVALID) {
+                       if (userparse(answer, &vp) == T_OP_INVALID) {
                                radlog(L_ERR, "Exec-Program-Wait: %s: unparsable reply", cmd);
 
                        } else {
@@ -558,13 +473,18 @@ int radius_exec_program(const char *cmd, REQUEST *request,
                                *output_pairs = vp;
                        }
                } /* else the answer was a set of VP's, not a text message */
-       } /* else we didn't read anything from the child. */
+       } /* else we didn't read anything from the child */
 
        /*
         *      Call rad_waitpid (should map to waitpid on non-threaded
         *      or single-server systems).
         */
-       child_pid = rad_waitpid(pid, &status, 0);
+       child_pid = rad_waitpid(pid, &status);
+       if (child_pid == 0) {
+               radlog(L_DBG, "Exec-Program: Timeout waiting for child");
+               return 2;
+       }
+
        if (child_pid == pid) {
                if (WIFEXITED(status)) {
                        status = WEXITSTATUS(status);