Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/plugins/python/python_plugin_io.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 2019-2020 Robert Manner <[email protected]>
5
*
6
* Permission to use, copy, modify, and distribute this software for any
7
* purpose with or without fee is hereby granted, provided that the above
8
* copyright notice and this permission notice appear in all copies.
9
*
10
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
*/
18
19
#include "python_plugin_common.h"
20
21
struct IOPluginContext
22
{
23
struct PluginContext base_ctx;
24
struct io_plugin *io_plugin;
25
};
26
27
#define BASE_CTX(io_ctx) (&(io_ctx->base_ctx))
28
29
#define PY_IO_PLUGIN_VERSION SUDO_API_MKVERSION(1, 0)
30
31
#define CALLBACK_PLUGINFUNC(func_name) io_ctx->io_plugin->func_name
32
33
// This also verifies compile time that the name matches the sudo plugin API.
34
#define CALLBACK_PYNAME(func_name) ((void)CALLBACK_PLUGINFUNC(func_name), #func_name)
35
36
#define MARK_CALLBACK_OPTIONAL(function_name) \
37
do { \
38
python_plugin_mark_callback_optional(plugin_ctx, CALLBACK_PYNAME(function_name), \
39
(void **)&CALLBACK_PLUGINFUNC(function_name)); \
40
} while(0)
41
42
sudo_dso_public struct io_plugin *python_io_clone(void);
43
44
static int
45
_call_plugin_open(struct IOPluginContext *io_ctx, int argc, char * const argv[], char * const command_info[])
46
{
47
debug_decl(_call_plugin_open, PYTHON_DEBUG_CALLBACKS);
48
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
49
plugin_ctx->call_close = 1;
50
51
if (!PyObject_HasAttrString(plugin_ctx->py_instance, CALLBACK_PYNAME(open))) {
52
debug_return_int(SUDO_RC_OK);
53
}
54
55
int rc = SUDO_RC_ERROR;
56
PyObject *py_argv = py_str_array_to_tuple_with_count(argc, argv);
57
PyObject *py_command_info = py_str_array_to_tuple(command_info);
58
59
if (py_argv != NULL && py_command_info != NULL) {
60
rc = python_plugin_api_rc_call(plugin_ctx, CALLBACK_PYNAME(open),
61
Py_BuildValue("(OO)", py_argv, py_command_info));
62
}
63
64
if (rc != SUDO_RC_OK)
65
plugin_ctx->call_close = 0;
66
67
Py_XDECREF(py_argv);
68
Py_XDECREF(py_command_info);
69
debug_return_int(rc);
70
}
71
72
static int
73
python_plugin_io_open(struct IOPluginContext *io_ctx,
74
unsigned int version, sudo_conv_t conversation,
75
sudo_printf_t sudo_printf, char * const settings[],
76
char * const user_info[], char * const command_info[],
77
int argc, char * const argv[], char * const user_env[],
78
char * const plugin_options[], const char **errstr)
79
{
80
debug_decl(python_plugin_io_open, PYTHON_DEBUG_CALLBACKS);
81
82
if (version < SUDO_API_MKVERSION(1, 2)) {
83
sudo_printf(SUDO_CONV_ERROR_MSG,
84
"Error: Python IO plugin requires at least plugin API version 1.2\n");
85
debug_return_int(SUDO_RC_ERROR);
86
}
87
88
int rc = python_plugin_register_logging(conversation, sudo_printf, settings);
89
if (rc != SUDO_RC_OK)
90
debug_return_int(rc);
91
92
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
93
rc = python_plugin_init(plugin_ctx, plugin_options, version);
94
95
if (rc != SUDO_RC_OK)
96
debug_return_int(rc);
97
98
rc = python_plugin_construct(plugin_ctx, PY_IO_PLUGIN_VERSION,
99
settings, user_info, user_env, plugin_options);
100
CALLBACK_SET_ERROR(plugin_ctx, errstr);
101
if (rc != SUDO_RC_OK) {
102
debug_return_int(rc);
103
}
104
105
// skip plugin callbacks which are not mandatory
106
MARK_CALLBACK_OPTIONAL(log_ttyin);
107
MARK_CALLBACK_OPTIONAL(log_ttyout);
108
MARK_CALLBACK_OPTIONAL(log_stdin);
109
MARK_CALLBACK_OPTIONAL(log_stdout);
110
MARK_CALLBACK_OPTIONAL(log_stderr);
111
MARK_CALLBACK_OPTIONAL(change_winsize);
112
MARK_CALLBACK_OPTIONAL(log_suspend);
113
// open and close are mandatory
114
115
if (argc > 0) // we only call open if there is request for running sg
116
rc = _call_plugin_open(io_ctx, argc, argv, command_info);
117
118
CALLBACK_SET_ERROR(plugin_ctx, errstr);
119
debug_return_int(rc);
120
}
121
122
static void
123
python_plugin_io_close(struct IOPluginContext *io_ctx, int exit_status, int error)
124
{
125
debug_decl(python_plugin_io_close, PYTHON_DEBUG_CALLBACKS);
126
python_plugin_close(BASE_CTX(io_ctx), CALLBACK_PYNAME(close),
127
Py_BuildValue("(ii)", error == 0 ? exit_status : -1, error));
128
debug_return;
129
}
130
131
static int
132
python_plugin_io_show_version(struct IOPluginContext *io_ctx, int verbose)
133
{
134
debug_decl(python_plugin_io_show_version, PYTHON_DEBUG_CALLBACKS);
135
136
PyThreadState_Swap(BASE_CTX(io_ctx)->py_interpreter);
137
138
debug_return_int(python_plugin_show_version(BASE_CTX(io_ctx), CALLBACK_PYNAME(show_version),
139
verbose, PY_IO_PLUGIN_VERSION, "io"));
140
}
141
142
static int
143
python_plugin_io_log_ttyin(struct IOPluginContext *io_ctx, const char *buf, unsigned int len, const char **errstr)
144
{
145
debug_decl(python_plugin_io_log_ttyin, PYTHON_DEBUG_CALLBACKS);
146
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
147
PyThreadState_Swap(plugin_ctx->py_interpreter);
148
int rc = python_plugin_api_rc_call(plugin_ctx, CALLBACK_PYNAME(log_ttyin),
149
Py_BuildValue("(s#)", buf, len));
150
CALLBACK_SET_ERROR(plugin_ctx, errstr);
151
debug_return_int(rc);
152
}
153
154
static int
155
python_plugin_io_log_ttyout(struct IOPluginContext *io_ctx, const char *buf, unsigned int len, const char **errstr)
156
{
157
debug_decl(python_plugin_io_log_ttyout, PYTHON_DEBUG_CALLBACKS);
158
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
159
PyThreadState_Swap(plugin_ctx->py_interpreter);
160
int rc = python_plugin_api_rc_call(plugin_ctx, CALLBACK_PYNAME(log_ttyout),
161
Py_BuildValue("(s#)", buf, len));
162
CALLBACK_SET_ERROR(plugin_ctx, errstr);
163
debug_return_int(rc);
164
}
165
166
static int
167
python_plugin_io_log_stdin(struct IOPluginContext *io_ctx, const char *buf, unsigned int len, const char **errstr)
168
{
169
debug_decl(python_plugin_io_log_stdin, PYTHON_DEBUG_CALLBACKS);
170
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
171
PyThreadState_Swap(plugin_ctx->py_interpreter);
172
int rc = python_plugin_api_rc_call(plugin_ctx, CALLBACK_PYNAME(log_stdin),
173
Py_BuildValue("(s#)", buf, len));
174
CALLBACK_SET_ERROR(plugin_ctx, errstr);
175
debug_return_int(rc);
176
}
177
178
static int
179
python_plugin_io_log_stdout(struct IOPluginContext *io_ctx, const char *buf, unsigned int len, const char **errstr)
180
{
181
debug_decl(python_plugin_io_log_stdout, PYTHON_DEBUG_CALLBACKS);
182
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
183
PyThreadState_Swap(plugin_ctx->py_interpreter);
184
int rc = python_plugin_api_rc_call(plugin_ctx, CALLBACK_PYNAME(log_stdout),
185
Py_BuildValue("(s#)", buf, len));
186
CALLBACK_SET_ERROR(plugin_ctx, errstr);
187
debug_return_int(rc);
188
}
189
190
static int
191
python_plugin_io_log_stderr(struct IOPluginContext *io_ctx, const char *buf, unsigned int len, const char **errstr)
192
{
193
debug_decl(python_plugin_io_log_stderr, PYTHON_DEBUG_CALLBACKS);
194
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
195
PyThreadState_Swap(plugin_ctx->py_interpreter);
196
int rc = python_plugin_api_rc_call(plugin_ctx, CALLBACK_PYNAME(log_stderr),
197
Py_BuildValue("(s#)", buf, len));
198
CALLBACK_SET_ERROR(plugin_ctx, errstr);
199
debug_return_int(rc);
200
}
201
202
static int
203
python_plugin_io_change_winsize(struct IOPluginContext *io_ctx, unsigned int line, unsigned int cols, const char **errstr)
204
{
205
debug_decl(python_plugin_io_change_winsize, PYTHON_DEBUG_CALLBACKS);
206
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
207
PyThreadState_Swap(plugin_ctx->py_interpreter);
208
int rc = python_plugin_api_rc_call(plugin_ctx, CALLBACK_PYNAME(change_winsize),
209
Py_BuildValue("(ii)", line, cols));
210
CALLBACK_SET_ERROR(plugin_ctx, errstr);
211
debug_return_int(rc);
212
}
213
214
static int
215
python_plugin_io_log_suspend(struct IOPluginContext *io_ctx, int signo, const char **errstr)
216
{
217
debug_decl(python_plugin_io_log_suspend, PYTHON_DEBUG_CALLBACKS);
218
struct PluginContext *plugin_ctx = BASE_CTX(io_ctx);
219
PyThreadState_Swap(plugin_ctx->py_interpreter);
220
int rc = python_plugin_api_rc_call(plugin_ctx, CALLBACK_PYNAME(log_suspend),
221
Py_BuildValue("(i)", signo));
222
CALLBACK_SET_ERROR(plugin_ctx, errstr);
223
debug_return_int(rc);
224
}
225
226
// generate symbols for loading multiple io plugins:
227
sudo_dso_public struct io_plugin python_io;
228
#define IO_SYMBOL_NAME(symbol) symbol
229
#include "python_plugin_io_multi.inc"
230
#define IO_SYMBOL_NAME(symbol) symbol##1
231
#include "python_plugin_io_multi.inc"
232
#define IO_SYMBOL_NAME(symbol) symbol##2
233
#include "python_plugin_io_multi.inc"
234
#define IO_SYMBOL_NAME(symbol) symbol##3
235
#include "python_plugin_io_multi.inc"
236
#define IO_SYMBOL_NAME(symbol) symbol##4
237
#include "python_plugin_io_multi.inc"
238
#define IO_SYMBOL_NAME(symbol) symbol##5
239
#include "python_plugin_io_multi.inc"
240
#define IO_SYMBOL_NAME(symbol) symbol##6
241
#include "python_plugin_io_multi.inc"
242
#define IO_SYMBOL_NAME(symbol) symbol##7
243
#include "python_plugin_io_multi.inc"
244
245
static struct io_plugin *extra_io_plugins[] = {
246
&python_io1,
247
&python_io2,
248
&python_io3,
249
&python_io4,
250
&python_io5,
251
&python_io6,
252
&python_io7
253
};
254
255
struct io_plugin *
256
python_io_clone(void)
257
{
258
static size_t counter = 0;
259
struct io_plugin *next_plugin = NULL;
260
261
size_t max = sizeof(extra_io_plugins) / sizeof(*extra_io_plugins);
262
if (counter < max) {
263
next_plugin = extra_io_plugins[counter];
264
++counter;
265
} else if (counter == max) {
266
++counter;
267
py_sudo_log(SUDO_CONV_ERROR_MSG, "sudo: loading more than %d sudo python IO plugins is not supported\n", counter);
268
}
269
270
return next_plugin;
271
}
272
273