]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Split out legacy exec functions to make them easier to remove in future
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 30 Aug 2021 17:16:46 +0000 (12:16 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 30 Aug 2021 17:16:46 +0000 (12:16 -0500)
src/lib/server/exec.c
src/lib/server/exec.h
src/lib/server/exec_legacy.c [new file with mode: 0644]
src/lib/server/exec_legacy.h [new file with mode: 0644]
src/lib/server/libfreeradius-server.mk
src/lib/server/map.c
src/lib/server/tmpl_eval.c
src/lib/server/trigger.c
src/lib/unlang/tmpl.c
src/modules/rlm_exec/rlm_exec.c
src/modules/rlm_mschap/rlm_mschap.c

index d8759b192df1068e5e0bf1e21720375d9e4a988b..6a0afde2131932314a85e3ddb38e4d2001deb2f0 100644 (file)
@@ -51,10 +51,10 @@ RCSID("$Id$")
 #  define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
 #endif
 #ifndef WIFEXITED
-#  define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#  define WIFEXITED(stat_val) (((stat_val) & 0x7f) == 0)
 #endif
 
-#define MAX_ARGV (256)
+#define MAX_ENVP (1024)
 
 /** Flatten a list into individual "char *" argv-style array
  *
@@ -65,7 +65,7 @@ RCSID("$Id$")
  *     - >= 0 number of array elements in argv
  *     - <0 on error
  */
-static int fr_exec_value_box_list_to_argv(TALLOC_CTX *ctx, char ***argv_p, fr_value_box_list_t const *in)
+static int exec_value_box_list_to_argv(TALLOC_CTX *ctx, char ***argv_p, fr_value_box_list_t const *in)
 {
        char            **argv;
        fr_value_box_t  *vb = NULL;
@@ -92,7 +92,8 @@ static int fr_exec_value_box_list_to_argv(TALLOC_CTX *ctx, char ***argv_p, fr_va
        return argc;
 }
 
-static void fr_exec_pair_to_env(request_t *request, fr_pair_list_t *input_pairs, char **envp, size_t envlen, bool shell_escape)
+static void exec_pair_to_env(request_t *request, fr_pair_list_t *input_pairs, char **envp,
+                            size_t envlen, bool shell_escape)
 {
        char                    *p;
        size_t                  i;
@@ -160,9 +161,9 @@ static void fr_exec_pair_to_env(request_t *request, fr_pair_list_t *input_pairs,
  *     We try to be fail-safe here. So if ANYTHING
  *     goes wrong, we exit with status 1.
  */
-static NEVER_RETURNS void fr_exec_child(request_t *request, char **argv, char **envp,
-                                       bool exec_wait,
-                                       int stdin_pipe[static 2], int stdout_pipe[static 2], int stderr_pipe[static 2])
+static NEVER_RETURNS void exec_child(request_t *request, char **argv, char **envp,
+                                    bool exec_wait,
+                                    int stdin_pipe[static 2], int stdout_pipe[static 2], int stderr_pipe[static 2])
 {
        int devnull;
 
@@ -259,409 +260,6 @@ static NEVER_RETURNS void fr_exec_child(request_t *request, char **argv, char **
        exit(2);
 }
 
-/** Start a process
- *
- * @param[out] stdin_fd                pointer to int, receives the stdin file
- *                             descriptor. Set to NULL and the child
- *                             will have /dev/null on stdin.
- * @param[out] stdout_fd       pointer to int, receives the stdout file
- *                             descriptor. Set to NULL and the child
- *                             will have /dev/null on stdout.
- * @param[out] stderr_fd       pointer to int, receives the stderr file
- *                             descriptor. Set to NULL and the child
- *                             will have /dev/null on stderr.
- * @param[in] cmd              Command to execute. This is parsed into argv[]
- *                             parts, then each individual argv part is
- *                             xlat'ed.
- * @param[in] request          Current reuqest
- * @param[in] exec_wait                set to true to read from or write to child.
- * @param[in] input_pairs      list of value pairs - these will be put into
- *                             the environment variables of the child.
- * @param[in] shell_escape     values before passing them as arguments.
- * @return
- *     - PID of the child process.
- *     - -1 on failure.
- */
-pid_t radius_start_program(int *stdin_fd, int *stdout_fd, int *stderr_fd,
-                          char const *cmd, request_t *request, bool exec_wait,
-                          fr_pair_list_t *input_pairs, bool shell_escape)
-{
-       int             stdin_pipe[2]  = {-1, -1};
-       int             stdout_pipe[2] = {-1, -1};
-       int             stderr_pipe[2] = {-1, -1};
-       pid_t           pid;
-       int             argc;
-       int             i;
-       char const      **argv_p;
-       char            *argv[MAX_ARGV], **argv_start = argv;
-       char            argv_buf[4096];
-#define MAX_ENVP 1024
-       char            **envp;
-
-       /*
-        *      Stupid array decomposition...
-        *
-        *      If we do memcpy(&argv_p, &argv, sizeof(argv_p)) src ends up being a char **
-        *      pointing to the value of the first element.
-        */
-       memcpy(&argv_p, &argv_start, sizeof(argv_p));
-       argc = rad_expand_xlat(request, cmd, MAX_ARGV, argv_p, true, sizeof(argv_buf), argv_buf);
-       if (argc <= 0) {
-               ROPTIONAL(RPEDEBUG, PERROR, "Invalid command '%s'", cmd);
-               return -1;
-       }
-
-       if (DEBUG_ENABLED3) {
-               for (i = 0; i < argc; i++) DEBUG3("arg[%d] %s", i, argv[i]);
-       }
-
-       /*
-        *      Open a pipe for child/parent communication, if necessary.
-        */
-       if (exec_wait) {
-               if (stdin_fd) {
-                       if (pipe(stdin_pipe) != 0) {
-                               ERROR("Couldn't open pipe to child: %s", fr_syserror(errno));
-                               return -1;
-                       }
-               }
-               if (stdout_fd) {
-                       if (pipe(stdout_pipe) != 0) {
-                               ERROR("Couldn't open pipe from child: %s", fr_syserror(errno));
-                               /* safe because these either need closing or are == -1 */
-                       error:
-                               close(stdin_pipe[0]);
-                               close(stdin_pipe[1]);
-                               close(stdout_pipe[0]);
-                               close(stdout_pipe[1]);
-                               close(stderr_pipe[0]);
-                               close(stderr_pipe[1]);
-                               return -1;
-                       }
-               }
-               if (stderr_fd) {
-                       if (pipe(stderr_pipe) != 0) {
-                               ERROR("Couldn't open pipe from child: %s", fr_syserror(errno));
-
-                               goto error;
-                       }
-               }
-       }
-
-       MEM(envp = talloc_zero_array(request, char *, MAX_ENVP));
-       envp[0] = NULL;
-       if (input_pairs) fr_exec_pair_to_env(request, input_pairs, envp, MAX_ENVP, shell_escape);
-
-       pid = fork();
-       if (pid == 0) {
-               fr_exec_child(request, argv, envp, exec_wait, stdin_pipe, stdout_pipe, stderr_pipe);
-       }
-
-       /*
-        *      Free child environment variables
-        */
-       talloc_free(envp);
-
-       /*
-        *      Parent process.
-        */
-       if (pid < 0) {
-               ERROR("Couldn't fork %s: %s", argv[0], fr_syserror(errno));
-               if (exec_wait) goto error;
-       }
-
-       /*
-        *      We're done.  Do any necessary cleanups.
-        */
-       if (exec_wait) {
-               /*
-                *      Close the ends of the pipe(s) the child is using
-                *      return the ends of the pipe(s) our caller wants
-                *
-                */
-               if (stdin_fd) {
-                       *stdin_fd = stdin_pipe[1];
-                       close(stdin_pipe[0]);
-               }
-               if (stdout_fd) {
-                       *stdout_fd = stdout_pipe[0];
-                       close(stdout_pipe[1]);
-               }
-               if (stderr_fd) {
-                       *stderr_fd = stderr_pipe[0];
-                       close(stderr_pipe[1]);
-               }
-       } else {
-               (void) fr_event_pid_wait(request->el, request->el, NULL, pid, NULL, NULL);
-       }
-
-       return pid;
-}
-
-
-/** Read from the child process.
- *
- * @param fd file descriptor to read from.
- * @param pid pid of child, will be reaped if it dies.
- * @param timeout amount of time to wait, in seconds.
- * @param answer buffer to write into.
- * @param left length of buffer.
- * @return
- *     - -1 on failure.
- *     - Length of output.
- */
-int radius_readfrom_program(int fd, pid_t pid, fr_time_delta_t timeout,
-                           char *answer, int left)
-{
-       int done = 0;
-       int status;
-       fr_time_t start;
-
-       fr_nonblock(fd);
-
-       /*
-        *      Minimum timeout period is one section
-        */
-       if (timeout < NSEC) timeout = fr_time_delta_from_sec(1);
-
-       /*
-        *      Read from the pipe until we doesn't get any more or
-        *      until the message is full.
-        */
-       start = fr_time();
-       while (1) {
-               int             rcode;
-               fd_set          fds;
-               fr_time_delta_t elapsed;
-
-               FD_ZERO(&fds);
-               FD_SET(fd, &fds);
-
-               elapsed = fr_time() - start;
-               if (elapsed >= timeout) goto too_long;
-
-               rcode = select(fd + 1, &fds, NULL, NULL, &fr_time_delta_to_timeval(timeout - elapsed));
-               if (rcode == 0) {
-               too_long:
-                       DEBUG("Child PID %u is taking too much time: forcing failure and killing child.", pid);
-                       kill(pid, SIGTERM);
-                       close(fd); /* should give SIGPIPE to child, too */
-
-                       /*
-                        *      Clean up the child entry.
-                        */
-                       waitpid(pid, &status, 0);
-                       return -1;
-               }
-               if (rcode < 0) {
-                       if (errno == EINTR) continue;
-                       break;
-               }
-
-#ifdef O_NONBLOCK
-               /*
-                *      Read as many bytes as possible.  The kernel
-                *      will return the number of bytes available.
-                */
-               status = read(fd, answer + done, left);
-#else
-               /*
-                *      There's at least 1 byte ready: read it.
-                *      This is a terrible hack for non-blocking IO.
-                */
-               status = read(fd, answer + done, 1);
-#endif
-
-               /*
-                *      Nothing more to read: stop.
-                */
-               if (status == 0) {
-                       break;
-               }
-
-               /*
-                *      Error: See if we have to continue.
-                */
-               if (status < 0) {
-                       /*
-                        *      We were interrupted: continue reading.
-                        */
-                       if (errno == EINTR) {
-                               continue;
-                       }
-
-                       /*
-                        *      There was another error.  Most likely
-                        *      The child process has finished, and
-                        *      exited.
-                        */
-                       break;
-               }
-
-               done += status;
-               left -= status;
-               if (left <= 0) break;
-       }
-
-       /* Strip trailing new lines */
-       while ((done > 0) && (answer[done - 1] == '\n')) {
-               answer[--done] = '\0';
-       }
-
-       return done;
-}
-
-/** Execute a program.
- *
- * @param[in,out] ctx to allocate new fr_pair_t (s) in.
- * @param[out] out buffer to append plaintext (non valuepair) output.
- * @param[in] outlen length of out buffer.
- * @param[out] output_pairs list of value pairs - Data on child's stdout will be parsed and
- *     added into this list of value pairs.
- * @param[in] request Current request (may be NULL).
- * @param[in] cmd Command to execute. This is parsed into argv[] parts, then each individual argv
- *     part is xlat'ed.
- * @param[in] input_pairs list of value pairs - these will be available in the environment of the
- *     child.
- * @param[in] exec_wait set to 1 if you want to read from or write to child.
- * @param[in] shell_escape values before passing them as arguments.
- * @param[in] timeout amount of time to wait, in seconds.
- * @return
- *     - 0 if exec_wait==0.
- *     - exit code if exec_wait!=0.
- *     - -1 on failure.
- */
-int radius_exec_program(TALLOC_CTX *ctx, char *out, size_t outlen, fr_pair_list_t *output_pairs,
-                       request_t *request, char const *cmd, fr_pair_list_t *input_pairs,
-                       bool exec_wait, bool shell_escape, fr_time_delta_t timeout)
-
-{
-       pid_t pid;
-       int stdout_pipe;
-       char *p;
-       pid_t child_pid;
-       int comma = 0;
-       int status, ret = 0;
-       ssize_t len;
-       char answer[4096];
-
-       RDEBUG2("Executing: %s", cmd);
-
-       if (out) *out = '\0';
-
-       pid = radius_start_program(NULL, &stdout_pipe, NULL, cmd, request, exec_wait, input_pairs, shell_escape);
-       if (pid < 0) {
-               return -1;
-       }
-
-       if (!exec_wait) {
-               return 0;
-       }
-
-       len = radius_readfrom_program(stdout_pipe, pid, timeout, answer, sizeof(answer));
-       if (len < 0) {
-               /*
-                *      Failure - radius_readfrom_program will
-                *      have called close(stdout_pipe) for us
-                */
-               RERROR("Failed to read from child output");
-               return -1;
-
-       }
-       answer[len] = '\0';
-
-       /*
-        *      Make sure that the writer can't block while writing to
-        *      a pipe that no one is reading from anymore.
-        */
-       close(stdout_pipe);
-
-       if (len == 0) {
-               goto wait;
-       }
-
-       /*
-        *      Parse the output, if any.
-        */
-       if (output_pairs) {
-               fr_pair_list_t vps;
-
-               fr_pair_list_init(&vps);
-               /*
-                *      HACK: Replace '\n' with ',' so that
-                *      fr_pair_list_afrom_str() can parse the buffer in
-                *      one go (the proper way would be to
-                *      fix fr_pair_list_afrom_str(), but oh well).
-                */
-               for (p = answer; *p; p++) {
-                       if (*p == '\n') {
-                               *p = comma ? ' ' : ',';
-                               p++;
-                               comma = 0;
-                       }
-                       if (*p == ',') {
-                               comma++;
-                       }
-               }
-
-               /*
-                *      Replace any trailing comma by a NUL.
-                */
-               if (answer[len - 1] == ',') {
-                       answer[--len] = '\0';
-               }
-
-               if (fr_pair_list_afrom_str(ctx, request->dict, answer, sizeof(answer), &vps) == T_INVALID) {
-                       RPERROR("Failed parsing output from: %s", cmd);
-                       if (out) strlcpy(out, answer, len);
-                       ret = -1;
-               }
-
-               /*
-                *      We want to mark the new attributes as tainted,
-                *      but not the existing ones.
-                */
-               fr_pair_list_tainted(&vps);
-               fr_pair_list_append(output_pairs, &vps);
-
-       } else if (out) {
-               /*
-                *      We've not been told to extract output pairs,
-                *      just copy the programs output to the out
-                *      buffer.
-                */
-               strlcpy(out, answer, outlen);
-       }
-
-wait:
-       child_pid = waitpid(pid, &status, 0);
-       if (child_pid == 0) {
-               RERROR("Timeout waiting for child");
-
-               return -2;
-       }
-
-       if (child_pid == pid) {
-               if (WIFEXITED(status)) {
-                       status = WEXITSTATUS(status);
-                       if ((status != 0) || (ret < 0)) {
-                               RERROR("Program returned code (%d) and output \"%pV\"", status,
-                                      fr_box_strvalue_len(answer, len));
-                       } else {
-                               RDEBUG2("Program returned code (%d) and output \"%pV\"", status,
-                                       fr_box_strvalue_len(answer, len));
-                       }
-
-                       return ret < 0 ? ret : status;
-               }
-       }
-
-       RERROR("Abnormal child exit: %s", fr_syserror(errno));
-
-       return -1;
-}
-
-
 /** Execute a program without waiting for the program to finish.
  *
  * @param request      the request
@@ -675,7 +273,7 @@ wait:
  *  would allow finer-grained control over the attributes to put into
  *  the environment.
  */
-int fr_exec_nowait(request_t *request, fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs)
+int fr_exec_fork_nowait(request_t *request, fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs)
 {
        int             argc;
        char            **envp;
@@ -698,13 +296,13 @@ int fr_exec_nowait(request_t *request, fr_value_box_list_t *vb_list, fr_pair_lis
         */
        if (env_pairs && !fr_pair_list_empty(env_pairs)) {
                MEM(envp = talloc_zero_array(request, char *, MAX_ENVP));
-               fr_exec_pair_to_env(request, env_pairs, envp, MAX_ENVP, true);
+               exec_pair_to_env(request, env_pairs, envp, MAX_ENVP, true);
        } else {
                MEM(envp = talloc_zero_array(request, char *, 1));
                envp[0] = NULL;
        }
 
-       argc = fr_exec_value_box_list_to_argv(request, &argv, vb_list);
+       argc = exec_value_box_list_to_argv(request, &argv, vb_list);
        if (argc < 0) {
                talloc_free(envp);
                return -1;
@@ -719,12 +317,12 @@ int fr_exec_nowait(request_t *request, fr_value_box_list_t *vb_list, fr_pair_lis
        pid = fork();
 
        /*
-        *      The child never returns from calling fr_exec_child();
+        *      The child never returns from calling exec_child();
         */
        if (pid == 0) {
                int unused[2];
 
-               fr_exec_child(request, argv, envp, false, unused, unused, unused);
+               exec_child(request, argv, envp, false, unused, unused, unused);
        }
 
        /*
@@ -769,8 +367,8 @@ int fr_exec_nowait(request_t *request, fr_value_box_list_t *vb_list, fr_pair_lis
  *  would allow finer-grained control over the attributes to put into
  *  the environment.
  */
-int fr_exec_wait_start(pid_t *pid_p, int *stdin_fd, int *stdout_fd, int *stderr_fd,
-                      request_t *request, fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs)
+int fr_exec_fork_wait(pid_t *pid_p, int *stdin_fd, int *stdout_fd, int *stderr_fd,
+                     request_t *request, fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs)
 {
        int             argc;
        char            **envp;
@@ -796,13 +394,13 @@ int fr_exec_wait_start(pid_t *pid_p, int *stdin_fd, int *stdout_fd, int *stderr_
         */
        if (env_pairs) {
                MEM(envp = talloc_zero_array(request, char *, MAX_ENVP));
-               fr_exec_pair_to_env(request, env_pairs, envp, MAX_ENVP, true);
+               exec_pair_to_env(request, env_pairs, envp, MAX_ENVP, true);
        } else {
                MEM(envp = talloc_zero_array(request, char *, 1));
                envp[0] = NULL;
        }
 
-       argc = fr_exec_value_box_list_to_argv(request, &argv, vb_list);
+       argc = exec_value_box_list_to_argv(request, &argv, vb_list);
        if (argc < 0) {
        error:
                talloc_free(envp);
@@ -847,9 +445,9 @@ int fr_exec_wait_start(pid_t *pid_p, int *stdin_fd, int *stdout_fd, int *stderr_
        pid = fork();
 
        /*
-        *      The child never returns from calling fr_exec_child();
+        *      The child never returns from calling exec_child();
         */
-       if (pid == 0) fr_exec_child(request, argv, envp, true, stdin_pipe, stdout_pipe, stderr_pipe);
+       if (pid == 0) exec_child(request, argv, envp, true, stdin_pipe, stdout_pipe, stderr_pipe);
 
        /*
         *      Parent process.  Do all necessary cleanups.
@@ -895,7 +493,7 @@ int fr_exec_wait_start(pid_t *pid_p, int *stdin_fd, int *stdout_fd, int *stderr_
 /** Cleans up an exec'd process on error
  *
  * This function is intended to be called at any point after a successful
- * #fr_exec_wait_start_io call in order to release resources and cleanup
+ * #fr_exec_start call in order to release resources and cleanup
  * zombie processes.
  *
  * @param[in] exec     state to cleanup.
@@ -951,7 +549,7 @@ void fr_exec_cleanup(fr_exec_state_t *exec, int signal)
 /*
  *     Callback when exec has completed.  Record the status and tidy up.
  */
-static void exec_waitpid(fr_event_list_t *el, pid_t pid, int status, void *uctx)
+static void exec_reap(fr_event_list_t *el, pid_t pid, int status, void *uctx)
 {
        fr_exec_state_t *exec = uctx;   /* may not be talloced */
        request_t       *request = exec->request;
@@ -1195,11 +793,11 @@ static void exec_stdout_read(UNUSED fr_event_list_t *el, int fd, int flags, void
  *     - 0 on success
  *     - -1 on failure
  */
-int fr_exec_wait_start_io(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *request,
-                         fr_value_box_list_t *cmd, fr_pair_list_t *env_pairs,
-                         bool need_stdin,
-                         bool store_stdout, TALLOC_CTX *stdout_ctx,
-                         fr_time_delta_t timeout)
+int fr_exec_start(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *request,
+                 fr_value_box_list_t *cmd, fr_pair_list_t *env_pairs,
+                 bool need_stdin,
+                 bool store_stdout, TALLOC_CTX *stdout_ctx,
+                 fr_time_delta_t timeout)
 {
        int     *stdout_fd = (store_stdout || RDEBUG_ENABLED2) ? &exec->stdout_fd : NULL;
 
@@ -1216,7 +814,7 @@ int fr_exec_wait_start_io(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *req
                .stdout_ctx = stdout_ctx
        };
 
-       if (fr_exec_wait_start(&exec->pid, exec->stdin_used ? &exec->stdin_fd : NULL,
+       if (fr_exec_fork_wait(&exec->pid, exec->stdin_used ? &exec->stdin_fd : NULL,
                               stdout_fd, &exec->stderr_fd, request, cmd, exec->vps) < 0) {
                RPEDEBUG("Failed executing program");
        fail:
@@ -1235,7 +833,7 @@ int fr_exec_wait_start_io(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *req
        /*
         *      Tell the event loop that it needs to wait for this PID
         */
-       if (fr_event_pid_wait(ctx, request->el, &exec->ev_pid, exec->pid, exec_waitpid, exec) < 0) {
+       if (fr_event_pid_wait(ctx, request->el, &exec->ev_pid, exec->pid, exec_reap, exec) < 0) {
                exec->pid = -1;
                RPEDEBUG("Failed adding watcher for child process");
 
@@ -1261,7 +859,8 @@ int fr_exec_wait_start_io(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *req
        /*
         *      Setup event to kill the child process after a period of time.
         */
-       if (fr_event_timer_in(ctx, request->el, &exec->ev, timeout, exec_timeout, exec) < 0) goto fail_and_close;
+       if ((timeout > 0) && fr_event_timer_in(ctx, request->el, &exec->ev,
+                                              timeout, exec_timeout, exec) < 0) goto fail_and_close;
 
        /*
         *      If we need to parse stdout, insert a special IO handler that
index 2a01a91a8bb80d9ac76e8be225765d110ea58686..44c18825e3286092eb43028c645deaa376923de4 100644 (file)
@@ -77,30 +77,18 @@ typedef struct {
 
 } fr_exec_state_t;
 
-
-pid_t  radius_start_program(int *stdin_fd, int *stdout_fd, int *stderr_fd,
-                            char const *cmd, request_t *request, bool exec_wait,
-                            fr_pair_list_t *input_pairs, bool shell_escape);
-
-int    radius_readfrom_program(int fd, pid_t pid, fr_time_delta_t timeout,
-                               char *answer, int left);
-
-int    radius_exec_program(TALLOC_CTX *ctx, char *out, size_t outlen, fr_pair_list_t *output_pairs,
-                           request_t *request, char const *cmd, fr_pair_list_t *input_pairs,
-                           bool exec_wait, bool shell_escape, fr_time_delta_t timeout) CC_HINT(nonnull (5, 6));
-
 void   fr_exec_cleanup(fr_exec_state_t *exec, int signal);
 
-int    fr_exec_nowait(request_t *request, fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs);
+int    fr_exec_fork_nowait(request_t *request, fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs);
 
-int    fr_exec_wait_start(pid_t *pid_p, int *stdin_fd, int *stdout_fd, int *stderr_fd,
+int    fr_exec_fork_wait(pid_t *pid_p, int *stdin_fd, int *stdout_fd, int *stderr_fd,
                           request_t *request, fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs);
 
-int    fr_exec_wait_start_io(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *request,
-                             fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs,
-                             bool need_stdin,
-                             bool store_stdout, TALLOC_CTX *stdout_ctx,
-                             fr_time_delta_t timeout);
+int    fr_exec_start(TALLOC_CTX *ctx, fr_exec_state_t *exec, request_t *request,
+                     fr_value_box_list_t *vb_list, fr_pair_list_t *env_pairs,
+                     bool need_stdin,
+                     bool store_stdout, TALLOC_CTX *stdout_ctx,
+                     fr_time_delta_t timeout);
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/lib/server/exec_legacy.c b/src/lib/server/exec_legacy.c
new file mode 100644 (file)
index 0000000..ce50698
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file src/lib/server/exec_legacy.c
+ * @brief Execute external programs.
+ *
+ * @copyright 2000-2004,2006 The FreeRADIUS server project
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/server/exec.h>
+#include <freeradius-devel/server/exec_legacy.h>
+#include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/server/request.h>
+#include <freeradius-devel/server/util.h>
+#include <freeradius-devel/unlang/interpret.h>
+
+#include <freeradius-devel/util/dlist.h>
+#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/pair_legacy.h>
+#include <freeradius-devel/util/syserror.h>
+#include <freeradius-devel/util/atexit.h>
+
+#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
+
+#include <sys/file.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_WAIT_H
+#  include <sys/wait.h>
+#endif
+#ifndef WEXITSTATUS
+#  define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+#ifndef WIFEXITED
+#  define WIFEXITED(stat_val) (((stat_val) & 0x7f) == 0)
+#endif
+
+#define MAX_ARGV (256)
+
+static void exec_pair_to_env_legacy(request_t *request, fr_pair_list_t *input_pairs, char **envp,
+                                   size_t envlen, bool shell_escape)
+{
+       char                    *p;
+       size_t                  i;
+       fr_dcursor_t            cursor;
+       fr_dict_attr_t const    *da;
+       fr_pair_t               *vp;
+       char                    buffer[1024];
+
+       /*
+        *      Set up the environment variables in the
+        *      parent, so we don't call libc functions that
+        *      hold mutexes.  They might be locked when we fork,
+        *      and will remain locked in the child.
+        */
+       for (vp = fr_pair_list_head(input_pairs), i = 0;
+            vp && (i < envlen - 1);
+            vp = fr_pair_list_next(input_pairs, vp)) {
+               size_t n;
+
+               /*
+                *      Hmm... maybe we shouldn't pass the
+                *      user's password in an environment
+                *      variable...
+                */
+               snprintf(buffer, sizeof(buffer), "%s=", vp->da->name);
+               if (shell_escape) {
+                       for (p = buffer; *p != '='; p++) {
+                               if (*p == '-') {
+                                       *p = '_';
+                               } else if (isalpha((int) *p)) {
+                                       *p = toupper(*p);
+                               }
+                       }
+               }
+
+               n = strlen(buffer);
+               fr_pair_print_value_quoted(&FR_SBUFF_OUT(buffer + n, sizeof(buffer) - n), vp,
+                                          shell_escape ? T_DOUBLE_QUOTED_STRING : T_BARE_WORD);
+
+               DEBUG3("export %s", buffer);
+               envp[i++] = talloc_typed_strdup(envp, buffer);
+       }
+
+       if (request) {
+               da = fr_dict_attr_child_by_num(fr_dict_root(fr_dict_internal()), FR_EXEC_EXPORT);
+               if (da) {
+                       for (vp = fr_dcursor_iter_by_da_init(&cursor, &request->control_pairs, da);
+                            vp && (i < (envlen - 1));
+                            vp = fr_dcursor_next(&cursor)) {
+                               DEBUG3("export %pV", &vp->data);
+                               memcpy(&envp[i++], &vp->vp_strvalue, sizeof(*envp));
+                       }
+
+                       /*
+                        *      NULL terminate for execve
+                        */
+                       envp[i] = NULL;
+               }
+       }
+}
+
+
+/*
+ *     Child process.
+ *
+ *     We try to be fail-safe here. So if ANYTHING
+ *     goes wrong, we exit with status 1.
+ */
+static NEVER_RETURNS void exec_child_legacy(request_t *request, char **argv, char **envp,
+                                           bool exec_wait,
+                                           int stdin_pipe[static 2], int stdout_pipe[static 2], int stderr_pipe[static 2])
+{
+       int devnull;
+
+       /*
+        *      Open STDIN to /dev/null
+        */
+       devnull = open("/dev/null", O_RDWR);
+       if (devnull < 0) {
+               fprintf(stderr, "Failed opening /dev/null: %s\n", fr_syserror(errno));
+
+               /*
+                *      Where the status code is interpreted as a module rcode
+                *      one is subtracted from it, to allow 0 to equal success
+                *
+                *      2 is RLM_MODULE_FAIL + 1
+                */
+               exit(2);
+       }
+
+       /*
+        *      Only massage the pipe handles if the parent
+        *      has created them.
+        */
+       if (exec_wait) {
+               if (stdin_pipe[1] >= 0) {
+                       close(stdin_pipe[1]);
+                       dup2(stdin_pipe[0], STDIN_FILENO);
+               } else {
+                       dup2(devnull, STDIN_FILENO);
+               }
+
+               if (stdout_pipe[1] >= 0) {
+                       close(stdout_pipe[0]);
+                       dup2(stdout_pipe[1], STDOUT_FILENO);
+               } else {
+                       dup2(devnull, STDOUT_FILENO);
+               }
+
+               if (stderr_pipe[1] >= 0) {
+                       close(stderr_pipe[0]);
+                       dup2(stderr_pipe[1], STDERR_FILENO);
+               } else {
+                       dup2(devnull, STDERR_FILENO);
+               }
+       } else {        /* no pipe, STDOUT should be /dev/null */
+               dup2(devnull, STDIN_FILENO);
+               dup2(devnull, STDOUT_FILENO);
+
+               /*
+                *      If we're not debugging, then we can't do
+                *      anything with the error messages, so we throw
+                *      them away.
+                *
+                *      If we are debugging, then we want the error
+                *      messages to go to the STDERR of the server.
+                */
+               if (!request || !RDEBUG_ENABLED) dup2(devnull, STDERR_FILENO);
+       }
+
+       close(devnull);
+
+       /*
+        *      The server may have MANY FD's open.  We don't
+        *      want to leave dangling FD's for the child process
+        *      to play funky games with, so we close them.
+        */
+       closefrom(STDERR_FILENO + 1);
+
+       /*
+        *      Disarm the thread local destructors
+        *
+        *      FIXME - Leaving them enabled causes issues in child
+        *      execd processes, but we should really track down why.
+        */
+       fr_atexit_thread_local_disarm_all();
+
+       /*
+        *      I swear the signature for execve is wrong and should
+        *      take 'char const * const argv[]'.
+        *
+        *      Note: execve(), unlike system(), treats all the space
+        *      delimited arguments as literals, so there's no need
+        *      to perform additional escaping.
+        */
+       execve(argv[0], argv, envp);
+       printf("Failed to execute \"%s\": %s", argv[0], fr_syserror(errno)); /* fork output will be captured */
+
+       /*
+        *      Where the status code is interpreted as a module rcode
+        *      one is subtracted from it, to allow 0 to equal success
+        *
+        *      2 is RLM_MODULE_FAIL + 1
+        */
+       exit(2);
+}
+
+
+/** Start a process
+ *
+ * @param[out] stdin_fd                pointer to int, receives the stdin file
+ *                             descriptor. Set to NULL and the child
+ *                             will have /dev/null on stdin.
+ * @param[out] stdout_fd       pointer to int, receives the stdout file
+ *                             descriptor. Set to NULL and the child
+ *                             will have /dev/null on stdout.
+ * @param[out] stderr_fd       pointer to int, receives the stderr file
+ *                             descriptor. Set to NULL and the child
+ *                             will have /dev/null on stderr.
+ * @param[in] cmd              Command to execute. This is parsed into argv[]
+ *                             parts, then each individual argv part is
+ *                             xlat'ed.
+ * @param[in] request          Current reuqest
+ * @param[in] exec_wait                set to true to read from or write to child.
+ * @param[in] input_pairs      list of value pairs - these will be put into
+ *                             the environment variables of the child.
+ * @param[in] shell_escape     values before passing them as arguments.
+ * @return
+ *     - PID of the child process.
+ *     - -1 on failure.
+ */
+pid_t radius_start_program_legacy(int *stdin_fd, int *stdout_fd, int *stderr_fd,
+                                 char const *cmd, request_t *request, bool exec_wait,
+                                 fr_pair_list_t *input_pairs, bool shell_escape)
+{
+       int             stdin_pipe[2]  = {-1, -1};
+       int             stdout_pipe[2] = {-1, -1};
+       int             stderr_pipe[2] = {-1, -1};
+       pid_t           pid;
+       int             argc;
+       int             i;
+       char const      **argv_p;
+       char            *argv[MAX_ARGV], **argv_start = argv;
+       char            argv_buf[4096];
+#define MAX_ENVP 1024
+       char            **envp;
+
+       /*
+        *      Stupid array decomposition...
+        *
+        *      If we do memcpy(&argv_p, &argv, sizeof(argv_p)) src ends up being a char **
+        *      pointing to the value of the first element.
+        */
+       memcpy(&argv_p, &argv_start, sizeof(argv_p));
+       argc = rad_expand_xlat(request, cmd, MAX_ARGV, argv_p, true, sizeof(argv_buf), argv_buf);
+       if (argc <= 0) {
+               ROPTIONAL(RPEDEBUG, PERROR, "Invalid command '%s'", cmd);
+               return -1;
+       }
+
+       if (DEBUG_ENABLED3) {
+               for (i = 0; i < argc; i++) DEBUG3("arg[%d] %s", i, argv[i]);
+       }
+
+       /*
+        *      Open a pipe for child/parent communication, if necessary.
+        */
+       if (exec_wait) {
+               if (stdin_fd) {
+                       if (pipe(stdin_pipe) != 0) {
+                               ERROR("Couldn't open pipe to child: %s", fr_syserror(errno));
+                               return -1;
+                       }
+               }
+               if (stdout_fd) {
+                       if (pipe(stdout_pipe) != 0) {
+                               ERROR("Couldn't open pipe from child: %s", fr_syserror(errno));
+                               /* safe because these either need closing or are == -1 */
+                       error:
+                               close(stdin_pipe[0]);
+                               close(stdin_pipe[1]);
+                               close(stdout_pipe[0]);
+                               close(stdout_pipe[1]);
+                               close(stderr_pipe[0]);
+                               close(stderr_pipe[1]);
+                               return -1;
+                       }
+               }
+               if (stderr_fd) {
+                       if (pipe(stderr_pipe) != 0) {
+                               ERROR("Couldn't open pipe from child: %s", fr_syserror(errno));
+
+                               goto error;
+                       }
+               }
+       }
+
+       MEM(envp = talloc_zero_array(request, char *, MAX_ENVP));
+       envp[0] = NULL;
+       if (input_pairs) exec_pair_to_env_legacy(request, input_pairs, envp, MAX_ENVP, shell_escape);
+
+       pid = fork();
+       if (pid == 0) {
+               exec_child_legacy(request, argv, envp, exec_wait, stdin_pipe, stdout_pipe, stderr_pipe);
+       }
+
+       /*
+        *      Free child environment variables
+        */
+       talloc_free(envp);
+
+       /*
+        *      Parent process.
+        */
+       if (pid < 0) {
+               ERROR("Couldn't fork %s: %s", argv[0], fr_syserror(errno));
+               if (exec_wait) goto error;
+       }
+
+       /*
+        *      We're done.  Do any necessary cleanups.
+        */
+       if (exec_wait) {
+               /*
+                *      Close the ends of the pipe(s) the child is using
+                *      return the ends of the pipe(s) our caller wants
+                *
+                */
+               if (stdin_fd) {
+                       *stdin_fd = stdin_pipe[1];
+                       close(stdin_pipe[0]);
+               }
+               if (stdout_fd) {
+                       *stdout_fd = stdout_pipe[0];
+                       close(stdout_pipe[1]);
+               }
+               if (stderr_fd) {
+                       *stderr_fd = stderr_pipe[0];
+                       close(stderr_pipe[1]);
+               }
+       } else {
+               (void) fr_event_pid_wait(request->el, request->el, NULL, pid, NULL, NULL);
+       }
+
+       return pid;
+}
+
+
+/** Read from the child process.
+ *
+ * @param fd file descriptor to read from.
+ * @param pid pid of child, will be reaped if it dies.
+ * @param timeout amount of time to wait, in seconds.
+ * @param answer buffer to write into.
+ * @param left length of buffer.
+ * @return
+ *     - -1 on failure.
+ *     - Length of output.
+ */
+int radius_readfrom_program_legacy(int fd, pid_t pid, fr_time_delta_t timeout, char *answer, int left)
+{
+       int done = 0;
+       int status;
+       fr_time_t start;
+
+       fr_nonblock(fd);
+
+       /*
+        *      Minimum timeout period is one section
+        */
+       if (timeout < NSEC) timeout = fr_time_delta_from_sec(1);
+
+       /*
+        *      Read from the pipe until we doesn't get any more or
+        *      until the message is full.
+        */
+       start = fr_time();
+       while (1) {
+               int             rcode;
+               fd_set          fds;
+               fr_time_delta_t elapsed;
+
+               FD_ZERO(&fds);
+               FD_SET(fd, &fds);
+
+               elapsed = fr_time() - start;
+               if (elapsed >= timeout) goto too_long;
+
+               rcode = select(fd + 1, &fds, NULL, NULL, &fr_time_delta_to_timeval(timeout - elapsed));
+               if (rcode == 0) {
+               too_long:
+                       DEBUG("Child PID %u is taking too much time: forcing failure and killing child.", pid);
+                       kill(pid, SIGTERM);
+                       close(fd); /* should give SIGPIPE to child, too */
+
+                       /*
+                        *      Clean up the child entry.
+                        */
+                       waitpid(pid, &status, 0);
+                       return -1;
+               }
+               if (rcode < 0) {
+                       if (errno == EINTR) continue;
+                       break;
+               }
+
+#ifdef O_NONBLOCK
+               /*
+                *      Read as many bytes as possible.  The kernel
+                *      will return the number of bytes available.
+                */
+               status = read(fd, answer + done, left);
+#else
+               /*
+                *      There's at least 1 byte ready: read it.
+                *      This is a terrible hack for non-blocking IO.
+                */
+               status = read(fd, answer + done, 1);
+#endif
+
+               /*
+                *      Nothing more to read: stop.
+                */
+               if (status == 0) {
+                       break;
+               }
+
+               /*
+                *      Error: See if we have to continue.
+                */
+               if (status < 0) {
+                       /*
+                        *      We were interrupted: continue reading.
+                        */
+                       if (errno == EINTR) {
+                               continue;
+                       }
+
+                       /*
+                        *      There was another error.  Most likely
+                        *      The child process has finished, and
+                        *      exited.
+                        */
+                       break;
+               }
+
+               done += status;
+               left -= status;
+               if (left <= 0) break;
+       }
+
+       /* Strip trailing new lines */
+       while ((done > 0) && (answer[done - 1] == '\n')) {
+               answer[--done] = '\0';
+       }
+
+       return done;
+}
+
+/** Execute a program.
+ *
+ * @param[in,out] ctx to allocate new fr_pair_t (s) in.
+ * @param[out] out buffer to append plaintext (non valuepair) output.
+ * @param[in] outlen length of out buffer.
+ * @param[out] output_pairs list of value pairs - Data on child's stdout will be parsed and
+ *     added into this list of value pairs.
+ * @param[in] request Current request (may be NULL).
+ * @param[in] cmd Command to execute. This is parsed into argv[] parts, then each individual argv
+ *     part is xlat'ed.
+ * @param[in] input_pairs list of value pairs - these will be available in the environment of the
+ *     child.
+ * @param[in] exec_wait set to 1 if you want to read from or write to child.
+ * @param[in] shell_escape values before passing them as arguments.
+ * @param[in] timeout amount of time to wait, in seconds.
+ * @return
+ *     - 0 if exec_wait==0.
+ *     - exit code if exec_wait!=0.
+ *     - -1 on failure.
+ */
+int radius_exec_program_legacy(TALLOC_CTX *ctx, char *out, size_t outlen, fr_pair_list_t *output_pairs,
+                              request_t *request, char const *cmd, fr_pair_list_t *input_pairs,
+                              bool exec_wait, bool shell_escape, fr_time_delta_t timeout)
+{
+       pid_t pid;
+       int stdout_pipe;
+       char *p;
+       pid_t child_pid;
+       int comma = 0;
+       int status, ret = 0;
+       ssize_t len;
+       char answer[4096];
+
+       RDEBUG2("Executing: %s", cmd);
+
+       if (out) *out = '\0';
+
+       pid = radius_start_program_legacy(NULL, &stdout_pipe, NULL, cmd, request, exec_wait, input_pairs, shell_escape);
+       if (pid < 0) {
+               return -1;
+       }
+
+       if (!exec_wait) {
+               return 0;
+       }
+
+       len = radius_readfrom_program_legacy(stdout_pipe, pid, timeout, answer, sizeof(answer));
+       if (len < 0) {
+               /*
+                *      Failure - radius_readfrom_program_legacy will
+                *      have called close(stdout_pipe) for us
+                */
+               RERROR("Failed to read from child output");
+               return -1;
+
+       }
+       answer[len] = '\0';
+
+       /*
+        *      Make sure that the writer can't block while writing to
+        *      a pipe that no one is reading from anymore.
+        */
+       close(stdout_pipe);
+
+       if (len == 0) {
+               goto wait;
+       }
+
+       /*
+        *      Parse the output, if any.
+        */
+       if (output_pairs) {
+               fr_pair_list_t vps;
+
+               fr_pair_list_init(&vps);
+               /*
+                *      HACK: Replace '\n' with ',' so that
+                *      fr_pair_list_afrom_str() can parse the buffer in
+                *      one go (the proper way would be to
+                *      fix fr_pair_list_afrom_str(), but oh well).
+                */
+               for (p = answer; *p; p++) {
+                       if (*p == '\n') {
+                               *p = comma ? ' ' : ',';
+                               p++;
+                               comma = 0;
+                       }
+                       if (*p == ',') {
+                               comma++;
+                       }
+               }
+
+               /*
+                *      Replace any trailing comma by a NUL.
+                */
+               if (answer[len - 1] == ',') {
+                       answer[--len] = '\0';
+               }
+
+               if (fr_pair_list_afrom_str(ctx, request->dict, answer, sizeof(answer), &vps) == T_INVALID) {
+                       RPERROR("Failed parsing output from: %s", cmd);
+                       if (out) strlcpy(out, answer, len);
+                       ret = -1;
+               }
+
+               /*
+                *      We want to mark the new attributes as tainted,
+                *      but not the existing ones.
+                */
+               fr_pair_list_tainted(&vps);
+               fr_pair_list_append(output_pairs, &vps);
+
+       } else if (out) {
+               /*
+                *      We've not been told to extract output pairs,
+                *      just copy the programs output to the out
+                *      buffer.
+                */
+               strlcpy(out, answer, outlen);
+       }
+
+wait:
+       child_pid = waitpid(pid, &status, 0);
+       if (child_pid == 0) {
+               RERROR("Timeout waiting for child");
+
+               return -2;
+       }
+
+       if (child_pid == pid) {
+               if (WIFEXITED(status)) {
+                       status = WEXITSTATUS(status);
+                       if ((status != 0) || (ret < 0)) {
+                               RERROR("Program returned code (%d) and output \"%pV\"", status,
+                                      fr_box_strvalue_len(answer, len));
+                       } else {
+                               RDEBUG2("Program returned code (%d) and output \"%pV\"", status,
+                                       fr_box_strvalue_len(answer, len));
+                       }
+
+                       return ret < 0 ? ret : status;
+               }
+       }
+
+       RERROR("Abnormal child exit: %s", fr_syserror(errno));
+
+       return -1;
+}
diff --git a/src/lib/server/exec_legacy.h b/src/lib/server/exec_legacy.h
new file mode 100644 (file)
index 0000000..5779266
--- /dev/null
@@ -0,0 +1,51 @@
+#pragma once
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file lib/server/exec_legacy.h
+ * @brief Legacy synchronous exec functions
+ *
+ * @copyright 2014 The FreeRADIUS server project
+ */
+RCSIDH(exec_legacy_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <unistd.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+pid_t  radius_start_program_legacy(int *stdin_fd, int *stdout_fd, int *stderr_fd,
+                            char const *cmd, request_t *request, bool exec_wait,
+                            fr_pair_list_t *input_pairs, bool shell_escape);
+
+int    radius_readfrom_program_legacy(int fd, pid_t pid, fr_time_delta_t timeout,
+                               char *answer, int left);
+
+int    radius_exec_program_legacy(TALLOC_CTX *ctx, char *out, size_t outlen, fr_pair_list_t *output_pairs,
+                           request_t *request, char const *cmd, fr_pair_list_t *input_pairs,
+                           bool exec_wait, bool shell_escape, fr_time_delta_t timeout) CC_HINT(nonnull (5, 6));
+
+#ifdef __cplusplus
+}
+#endif
index 928c0a9776c794cf465aa5a7cbc3530731510650..3e85b8cc2d412d3cee13cf34e9be40dcef1c1585 100644 (file)
@@ -14,6 +14,7 @@ SOURCES       := \
        dependency.c \
        dl_module.c \
        exec.c \
+       exec_legacy.c \
        exfile.c \
        log.c \
        main_config.c \
index ece9bfdc6b087688b1c9967c6fc1e0099eb2128d..118d0f8e157257aa4a74047da6ddc978d9c7233f 100644 (file)
@@ -29,6 +29,7 @@
 RCSID("$Id$")
 
 #include <freeradius-devel/server/exec.h>
+#include <freeradius-devel/server/exec_legacy.h>
 #include <freeradius-devel/server/map.h>
 #include <freeradius-devel/server/paircmp.h>
 #include <freeradius-devel/server/cond.h>
@@ -1036,7 +1037,7 @@ static int map_exec_to_vp(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *reque
         *      if dst is an attribute, then we create an attribute of that type and then
         *      call fr_pair_value_from_str on the output of the script.
         */
-       result = radius_exec_program(ctx, answer, sizeof(answer),
+       result = radius_exec_program_legacy(ctx, answer, sizeof(answer),
                                     tmpl_is_list(map->lhs) ? &output_pairs : NULL,
                                     request, map->rhs->name, input_pairs ? input_pairs : NULL,
                                     true, true, fr_time_delta_from_sec(EXEC_TIMEOUT));
index a473dd5937630ace504c1c0fcaf0e40bb234b3d6..8b1f54def8edea5a22d8097cc1ecd1c3c8096cb1 100644 (file)
@@ -30,6 +30,7 @@ RCSID("$Id$")
 
 #include <freeradius-devel/server/tmpl.h>
 #include <freeradius-devel/server/exec.h>
+#include <freeradius-devel/server/exec_legacy.h>
 #include <freeradius-devel/util/proto.h>
 #include <freeradius-devel/util/dlist.h>
 
@@ -310,7 +311,7 @@ ssize_t _tmpl_to_type(void *out,
                        return -1;
                }
 
-               if (radius_exec_program(request, (char *)buff, bufflen, NULL, request, vpt->name, NULL,
+               if (radius_exec_program_legacy(request, (char *)buff, bufflen, NULL, request, vpt->name, NULL,
                                        true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) return -1;
                fr_value_box_strdup_shallow(&value_to_cast, NULL, (char *)buff, true);
                src_type = FR_TYPE_STRING;
@@ -589,7 +590,7 @@ ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out,
                RDEBUG4("EXPAND TMPL EXEC");
 
                fr_value_box_bstr_alloc(tmp_ctx, &buff, &value, NULL, 1024, true);
-               if (radius_exec_program(request, buff, 1024, NULL, request, vpt->name, NULL,
+               if (radius_exec_program_legacy(request, buff, 1024, NULL, request, vpt->name, NULL,
                                        true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) {
                error:
                        talloc_free(tmp_ctx);
index a0ce6d8cdca441357c077cb9b337f03915876d1e..bc47fedb43950792741bbf075a80764f24fb0d82 100644 (file)
@@ -202,7 +202,7 @@ static unlang_action_t trigger_resume(rlm_rcode_t *p_result, UNUSED int *priorit
         *      continuing. This blocks the executing thread.
         */
        if (trigger->synchronous) {
-               if (fr_exec_wait_start(&trigger->pid, NULL, NULL, NULL, request, &trigger->args, NULL) < 0) {
+               if (fr_exec_fork_wait(&trigger->pid, NULL, NULL, NULL, request, &trigger->args, NULL) < 0) {
                        RPERROR("Failed running trigger %s", trigger->name);
                        RETURN_MODULE_FAIL;
                }
@@ -216,7 +216,7 @@ static unlang_action_t trigger_resume(rlm_rcode_t *p_result, UNUSED int *priorit
         *      Execute the program without waiting for the result.
         */
        } else {
-               if (fr_exec_nowait(request, &trigger->args, NULL) < 0) {
+               if (fr_exec_fork_nowait(request, &trigger->args, NULL) < 0) {
                        RPERROR("Failed running trigger %s", trigger->name);
                        RETURN_MODULE_FAIL;
                }
@@ -365,7 +365,7 @@ int trigger_exec(unlang_interpret_t *intp, request_t *request,
        }
 
        /*
-        *      radius_exec_program always needs a request.
+        *      radius_exec_program_legacy always needs a request.
         */
        child = request_alloc_internal(NULL, (&(request_init_args_t){ .parent = request, .detachable = true }));
 
index ba6e916e2bec85292ab7e7445f6c405b29e394ff..7bd9b200174e46bf1e2794f06ac91ff31deef484 100644 (file)
@@ -166,7 +166,7 @@ static unlang_action_t unlang_tmpl_exec_wait_resume(rlm_rcode_t *p_result, reque
 {
        unlang_frame_state_tmpl_t       *state = talloc_get_type_abort(frame->state, unlang_frame_state_tmpl_t);
 
-       if (fr_exec_wait_start_io(state->ctx, &state->exec, request,
+       if (fr_exec_start(state->ctx, &state->exec, request,
                                  &state->box, state->args.exec.env,
                                  false,
                                  (state->out != NULL), state,
@@ -189,7 +189,7 @@ static unlang_action_t unlang_tmpl_exec_nowait_resume(rlm_rcode_t *p_result, req
 {
        unlang_frame_state_tmpl_t       *state = talloc_get_type_abort(frame->state, unlang_frame_state_tmpl_t);
 
-       if (fr_exec_nowait(request, &state->box, state->exec.vps) < 0) {
+       if (fr_exec_fork_nowait(request, &state->box, state->exec.vps) < 0) {
                RPEDEBUG("Failed executing program");
                *p_result = RLM_MODULE_FAIL;
 
index 66578cefa1c4e73c6f9e4138b1cbee34924aacbb..e0ab03e9cda8a72929d54923c63018f363eae1b9 100644 (file)
@@ -133,13 +133,13 @@ static xlat_action_t exec_xlat(TALLOC_CTX *ctx, UNUSED fr_dcursor_t *out, reques
 
        if (!inst->wait) {
                /* Not waiting for the response */
-               fr_exec_nowait(request, in, input_pairs);
+               fr_exec_fork_nowait(request, in, input_pairs);
                return XLAT_ACTION_DONE;
        }
 
        MEM(exec = talloc_zero(request, fr_exec_state_t)); /* Fixme - Should be frame ctx */
 
-       if (fr_exec_wait_start_io(exec, exec, request, in, input_pairs,
+       if (fr_exec_start(exec, exec, request, in, input_pairs,
                                  false,
                                  inst->wait, ctx,
                                  inst->timeout) < 0) {
@@ -297,7 +297,7 @@ static unlang_action_t mod_exec_nowait_resume(rlm_rcode_t *p_result, module_ctx_
                }
        }
 
-       if (fr_exec_nowait(request, box, env_pairs) < 0) {
+       if (fr_exec_fork_nowait(request, box, env_pairs) < 0) {
                RPEDEBUG("Failed executing program");
                RETURN_MODULE_FAIL;
        }
index 068015b8a5f967c600094d217b8cdd590d67612e..93cadcfc8dd941bc06f88634131a59884bf37177 100644 (file)
@@ -29,6 +29,7 @@ RCSID("$Id$")
 #define LOG_PREFIX_ARGS dl_module_instance_name_by_data(inst)
 
 #include <freeradius-devel/server/base.h>
+#include <freeradius-devel/server/exec_legacy.h>
 #include <freeradius-devel/server/module.h>
 #include <freeradius-devel/server/password.h>
 #include <freeradius-devel/util/debug.h>
@@ -820,7 +821,7 @@ static int CC_HINT(nonnull (1, 2, 4, 5)) do_mschap_cpw(rlm_mschap_t const *inst,
                 * Start up ntlm_auth with a pipe on stdin and stdout
                 */
 
-               pid = radius_start_program(&to_child, &from_child, NULL, inst->ntlm_cpw, request, true, NULL, false);
+               pid = radius_start_program_legacy(&to_child, &from_child, NULL, inst->ntlm_cpw, request, true, NULL, false);
                if (pid < 0) {
                        REDEBUG("could not exec ntlm_auth cpw command");
                        return -1;
@@ -909,9 +910,9 @@ static int CC_HINT(nonnull (1, 2, 4, 5)) do_mschap_cpw(rlm_mschap_t const *inst,
                /*
                 *  Read from the child
                 */
-               len = radius_readfrom_program(from_child, pid, fr_time_delta_from_sec(10), buf, sizeof(buf));
+               len = radius_readfrom_program_legacy(from_child, pid, fr_time_delta_from_sec(10), buf, sizeof(buf));
                if (len < 0) {
-                       /* radius_readfrom_program will have closed from_child for us */
+                       /* radius_readfrom_program_legacy will have closed from_child for us */
                        REDEBUG("Failure reading from child");
                        return -1;
                }
@@ -1186,7 +1187,7 @@ static int CC_HINT(nonnull (1, 2, 4, 5, 6)) do_mschap(rlm_mschap_t const *inst,
                /*
                 *      Run the program, and expect that we get 16
                 */
-               result = radius_exec_program(request, buffer, sizeof(buffer), NULL, request, inst->ntlm_auth, NULL,
+               result = radius_exec_program_legacy(request, buffer, sizeof(buffer), NULL, request, inst->ntlm_auth, NULL,
                                             true, true, inst->ntlm_auth_timeout);
                if (result != 0) {
                        char *p;