From 1a1cb54975d245216ae1e163e1115d51aff92b46 Mon Sep 17 00:00:00 2001 From: Robert Manner Date: Thu, 6 Feb 2020 15:15:43 +0100 Subject: [PATCH] plugins/python/regress/check_python_examples: add audit_plugin tests --- .../python/regress/check_python_examples.c | 304 +++++++++++++++++- ...xample_audit_plugin_receives_accept.stdout | 7 + ...example_audit_plugin_receives_error.stdout | 5 + ...xample_audit_plugin_receives_reject.stdout | 5 + ...xample_audit_plugin_version_display.stdout | 6 + ...mple_audit_plugin_workflow_multiple.stderr | 1 + ...mple_audit_plugin_workflow_multiple.stdout | 14 + 7 files changed, 341 insertions(+), 1 deletion(-) create mode 100644 plugins/python/regress/testdata/check_example_audit_plugin_receives_accept.stdout create mode 100644 plugins/python/regress/testdata/check_example_audit_plugin_receives_error.stdout create mode 100644 plugins/python/regress/testdata/check_example_audit_plugin_receives_reject.stdout create mode 100644 plugins/python/regress/testdata/check_example_audit_plugin_version_display.stdout create mode 100644 plugins/python/regress/testdata/check_example_audit_plugin_workflow_multiple.stderr create mode 100644 plugins/python/regress/testdata/check_example_audit_plugin_workflow_multiple.stdout diff --git a/plugins/python/regress/check_python_examples.c b/plugins/python/regress/check_python_examples.c index b6e977cbb..63f344d25 100644 --- a/plugins/python/regress/check_python_examples.c +++ b/plugins/python/regress/check_python_examples.c @@ -27,9 +27,10 @@ static const char *python_plugin_so_path = NULL; static void *python_plugin_handle = NULL; -static struct io_plugin *python_io; +static struct io_plugin *python_io = NULL; static struct policy_plugin *python_policy = NULL; static struct sudoers_group_plugin *group_plugin = NULL; +static struct audit_plugin *python_audit = NULL; static struct passwd example_pwd; @@ -76,6 +77,19 @@ create_debugging_plugin_options(void) ); } +void +create_audit_plugin_options(const char *extra_argument) +{ + str_array_free(&data.plugin_options); + data.plugin_options = create_str_array( + 4, + "ModulePath=" SRC_DIR "/example_audit_plugin.py", + "ClassName=SudoAuditPlugin", + extra_argument, + NULL + ); +} + void create_conversation_plugin_options(void) { @@ -995,6 +1009,281 @@ check_python_plugins_do_not_affect_each_other(void) return true; } +int +check_example_audit_plugin_receives_accept(void) +{ + create_audit_plugin_options(""); + const char *errstr = NULL; + + str_array_free(&data.plugin_argv); + data.plugin_argv = create_str_array(6, "sudo", "-u", "user", "id", "--help", NULL); + + str_array_free(&data.user_env); + data.user_env = create_str_array(3, "KEY1=VALUE1", "KEY2=VALUE2", NULL); + + str_array_free(&data.user_info); + data.user_info = create_str_array(3, "user=testuser1", "uid=123", NULL); + + VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 3, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + str_array_free(&data.command_info); + data.command_info = create_str_array(2, "command=/sbin/id", NULL); + + str_array_free(&data.plugin_argv); + data.plugin_argv = create_str_array(3, "id", "--help", NULL); + + VERIFY_INT(python_audit->accept("accepter plugin name", SUDO_POLICY_PLUGIN, + data.command_info, data.plugin_argv, + data.user_env, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + python_audit->close(SUDO_PLUGIN_WAIT_STATUS, W_EXITCODE(2, 0)); // process exited with 2 + + VERIFY_STDOUT(expected_path("check_example_audit_plugin_receives_accept.stdout")); + VERIFY_STR(data.stderr_str, ""); + + return true; +} + +int +check_example_audit_plugin_receives_reject(void) +{ + create_audit_plugin_options(""); + const char *errstr = NULL; + + str_array_free(&data.plugin_argv); + data.plugin_argv = create_str_array(3, "sudo", "passwd", NULL); + + str_array_free(&data.user_info); + data.user_info = create_str_array(3, "user=root", "uid=0", NULL); + + VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 1, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + VERIFY_INT(python_audit->reject("rejecter plugin name", SUDO_IO_PLUGIN, + "Rejected just because!", data.command_info, + &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + python_audit->close(SUDO_PLUGIN_NO_STATUS, 0); // program was not run + + VERIFY_STDOUT(expected_path("check_example_audit_plugin_receives_reject.stdout")); + VERIFY_STR(data.stderr_str, ""); + + return true; +} + +int +check_example_audit_plugin_receives_error(void) +{ + create_audit_plugin_options(""); + const char *errstr = NULL; + + str_array_free(&data.plugin_argv); + data.plugin_argv = create_str_array(5, "sudo", "-u", "user", "id", NULL); + + VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 3, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + str_array_free(&data.command_info); + data.command_info = create_str_array(2, "command=/sbin/id", NULL); + + VERIFY_INT(python_audit->error("errorer plugin name", SUDO_AUDIT_PLUGIN, + "Some error has happened", data.command_info, + &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + python_audit->close(SUDO_PLUGIN_SUDO_ERROR, 222); + + VERIFY_STDOUT(expected_path("check_example_audit_plugin_receives_error.stdout")); + VERIFY_STR(data.stderr_str, ""); + + return true; +} + +typedef struct audit_plugin * (audit_clone_func)(void); + +int +check_example_audit_plugin_workflow_multiple(void) +{ + // verify multiple python audit plugins are available + audit_clone_func *python_audit_clone = (audit_clone_func *)sudo_dso_findsym( + python_plugin_handle, "python_audit_clone"); + VERIFY_PTR_NE(python_audit_clone, NULL); + + struct audit_plugin *python_audit2 = NULL; + + for (int i = 0; i < 7; ++i) { + python_audit2 = (*python_audit_clone)(); + VERIFY_PTR_NE(python_audit2, NULL); + VERIFY_PTR_NE(python_audit2, python_audit); + } + + const char *errstr = NULL; + + str_array_free(&data.plugin_argv); + data.plugin_argv = create_str_array(6, "sudo", "-u", "user", "id", "--help", NULL); + + str_array_free(&data.user_env); + data.user_env = create_str_array(3, "KEY1=VALUE1", "KEY2=VALUE2", NULL); + + str_array_free(&data.user_info); + data.user_info = create_str_array(3, "user=default", "uid=1000", NULL); + + create_audit_plugin_options("Id=1"); + VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 3, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + // For verifying the error message of no more plugin. It should be displayed only once. + VERIFY_PTR((*python_audit_clone)(), NULL); + VERIFY_PTR((*python_audit_clone)(), NULL); + + create_audit_plugin_options("Id=2"); + VERIFY_INT(python_audit2->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 3, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + str_array_free(&data.command_info); + data.command_info = create_str_array(2, "command=/sbin/id", NULL); + + str_array_free(&data.plugin_argv); + data.plugin_argv = create_str_array(3, "id", "--help", NULL); + + VERIFY_INT(python_audit->accept("accepter plugin name", SUDO_POLICY_PLUGIN, + data.command_info, data.plugin_argv, + data.user_env, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + VERIFY_INT(python_audit2->accept("accepter plugin name", SUDO_POLICY_PLUGIN, + data.command_info, data.plugin_argv, + data.user_env, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + python_audit->close(SUDO_PLUGIN_WAIT_STATUS, W_EXITCODE(0, 11)); // process got signal 11 + python_audit2->close(SUDO_PLUGIN_WAIT_STATUS, W_EXITCODE(0, 11)); + + VERIFY_STDOUT(expected_path("check_example_audit_plugin_workflow_multiple.stdout")); + VERIFY_STDERR(expected_path("check_example_audit_plugin_workflow_multiple.stderr")); + + return true; +} + +int +check_example_audit_plugin_version_display(void) +{ + create_audit_plugin_options(""); + const char *errstr = NULL; + + str_array_free(&data.user_info); + data.user_info = create_str_array(3, "user=root", "uid=0", NULL); + + str_array_free(&data.plugin_argv); + data.plugin_argv = create_str_array(3, "sudo", "-V", NULL); + + VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 2, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), SUDO_RC_OK); + VERIFY_PTR(errstr, NULL); + + VERIFY_INT(python_audit->show_version(false), SUDO_RC_OK); + VERIFY_INT(python_audit->show_version(true), SUDO_RC_OK); + + python_audit->close(SUDO_PLUGIN_SUDO_ERROR, 222); + + VERIFY_STDOUT(expected_path("check_example_audit_plugin_version_display.stdout")); + VERIFY_STR(data.stderr_str, ""); + + return true; +} + +int +check_audit_plugin_callbacks_are_optional(void) +{ + const char *errstr = NULL; + + create_debugging_plugin_options(); + + VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 2, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), + SUDO_RC_OK); + + VERIFY_PTR(python_audit->accept, NULL); + VERIFY_PTR(python_audit->reject, NULL); + VERIFY_PTR(python_audit->error, NULL); + VERIFY_PTR(python_audit->show_version, NULL); + + python_audit->close(SUDO_PLUGIN_NO_STATUS, 0); + return true; +} + +int +check_audit_plugin_reports_error(void) +{ + const char *errstr = NULL; + str_array_free(&data.plugin_options); + data.plugin_options = create_str_array( + 3, + "ModulePath=" SRC_DIR "/regress/plugin_errorstr.py", + "ClassName=ConstructErrorPlugin", + NULL + ); + + VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 0, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), SUDO_RC_ERROR); + + VERIFY_STR(errstr, "Something wrong in plugin constructor"); + errstr = NULL; + + python_audit->close(SUDO_PLUGIN_NO_STATUS, 0); + + str_array_free(&data.plugin_options); + data.plugin_options = create_str_array( + 3, + "ModulePath=" SRC_DIR "/regress/plugin_errorstr.py", + "ClassName=ErrorMsgPlugin", + NULL + ); + + VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf, + data.settings, data.user_info, 0, data.plugin_argv, + data.user_env, data.plugin_options, &errstr), SUDO_RC_ERROR); + VERIFY_STR(errstr, "Something wrong in open"); + + VERIFY_INT(python_audit->accept("plugin name", SUDO_POLICY_PLUGIN, + data.command_info, data.plugin_argv, + data.user_env, &errstr), SUDO_RC_ERROR); + VERIFY_STR(errstr, "Something wrong in accept"); + + VERIFY_INT(python_audit->reject("plugin name", SUDO_POLICY_PLUGIN, + "audit message", data.command_info, + &errstr), SUDO_RC_ERROR); + VERIFY_STR(errstr, "Something wrong in reject"); + + VERIFY_INT(python_audit->error("plugin name", SUDO_POLICY_PLUGIN, + "audit message", data.command_info, + &errstr), SUDO_RC_ERROR); + VERIFY_STR(errstr, "Something wrong in error"); + + python_audit->close(SUDO_PLUGIN_NO_STATUS, 0); + + VERIFY_STR(data.stderr_str, ""); + VERIFY_STR(data.stdout_str, ""); + return true; +} + + static int _load_symbols(void) { @@ -1009,6 +1298,10 @@ _load_symbols(void) python_policy = sudo_dso_findsym(python_plugin_handle, "python_policy"); VERIFY_PTR_NE(python_policy, NULL); + + python_audit = sudo_dso_findsym(python_plugin_handle, "python_audit"); + VERIFY_PTR_NE(python_audit, NULL); + return true; } @@ -1018,6 +1311,7 @@ _unload_symbols(void) python_io = NULL; group_plugin = NULL; python_policy = NULL; + python_audit = NULL; VERIFY_INT(sudo_dso_unload(python_plugin_handle), 0); return true; } @@ -1064,6 +1358,14 @@ main(int argc, char *argv[]) RUN_TEST(check_policy_plugin_callbacks_are_optional()); RUN_TEST(check_policy_plugin_reports_error()); + RUN_TEST(check_example_audit_plugin_receives_accept()); + RUN_TEST(check_example_audit_plugin_receives_reject()); + RUN_TEST(check_example_audit_plugin_receives_error()); + RUN_TEST(check_example_audit_plugin_workflow_multiple()); + RUN_TEST(check_example_audit_plugin_version_display()); + RUN_TEST(check_audit_plugin_callbacks_are_optional()); + RUN_TEST(check_audit_plugin_reports_error()); + RUN_TEST(check_python_plugins_do_not_affect_each_other()); RUN_TEST(check_example_debugging("plugin@err")); diff --git a/plugins/python/regress/testdata/check_example_audit_plugin_receives_accept.stdout b/plugins/python/regress/testdata/check_example_audit_plugin_receives_accept.stdout new file mode 100644 index 000000000..2c8397228 --- /dev/null +++ b/plugins/python/regress/testdata/check_example_audit_plugin_receives_accept.stdout @@ -0,0 +1,7 @@ +(AUDIT) -- Started by user testuser1 (123) -- +(AUDIT) Requested command: id --help +(AUDIT) Accepted command: /sbin/id --help +(AUDIT) By the plugin: accepter plugin name (type=POLICY) +(AUDIT) Environment: KEY1=VALUE1 KEY2=VALUE2 +(AUDIT) Command returned with exit code 2 +(AUDIT) -- Finished -- diff --git a/plugins/python/regress/testdata/check_example_audit_plugin_receives_error.stdout b/plugins/python/regress/testdata/check_example_audit_plugin_receives_error.stdout new file mode 100644 index 000000000..cb7068dff --- /dev/null +++ b/plugins/python/regress/testdata/check_example_audit_plugin_receives_error.stdout @@ -0,0 +1,5 @@ +(AUDIT) -- Started by user ??? (???) -- +(AUDIT) Requested command: id +(AUDIT) Plugin errorer plugin name (type=AUDIT) got an error: Some error has happened +(AUDIT) Sudo has run into an error: 222 +(AUDIT) -- Finished -- diff --git a/plugins/python/regress/testdata/check_example_audit_plugin_receives_reject.stdout b/plugins/python/regress/testdata/check_example_audit_plugin_receives_reject.stdout new file mode 100644 index 000000000..c6e8a5abf --- /dev/null +++ b/plugins/python/regress/testdata/check_example_audit_plugin_receives_reject.stdout @@ -0,0 +1,5 @@ +(AUDIT) -- Started by user root (0) -- +(AUDIT) Requested command: passwd +(AUDIT) Rejected by plugin rejecter plugin name (type=IO): Rejected just because! +(AUDIT) The command was not executed +(AUDIT) -- Finished -- diff --git a/plugins/python/regress/testdata/check_example_audit_plugin_version_display.stdout b/plugins/python/regress/testdata/check_example_audit_plugin_version_display.stdout new file mode 100644 index 000000000..3f7015ba1 --- /dev/null +++ b/plugins/python/regress/testdata/check_example_audit_plugin_version_display.stdout @@ -0,0 +1,6 @@ +(AUDIT) -- Started by user root (0) -- +Python Example Audit Plugin +Python audit plugin API version 1.0 +Python Example Audit Plugin (version=1.0) +(AUDIT) Sudo has run into an error: 222 +(AUDIT) -- Finished -- diff --git a/plugins/python/regress/testdata/check_example_audit_plugin_workflow_multiple.stderr b/plugins/python/regress/testdata/check_example_audit_plugin_workflow_multiple.stderr new file mode 100644 index 000000000..1d7d4a1bc --- /dev/null +++ b/plugins/python/regress/testdata/check_example_audit_plugin_workflow_multiple.stderr @@ -0,0 +1 @@ +sudo: loading more than 8 sudo python audit plugins is not supported diff --git a/plugins/python/regress/testdata/check_example_audit_plugin_workflow_multiple.stdout b/plugins/python/regress/testdata/check_example_audit_plugin_workflow_multiple.stdout new file mode 100644 index 000000000..aa5ee5893 --- /dev/null +++ b/plugins/python/regress/testdata/check_example_audit_plugin_workflow_multiple.stdout @@ -0,0 +1,14 @@ +(AUDIT1) -- Started by user default (1000) -- +(AUDIT1) Requested command: id --help +(AUDIT2) -- Started by user default (1000) -- +(AUDIT2) Requested command: id --help +(AUDIT1) Accepted command: /sbin/id --help +(AUDIT1) By the plugin: accepter plugin name (type=POLICY) +(AUDIT1) Environment: KEY1=VALUE1 KEY2=VALUE2 +(AUDIT2) Accepted command: /sbin/id --help +(AUDIT2) By the plugin: accepter plugin name (type=POLICY) +(AUDIT2) Environment: KEY1=VALUE1 KEY2=VALUE2 +(AUDIT1) Command exited due to signal 11 +(AUDIT1) -- Finished -- +(AUDIT2) Command exited due to signal 11 +(AUDIT2) -- Finished --