From 5a2e9a2587372aeb4b74fa1aadf53283ed7cae10 Mon Sep 17 00:00:00 2001 From: james Date: Sat, 26 Jul 2008 07:27:03 +0000 Subject: Completely revamped the system for calling external programs and scripts: * All external programs and scripts are now called by execve() on unix and CreateProcess on Windows. * The system() function is no longer used. * Argument lists for external programs and scripts are now built by the new argv_printf function which natively outputs to string arrays (i.e. char *argv[] lists), never truncates its output, and eliminates the security issues inherent in formatting and parsing command lines, and dealing with argument quoting. * The --script-security directive has been added to offer policy controls on OpenVPN's execution of external programs and scripts. Also added a new plugin example (openvpn/plugin/examples/log.c) that logs information to stdout for every plugin method called by OpenVPN. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3122 e7ae566f-a301-0410-adde-c780ea21d3b5 --- multi.c | 65 ++++++++++++++++++++++++++++++----------------------------------- 1 file changed, 30 insertions(+), 35 deletions(-) (limited to 'multi.c') diff --git a/multi.c b/multi.c index c5bbcfd..5f70b6f 100644 --- a/multi.c +++ b/multi.c @@ -85,36 +85,33 @@ learn_address_script (const struct multi_context *m, if (plugin_defined (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS)) { - struct buffer cmd = alloc_buf_gc (256, &gc); - - buf_printf (&cmd, "\"%s\" \"%s\"", - op, - mroute_addr_print (addr, &gc)); + struct argv argv = argv_new (); + argv_printf (&argv, "%s %s", + op, + mroute_addr_print (addr, &gc)); if (mi) - buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false)); - - if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, BSTR (&cmd), NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); + if (plugin_call (plugins, OPENVPN_PLUGIN_LEARN_ADDRESS, &argv, NULL, es) != OPENVPN_PLUGIN_FUNC_SUCCESS) { msg (M_WARN, "WARNING: learn-address plugin call failed"); ret = false; } + argv_reset (&argv); } if (m->top.options.learn_address_script) { - struct buffer cmd = alloc_buf_gc (256, &gc); - + struct argv argv = argv_new (); setenv_str (es, "script_type", "learn-address"); - - buf_printf (&cmd, "%s \"%s\" \"%s\"", - m->top.options.learn_address_script, - op, - mroute_addr_print (addr, &gc)); + argv_printf (&argv, "%s %s %s", + m->top.options.learn_address_script, + op, + mroute_addr_print (addr, &gc)); if (mi) - buf_printf (&cmd, " \"%s\"", tls_common_name (mi->context.c2.tls_multi, false)); - - if (!system_check (BSTR (&cmd), es, S_SCRIPT, "WARNING: learn-address command failed")) + argv_printf_cat (&argv, "%s", tls_common_name (mi->context.c2.tls_multi, false)); + if (!openvpn_execve_check (&argv, es, S_SCRIPT, "WARNING: learn-address command failed")) ret = false; + argv_reset (&argv); } gc_free (&gc); @@ -474,16 +471,11 @@ multi_client_disconnect_script (struct multi_context *m, if (mi->context.options.client_disconnect_script) { - struct gc_arena gc = gc_new (); - struct buffer cmd = alloc_buf_gc (256, &gc); - + struct argv argv = argv_new (); setenv_str (mi->context.c2.es, "script_type", "client-disconnect"); - - buf_printf (&cmd, "%s", mi->context.options.client_disconnect_script); - - system_check (BSTR (&cmd), mi->context.c2.es, S_SCRIPT, "client-disconnect command failed"); - - gc_free (&gc); + argv_printf (&argv, "%s", mi->context.options.client_disconnect_script); + openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-disconnect command failed"); + argv_reset (&argv); } #ifdef MANAGEMENT_DEF_AUTH if (management) @@ -1523,11 +1515,11 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi /* deprecated callback, use a file for passing back return info */ if (plugin_defined (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT)) { + struct argv argv = argv_new (); const char *dc_file = create_temp_filename (mi->context.options.tmp_dir, "cc", &gc); - + argv_printf (&argv, "%s", dc_file); delete_file (dc_file); - - if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, dc_file, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) + if (plugin_call (mi->context.plugins, OPENVPN_PLUGIN_CLIENT_CONNECT, &argv, NULL, mi->context.c2.es) != OPENVPN_PLUGIN_FUNC_SUCCESS) { msg (M_WARN, "WARNING: client-connect plugin call failed"); cc_succeeded = false; @@ -1537,6 +1529,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found); ++cc_succeeded_count; } + argv_reset (&argv); } /* V2 callback, use a plugin_return struct for passing back return info */ @@ -1566,7 +1559,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi */ if (mi->context.options.client_connect_script && cc_succeeded) { - struct buffer cmd = alloc_buf_gc (256, &gc); + struct argv argv = argv_new (); const char *dc_file = NULL; setenv_str (mi->context.c2.es, "script_type", "client-connect"); @@ -1575,17 +1568,19 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi delete_file (dc_file); - buf_printf (&cmd, "%s %s", - mi->context.options.client_connect_script, - dc_file); + argv_printf (&argv, "%s %s", + mi->context.options.client_connect_script, + dc_file); - if (system_check (BSTR (&cmd), mi->context.c2.es, S_SCRIPT, "client-connect command failed")) + if (openvpn_execve_check (&argv, mi->context.c2.es, S_SCRIPT, "client-connect command failed")) { multi_client_connect_post (m, mi, dc_file, option_permissions_mask, &option_types_found); ++cc_succeeded_count; } else cc_succeeded = false; + + argv_reset (&argv); } /* -- cgit