static void plugin_common_open (struct plugin_common *pc, const struct plugin_option_list *list, struct plugin_return *pr, const struct env_set *es, const int init_point) { struct gc_arena gc = gc_new (); int i; const char **envp; envp = make_env_array (es, false, &gc); if (pr) plugin_return_init (pr); for (i = 0; i < pc->n; ++i) { plugin_open_item (&pc->plugins[i], &list->plugins[i], pr ? &pr->list[i] : NULL, envp, init_point); } if (pr) pr->n = i; gc_free (&gc); }
/* * Run execve() inside a fork(). Designed to replicate the semantics of system() but * in a safer way that doesn't require the invocation of a shell or the risks * assocated with formatting and parsing a command line. */ int openvpn_execve(const struct argv *a, const struct env_set *es, const unsigned int flags) { struct gc_arena gc = gc_new(); int ret = -1; static bool warn_shown = false; if (a && a->argv[0]) { #if defined(ENABLE_FEATURE_EXECVE) if (openvpn_execve_allowed(flags)) { const char *cmd = a->argv[0]; char *const *argv = a->argv; char *const *envp = (char *const *)make_env_array(es, true, &gc); pid_t pid; pid = fork(); if (pid == (pid_t)0) /* child side */ { execve(cmd, argv, envp); exit(127); } else if (pid < (pid_t)0) /* fork failed */ { msg(M_ERR, "openvpn_execve: unable to fork"); } else /* parent side */ { if (waitpid(pid, &ret, 0) != pid) { ret = -1; } } } else if (!warn_shown && (script_security() < SSEC_SCRIPTS)) { msg(M_WARN, SCRIPT_SECURITY_WARNING); warn_shown = true; } #else /* if defined(ENABLE_FEATURE_EXECVE) */ msg(M_WARN, "openvpn_execve: execve function not available"); #endif /* if defined(ENABLE_FEATURE_EXECVE) */ } else { msg(M_FATAL, "openvpn_execve: called with empty argv"); } gc_free(&gc); return ret; }
int plugin_call_ssl (const struct plugin_list *pl, const int type, const struct argv *av, struct plugin_return *pr, struct env_set *es #ifdef USE_SSL , int certdepth, x509_cert_t *current_cert #endif ) { if (pr) plugin_return_init (pr); if (plugin_defined (pl, type)) { struct gc_arena gc = gc_new (); int i; const char **envp; const int n = plugin_n (pl); bool success = false; bool error = false; bool deferred = false; setenv_del (es, "script_type"); envp = make_env_array (es, false, &gc); for (i = 0; i < n; ++i) { const int status = plugin_call_item (&pl->common->plugins[i], pl->per_client.per_client_context[i], type, av, pr ? &pr->list[i] : NULL, envp #ifdef USE_SSL ,certdepth, current_cert #endif ); switch (status) { case OPENVPN_PLUGIN_FUNC_SUCCESS: success = true; break; case OPENVPN_PLUGIN_FUNC_DEFERRED: deferred = true; break; default: error = true; break; } } if (pr) pr->n = i; gc_free (&gc); if (type == OPENVPN_PLUGIN_ENABLE_PF && success) return OPENVPN_PLUGIN_FUNC_SUCCESS; else if (error) return OPENVPN_PLUGIN_FUNC_ERROR; else if (deferred) return OPENVPN_PLUGIN_FUNC_DEFERRED; } return OPENVPN_PLUGIN_FUNC_SUCCESS; }
/* * Run execve() inside a fork(), duping stdout. Designed to replicate the semantics of popen() but * in a safer way that doesn't require the invocation of a shell or the risks * assocated with formatting and parsing a command line. */ int openvpn_popen (const struct argv *a, const struct env_set *es) { struct gc_arena gc = gc_new (); int ret = -1; static bool warn_shown = false; if (a && a->argv[0]) { #if defined(ENABLE_FEATURE_EXECVE) if (script_security >= SSEC_BUILT_IN) { const char *cmd = a->argv[0]; char *const *argv = a->argv; char *const *envp = (char *const *)make_env_array (es, true, &gc); pid_t pid; int pipe_stdout[2]; if (pipe (pipe_stdout) == 0) { pid = fork (); if (pid == (pid_t)0) /* child side */ { close (pipe_stdout[0]); /* Close read end */ dup2 (pipe_stdout[1],1); execve (cmd, argv, envp); exit (127); } else if (pid > (pid_t)0) /* parent side */ { int status = 0; close (pipe_stdout[1]); /* Close write end */ waitpid(pid, &status, 0); ret = pipe_stdout[0]; } else /* fork failed */ { close (pipe_stdout[0]); close (pipe_stdout[1]); msg (M_ERR, "openvpn_popen: unable to fork %s", cmd); } } else { msg (M_WARN, "openvpn_popen: unable to create stdout pipe for %s", cmd); ret = -1; } } else if (!warn_shown && (script_security < SSEC_SCRIPTS)) { msg (M_WARN, SCRIPT_SECURITY_WARNING); warn_shown = true; } #else msg (M_WARN, "openvpn_popen: execve function not available"); #endif } else { msg (M_FATAL, "openvpn_popen: called with empty argv"); } gc_free (&gc); return ret; }