Path: blob/main/plugins/python/python_plugin_policy.c
1532 views
/*1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2019-2020 Robert Manner <[email protected]>4*5* Permission to use, copy, modify, and distribute this software for any6* purpose with or without fee is hereby granted, provided that the above7* copyright notice and this permission notice appear in all copies.8*9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.16*/1718#include "python_plugin_common.h"192021static struct PluginContext plugin_ctx;2223extern struct policy_plugin python_policy;2425#define PY_POLICY_PLUGIN_VERSION SUDO_API_MKVERSION(1, 0)2627#define CALLBACK_PLUGINFUNC(func_name) python_policy.func_name28#define CALLBACK_CFUNC(func_name) python_plugin_policy_ ## func_name2930// This also verifies compile time that the name matches the sudo plugin API.31#define CALLBACK_PYNAME(func_name) ((void)CALLBACK_PLUGINFUNC(func_name), #func_name)3233#define MARK_CALLBACK_OPTIONAL(function_name) \34do { \35python_plugin_mark_callback_optional(&plugin_ctx, CALLBACK_PYNAME(function_name), \36(void **)&CALLBACK_PLUGINFUNC(function_name)); \37} while(0)383940static int41python_plugin_policy_open(unsigned int version, sudo_conv_t conversation,42sudo_printf_t sudo_printf, char * const settings[],43char * const user_info[], char * const user_env[],44char * const plugin_options[], const char **errstr)45{46debug_decl(python_plugin_policy_open, PYTHON_DEBUG_CALLBACKS);4748if (version < SUDO_API_MKVERSION(1, 2)) {49sudo_printf(SUDO_CONV_ERROR_MSG,50"Error: Python policy plugin requires at least plugin API version 1.2\n");51debug_return_int(SUDO_RC_ERROR);52}5354int rc = python_plugin_register_logging(conversation, sudo_printf, settings);55if (rc != SUDO_RC_OK)56debug_return_int(rc);5758rc = python_plugin_init(&plugin_ctx, plugin_options, version);59if (rc != SUDO_RC_OK)60debug_return_int(rc);6162rc = python_plugin_construct(&plugin_ctx, PY_POLICY_PLUGIN_VERSION, settings,63user_info, user_env, plugin_options);64CALLBACK_SET_ERROR(&plugin_ctx, errstr);65if (rc != SUDO_RC_OK) {66debug_return_int(rc);67}6869// skip plugin callbacks which are not mandatory70MARK_CALLBACK_OPTIONAL(list);71MARK_CALLBACK_OPTIONAL(validate);72MARK_CALLBACK_OPTIONAL(invalidate);73MARK_CALLBACK_OPTIONAL(init_session);74// check_policy, open and close are mandatory7576debug_return_int(rc);77}7879static void80python_plugin_policy_close(int exit_status, int error)81{82debug_decl(python_plugin_policy_close, PYTHON_DEBUG_CALLBACKS);83python_plugin_close(&plugin_ctx, CALLBACK_PYNAME(close),84Py_BuildValue("(ii)", error == 0 ? exit_status : -1, error));85debug_return;86}8788static int89python_plugin_policy_check(int argc, char * const argv[],90char *env_add[], char **command_info_out[],91char **argv_out[], char **user_env_out[], const char **errstr)92{93debug_decl(python_plugin_policy_check, PYTHON_DEBUG_CALLBACKS);94int rc = SUDO_RC_ERROR;9596PyThreadState_Swap(plugin_ctx.py_interpreter);9798*command_info_out = *argv_out = *user_env_out = NULL;99100PyObject *py_argv = py_str_array_to_tuple_with_count(argc, argv);101102PyObject *py_env_add = py_str_array_to_tuple(env_add);103PyObject *py_result = NULL;104105if (py_argv == NULL || py_env_add == NULL) {106sudo_debug_printf(SUDO_DEBUG_ERROR, "Failed to create some of the arguments for the python call "107"(py_argv=%p py_env_add=%p)\n", (void *)py_argv, (void *)py_env_add);108goto cleanup;109}110111py_result = python_plugin_api_call(&plugin_ctx, CALLBACK_PYNAME(check_policy),112Py_BuildValue("(OO)", py_argv, py_env_add));113CALLBACK_SET_ERROR(&plugin_ctx, errstr);114if (py_result == NULL)115goto cleanup;116117PyObject *py_rc = NULL,118*py_command_info_out = NULL,119*py_argv_out = NULL,120*py_user_env_out = NULL;121if (PyTuple_Check(py_result))122{123if (!PyArg_ParseTuple(py_result, "O!|O!O!O!:python_plugin.check_policy",124&PyLong_Type, &py_rc,125&PyTuple_Type, &py_command_info_out,126&PyTuple_Type, &py_argv_out,127&PyTuple_Type, &py_user_env_out))128{129goto cleanup;130}131} else {132py_rc = py_result;133}134135if (py_command_info_out != NULL)136*command_info_out = py_str_array_from_tuple(py_command_info_out);137138if (py_argv_out != NULL)139*argv_out = py_str_array_from_tuple(py_argv_out);140141if (py_user_env_out != NULL)142*user_env_out = py_str_array_from_tuple(py_user_env_out);143144rc = python_plugin_rc_to_int(py_rc);145146cleanup:147if (PyErr_Occurred()) {148py_log_last_error(NULL);149rc = SUDO_RC_ERROR;150free(*command_info_out);151free(*argv_out);152free(*user_env_out);153*command_info_out = *argv_out = *user_env_out = NULL;154}155156Py_XDECREF(py_argv);157Py_XDECREF(py_env_add);158Py_XDECREF(py_result);159160if (rc == SUDO_RC_ACCEPT)161plugin_ctx.call_close = 1;162163debug_return_int(rc);164}165166static int167python_plugin_policy_list(int argc, char * const argv[], int verbose, const char *list_user, const char **errstr)168{169debug_decl(python_plugin_policy_list, PYTHON_DEBUG_CALLBACKS);170171PyThreadState_Swap(plugin_ctx.py_interpreter);172173PyObject *py_argv = py_str_array_to_tuple_with_count(argc, argv);174if (py_argv == NULL) {175sudo_debug_printf(SUDO_DEBUG_ERROR, "%s: Failed to create argv argument for the python call\n", __func__);176debug_return_int(SUDO_RC_ERROR);177}178179int rc = python_plugin_api_rc_call(&plugin_ctx, CALLBACK_PYNAME(list),180Py_BuildValue("(Oiz)", py_argv, verbose, list_user));181182Py_XDECREF(py_argv);183184CALLBACK_SET_ERROR(&plugin_ctx, errstr);185debug_return_int(rc);186}187188static int189python_plugin_policy_version(int verbose)190{191debug_decl(python_plugin_policy_version, PYTHON_DEBUG_CALLBACKS);192193PyThreadState_Swap(plugin_ctx.py_interpreter);194195debug_return_int(python_plugin_show_version(&plugin_ctx, CALLBACK_PYNAME(show_version),196verbose, PY_POLICY_PLUGIN_VERSION, "policy"));197}198199static int200python_plugin_policy_validate(const char **errstr)201{202debug_decl(python_plugin_policy_validate, PYTHON_DEBUG_CALLBACKS);203PyThreadState_Swap(plugin_ctx.py_interpreter);204int rc = python_plugin_api_rc_call(&plugin_ctx, CALLBACK_PYNAME(validate), NULL);205CALLBACK_SET_ERROR(&plugin_ctx, errstr);206debug_return_int(rc);207}208209static void210python_plugin_policy_invalidate(int unlinkit)211{212debug_decl(python_plugin_policy_invalidate, PYTHON_DEBUG_CALLBACKS);213PyThreadState_Swap(plugin_ctx.py_interpreter);214python_plugin_api_rc_call(&plugin_ctx, CALLBACK_PYNAME(invalidate),215Py_BuildValue("(i)", unlinkit));216debug_return;217}218219static int220python_plugin_policy_init_session(struct passwd *pwd, char **user_env[], const char **errstr)221{222debug_decl(python_plugin_policy_init_session, PYTHON_DEBUG_CALLBACKS);223int rc = SUDO_RC_ERROR;224PyThreadState_Swap(plugin_ctx.py_interpreter);225PyObject *py_pwd = NULL, *py_user_env = NULL, *py_result = NULL;226227py_pwd = py_from_passwd(pwd);228if (py_pwd == NULL)229goto cleanup;230231py_user_env = py_str_array_to_tuple(*user_env);232if (py_user_env == NULL)233goto cleanup;234235py_result = python_plugin_api_call(&plugin_ctx, CALLBACK_PYNAME(init_session),236Py_BuildValue("(OO)", py_pwd, py_user_env));237CALLBACK_SET_ERROR(&plugin_ctx, errstr);238if (py_result == NULL)239goto cleanup;240241PyObject *py_user_env_out = NULL, *py_rc = NULL;242if (PyTuple_Check(py_result)) {243if (!PyArg_ParseTuple(py_result, "O!|O!:python_plugin.init_session",244&PyLong_Type, &py_rc,245&PyTuple_Type, &py_user_env_out)) {246goto cleanup;247}248} else {249py_rc = py_result;250}251252if (py_user_env_out != NULL) {253str_array_free(user_env);254*user_env = py_str_array_from_tuple(py_user_env_out);255if (*user_env == NULL)256goto cleanup;257}258259rc = python_plugin_rc_to_int(py_rc);260261cleanup:262Py_XDECREF(py_pwd);263Py_XDECREF(py_user_env);264Py_XDECREF(py_result);265266debug_return_int(rc);267}268269sudo_dso_public struct policy_plugin python_policy = {270SUDO_POLICY_PLUGIN,271SUDO_API_VERSION,272CALLBACK_CFUNC(open),273CALLBACK_CFUNC(close),274CALLBACK_CFUNC(version),275CALLBACK_CFUNC(check),276CALLBACK_CFUNC(list),277CALLBACK_CFUNC(validate),278CALLBACK_CFUNC(invalidate),279CALLBACK_CFUNC(init_session),280NULL, /* register_hooks */281NULL, /* deregister_hooks */282NULL /* event_alloc */283};284285286