From 2eeda38f95b41dcf94d76851fd07295c50b7216a Mon Sep 17 00:00:00 2001 From: Robert Manner Date: Wed, 22 Jan 2020 16:14:12 +0100 Subject: [PATCH] plugins/python/regress: add a testcase for multiple io plugin loading to verify 2 python plugins can work next to each other. --- .../python/regress/check_python_examples.c | 85 ++++++++++++++++++- ...mple_io_plugin_command_log_multiple.stderr | 0 ...mple_io_plugin_command_log_multiple.stdout | 2 + ...ple_io_plugin_command_log_multiple1.stored | 16 ++++ ...ple_io_plugin_command_log_multiple2.stored | 16 ++++ plugins/python/regress/testhelpers.c | 8 +- plugins/python/regress/testhelpers.h | 5 +- 7 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple.stderr create mode 100644 plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple.stdout create mode 100644 plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple1.stored create mode 100644 plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple2.stored diff --git a/plugins/python/regress/check_python_examples.c b/plugins/python/regress/check_python_examples.c index d93a29083..597d91245 100644 --- a/plugins/python/regress/check_python_examples.c +++ b/plugins/python/regress/check_python_examples.c @@ -25,7 +25,8 @@ #include "sudo_dso.h" -static struct io_plugin *python_io = NULL; +static void *python_plugin_handle = NULL; +static struct io_plugin *python_io; static struct policy_plugin *python_policy = NULL; static struct sudoers_group_plugin *group_plugin = NULL; @@ -143,6 +144,9 @@ cleanup(int success) } VERIFY_TRUE(rmdir_recursive(data.tmp_dir)); + if (data.tmp_dir2) { + VERIFY_TRUE(rmdir_recursive(data.tmp_dir2)); + } free(data.settings); free(data.user_info); @@ -214,6 +218,82 @@ check_example_io_plugin_command_log(void) return true; } +typedef struct io_plugin * (io_clone_func)(void); + +int +check_example_io_plugin_command_log_multiple(void) +{ + // verify multiple python io plugin symbols are available + io_clone_func *python_io_clone = (io_clone_func *)sudo_dso_findsym(python_plugin_handle, "python_io_clone"); + VERIFY_PTR_NE(python_io_clone, NULL); + + struct io_plugin *python_io2 = NULL; + + for (int i = 0; i < 7; ++i) { + python_io2 = (*python_io_clone)(); + VERIFY_PTR_NE(python_io2, NULL); + VERIFY_PTR_NE(python_io2, python_io); + } + VERIFY_PTR((*python_io_clone)(), NULL); // no more available + + // open the first plugin and let it log to tmp_dir + create_io_plugin_options(data.tmp_dir); + + free(data.plugin_argv); + data.plugin_argc = 2; + data.plugin_argv = create_str_array(3, "id", "--help", NULL); + + free(data.command_info); + data.command_info = create_str_array(3, "command=/bin/id", "runas_uid=0", NULL); + + VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings, + data.user_info, data.command_info, data.plugin_argc, data.plugin_argv, + data.user_env, data.plugin_options), SUDO_RC_OK); + + // open the second plugin with another log directory + VERIFY_TRUE(asprintf(&data.tmp_dir2, TEMP_PATH_TEMPLATE) >= 0); + VERIFY_NOT_NULL(mkdtemp(data.tmp_dir2)); + create_io_plugin_options(data.tmp_dir2); + + free(data.plugin_argv); + data.plugin_argc = 1; + data.plugin_argv = create_str_array(2, "whoami", NULL); + + free(data.command_info); + data.command_info = create_str_array(3, "command=/bin/whoami", "runas_uid=1", NULL); + + VERIFY_INT(python_io2->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings, + data.user_info, data.command_info, data.plugin_argc, data.plugin_argv, + data.user_env, data.plugin_options), SUDO_RC_OK); + + VERIFY_INT(python_io->log_stdin("stdin for plugin 1", strlen("stdin for plugin 1")), SUDO_RC_OK); + VERIFY_INT(python_io2->log_stdin("stdin for plugin 2", strlen("stdin for plugin 2")), SUDO_RC_OK); + VERIFY_INT(python_io->log_stdout("stdout for plugin 1", strlen("stdout for plugin 1")), SUDO_RC_OK); + VERIFY_INT(python_io2->log_stdout("stdout for plugin 2", strlen("stdout for plugin 2")), SUDO_RC_OK); + VERIFY_INT(python_io->log_stderr("stderr for plugin 1", strlen("stderr for plugin 1")), SUDO_RC_OK); + VERIFY_INT(python_io2->log_stderr("stderr for plugin 2", strlen("stderr for plugin 2")), SUDO_RC_OK); + VERIFY_INT(python_io->log_suspend(SIGTSTP), SUDO_RC_OK); + VERIFY_INT(python_io2->log_suspend(SIGSTOP), SUDO_RC_OK); + VERIFY_INT(python_io->log_suspend(SIGCONT), SUDO_RC_OK); + VERIFY_INT(python_io2->log_suspend(SIGCONT), SUDO_RC_OK); + VERIFY_INT(python_io->change_winsize(20, 10), SUDO_RC_OK); + VERIFY_INT(python_io2->change_winsize(30, 40), SUDO_RC_OK); + VERIFY_INT(python_io->log_ttyin("tty input for plugin 1", strlen("tty input for plugin 1")), SUDO_RC_OK); + VERIFY_INT(python_io2->log_ttyin("tty input for plugin 2", strlen("tty input for plugin 2")), SUDO_RC_OK); + VERIFY_INT(python_io->log_ttyout("tty output for plugin 1", strlen("tty output for plugin 1")), SUDO_RC_OK); + VERIFY_INT(python_io2->log_ttyout("tty output for plugin 2", strlen("tty output for plugin 2")), SUDO_RC_OK); + + python_io->close(1, 0); // successful execution, command returned 1 + python_io2->close(2, 0); // command returned 2 + + VERIFY_STDOUT(expected_path("check_example_io_plugin_command_log_multiple.stdout")); + VERIFY_STDERR(expected_path("check_example_io_plugin_command_log_multiple.stderr")); + VERIFY_FILE("sudo.log", expected_path("check_example_io_plugin_command_log_multiple1.stored")); + VERIFY_TRUE(verify_file(data.tmp_dir2, "sudo.log", expected_path("check_example_io_plugin_command_log_multiple2.stored"))); + + return true; +} + int check_example_io_plugin_failed_to_start_command(void) { @@ -710,7 +790,7 @@ int check_python_plugin_can_be_loaded(const char *python_plugin_path) { printf("Loading python plugin from '%s'\n", python_plugin_path); - void *python_plugin_handle = sudo_dso_load(python_plugin_path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL); + python_plugin_handle = sudo_dso_load(python_plugin_path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL); VERIFY_PTR_NE(python_plugin_handle, NULL); python_io = sudo_dso_findsym(python_plugin_handle, "python_io"); @@ -737,6 +817,7 @@ main(int argc, char *argv[]) RUN_TEST(check_example_io_plugin_version_display(true)); RUN_TEST(check_example_io_plugin_version_display(false)); RUN_TEST(check_example_io_plugin_command_log()); + RUN_TEST(check_example_io_plugin_command_log_multiple()); RUN_TEST(check_example_io_plugin_failed_to_start_command()); RUN_TEST(check_example_io_plugin_fails_with_python_backtrace()); RUN_TEST(check_io_plugin_callbacks_are_optional()); diff --git a/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple.stderr b/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple.stderr new file mode 100644 index 000000000..e69de29bb diff --git a/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple.stdout b/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple.stdout new file mode 100644 index 000000000..e9dbd676a --- /dev/null +++ b/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple.stdout @@ -0,0 +1,2 @@ +Example sudo python plugin will log to /tmp/sudo_check_python_exampleXXXXXX/sudo.log +Example sudo python plugin will log to /tmp/sudo_check_python_exampleXXXXXX2/sudo.log diff --git a/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple1.stored b/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple1.stored new file mode 100644 index 000000000..bc60c38bd --- /dev/null +++ b/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple1.stored @@ -0,0 +1,16 @@ + -- Plugin STARTED -- +EXEC id --help +EXEC info [ + "command=/bin/id", + "runas_uid=0" +] +STD IN stdin for plugin 1 +STD OUT stdout for plugin 1 +STD ERR stderr for plugin 1 +SUSPEND SIGTSTP +SUSPEND SIGCONT +WINSIZE 20x10 +TTY IN tty input for plugin 1 +TTY OUT tty output for plugin 1 +CLOSE Command returned 1 + -- Plugin DESTROYED -- diff --git a/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple2.stored b/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple2.stored new file mode 100644 index 000000000..ed3fdc845 --- /dev/null +++ b/plugins/python/regress/testdata/check_example_io_plugin_command_log_multiple2.stored @@ -0,0 +1,16 @@ + -- Plugin STARTED -- +EXEC whoami +EXEC info [ + "command=/bin/whoami", + "runas_uid=1" +] +STD IN stdin for plugin 2 +STD OUT stdout for plugin 2 +STD ERR stderr for plugin 2 +SUSPEND SIGSTOP +SUSPEND SIGCONT +WINSIZE 30x40 +TTY IN tty input for plugin 2 +TTY OUT tty output for plugin 2 +CLOSE Command returned 2 + -- Plugin DESTROYED -- diff --git a/plugins/python/regress/testhelpers.c b/plugins/python/regress/testhelpers.c index 373b3d988..e3686a6d2 100644 --- a/plugins/python/regress/testhelpers.c +++ b/plugins/python/regress/testhelpers.c @@ -33,6 +33,10 @@ clean_output(char *output) { // we replace some output which otherwise would be test run dependant str_replace_in_place(output, MAX_OUTPUT, data.tmp_dir, TEMP_PATH_TEMPLATE); + + if (data.tmp_dir2) + str_replace_in_place(output, MAX_OUTPUT, data.tmp_dir2, TEMP_PATH_TEMPLATE "2"); + str_replace_in_place(output, MAX_OUTPUT, SRC_DIR, "SRC_DIR"); } @@ -98,10 +102,10 @@ verify_content(char *actual_content, const char *reference_path) } int -verify_file(const char *actual_file_name, const char *reference_path) +verify_file(const char *actual_dir, const char *actual_file_name, const char *reference_path) { char actual_path[PATH_MAX]; - snprintf(actual_path, sizeof(actual_path), "%s/%s", data.tmp_dir, actual_file_name); + snprintf(actual_path, sizeof(actual_path), "%s/%s", actual_dir, actual_file_name); char actual_str[MAX_OUTPUT]; if (!freadall(actual_path, actual_str, sizeof(actual_str))) { diff --git a/plugins/python/regress/testhelpers.h b/plugins/python/regress/testhelpers.h index 649b3687b..691928f3f 100644 --- a/plugins/python/regress/testhelpers.h +++ b/plugins/python/regress/testhelpers.h @@ -38,6 +38,7 @@ extern const char *sudo_conf_normal_mode; extern struct TestData { char *tmp_dir; + char *tmp_dir2; char stdout_str[MAX_OUTPUT]; char stderr_str[MAX_OUTPUT]; @@ -141,10 +142,10 @@ int verify_content(char *actual_content, const char *reference_path); #define VERIFY_CONV(reference_name) \ VERIFY_CONTENT(data.conv_str, reference_name) -int verify_file(const char *actual_file_name, const char *reference_path); +int verify_file(const char *actual_dir, const char *actual_file_name, const char *reference_path); #define VERIFY_FILE(actual_file_name, reference_path) \ - VERIFY_TRUE(verify_file(actual_file_name, reference_path)) + VERIFY_TRUE(verify_file(data.tmp_dir, actual_file_name, reference_path)) int fake_conversation(int num_msgs, const struct sudo_conv_message msgs[], struct sudo_conv_reply replies[], struct sudo_conv_callback *callback);