Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sudo-project
GitHub Repository: sudo-project/sudo
Path: blob/main/plugins/python/regress/check_python_examples.c
1532 views
1
/*
2
* SPDX-License-Identifier: ISC
3
*
4
* Copyright (c) 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 "testhelpers.h"
20
#include <unistd.h>
21
22
#include <sudo_dso.h>
23
24
#define DECL_PLUGIN(type, variable_name) \
25
static struct type *variable_name = NULL; \
26
static struct type variable_name ## _original
27
28
#define RESTORE_PYTHON_PLUGIN(variable_name) \
29
memcpy(variable_name, &(variable_name ## _original), sizeof(variable_name ## _original))
30
31
#define SAVE_PYTHON_PLUGIN(variable_name) \
32
memcpy(&(variable_name ## _original), variable_name, sizeof(variable_name ## _original))
33
34
static const char *python_plugin_so_path = NULL;
35
static void *python_plugin_handle = NULL;
36
DECL_PLUGIN(io_plugin, python_io);
37
DECL_PLUGIN(policy_plugin, python_policy);
38
DECL_PLUGIN(approval_plugin, python_approval);
39
DECL_PLUGIN(audit_plugin, python_audit);
40
DECL_PLUGIN(sudoers_group_plugin, group_plugin);
41
42
static struct passwd example_pwd;
43
static bool verbose;
44
45
static int _init_symbols(void);
46
static int _unlink_symbols(void);
47
48
static void
49
create_plugin_options(const char *module_name, const char *class_name, const char *extra_option)
50
{
51
char opt_module_path[PATH_MAX + 256];
52
char opt_classname[PATH_MAX + 256];
53
snprintf(opt_module_path, sizeof(opt_module_path),
54
"ModulePath=" SRC_DIR "/%s.py", module_name);
55
56
snprintf(opt_classname, sizeof(opt_classname), "ClassName=%s", class_name);
57
58
str_array_free(&data.plugin_options);
59
size_t count = 3 + (extra_option != NULL);
60
data.plugin_options = create_str_array(count, opt_module_path,
61
opt_classname, extra_option, NULL);
62
}
63
64
static void
65
create_io_plugin_options(const char *log_path)
66
{
67
char opt_logpath[PATH_MAX + 16];
68
snprintf(opt_logpath, sizeof(opt_logpath), "LogPath=%s", log_path);
69
create_plugin_options("example_io_plugin", "SudoIOPlugin", opt_logpath);
70
}
71
72
static void
73
create_debugging_plugin_options(void)
74
{
75
create_plugin_options("example_debugging", "DebugDemoPlugin", NULL);
76
}
77
78
static void
79
create_audit_plugin_options(const char *extra_argument)
80
{
81
create_plugin_options("example_audit_plugin", "SudoAuditPlugin", extra_argument);
82
}
83
84
static void
85
create_conversation_plugin_options(void)
86
{
87
char opt_logpath[PATH_MAX + 16];
88
snprintf(opt_logpath, sizeof(opt_logpath), "LogPath=%s", data.tmp_dir);
89
create_plugin_options("example_conversation", "ReasonLoggerIOPlugin", opt_logpath);
90
}
91
92
static void
93
create_policy_plugin_options(void)
94
{
95
create_plugin_options("example_policy_plugin", "SudoPolicyPlugin", NULL);
96
}
97
98
static int
99
init(void)
100
{
101
// always start each test from clean state
102
memset(&data, 0, sizeof(data));
103
104
memset(&example_pwd, 0, sizeof(example_pwd));
105
example_pwd.pw_name = (char *)"pw_name";
106
example_pwd.pw_passwd = (char *)"pw_passwd";
107
example_pwd.pw_gecos = (char *)"pw_gecos";
108
example_pwd.pw_shell = (char *)"pw_shell";
109
example_pwd.pw_dir = (char *)"pw_dir";
110
example_pwd.pw_uid = (uid_t)1001;
111
example_pwd.pw_gid = (gid_t)101;
112
113
VERIFY_TRUE(asprintf(&data.tmp_dir, TEMP_PATH_TEMPLATE) >= 0);
114
VERIFY_NOT_NULL(mkdtemp(data.tmp_dir));
115
116
sudo_conf_clear_paths();
117
118
// some default values for the plugin open:
119
data.settings = create_str_array(1, NULL);
120
data.user_info = create_str_array(1, NULL);
121
data.command_info = create_str_array(1, NULL);
122
data.plugin_argc = 0;
123
data.plugin_argv = create_str_array(1, NULL);
124
data.user_env = create_str_array(1, NULL);
125
126
VERIFY_TRUE(_init_symbols());
127
return true;
128
}
129
130
static int
131
cleanup(int success)
132
{
133
if (!success) {
134
printf("\nThe output of the plugin:\n%s", data.stdout_str);
135
printf("\nThe error output of the plugin:\n%s", data.stderr_str);
136
}
137
138
VERIFY_TRUE(rmdir_recursive(data.tmp_dir));
139
if (data.tmp_dir2) {
140
VERIFY_TRUE(rmdir_recursive(data.tmp_dir2));
141
}
142
143
free(data.tmp_dir);
144
free(data.tmp_dir2);
145
146
str_array_free(&data.settings);
147
str_array_free(&data.user_info);
148
str_array_free(&data.command_info);
149
str_array_free(&data.plugin_argv);
150
str_array_free(&data.user_env);
151
str_array_free(&data.plugin_options);
152
153
return true;
154
}
155
156
static int
157
check_example_io_plugin_version_display(int is_verbose)
158
{
159
const char *errstr = NULL;
160
create_io_plugin_options(data.tmp_dir);
161
162
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
163
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv, data.user_env,
164
data.plugin_options, &errstr), SUDO_RC_OK);
165
VERIFY_INT(python_io->show_version(is_verbose), SUDO_RC_OK);
166
167
python_io->close(0, 0); // this should not call the python plugin close as there was no command run invocation
168
169
if (is_verbose) {
170
// Note: the exact python version is environment dependent
171
VERIFY_STR_CONTAINS(data.stdout_str, "Python interpreter version:");
172
*strstr(data.stdout_str, "Python interpreter version:") = '\0';
173
VERIFY_STDOUT(expected_path("check_example_io_plugin_version_display_full.stdout"));
174
} else {
175
VERIFY_STDOUT(expected_path("check_example_io_plugin_version_display.stdout"));
176
}
177
178
VERIFY_STDERR(expected_path("check_example_io_plugin_version_display.stderr"));
179
VERIFY_FILE("sudo.log", expected_path("check_example_io_plugin_version_display.stored"));
180
181
return true;
182
}
183
184
static int
185
check_example_io_plugin_command_log(void)
186
{
187
const char *errstr = NULL;
188
create_io_plugin_options(data.tmp_dir);
189
190
str_array_free(&data.plugin_argv);
191
data.plugin_argc = 2;
192
data.plugin_argv = create_str_array(3, "id", "--help", NULL);
193
194
str_array_free(&data.command_info);
195
data.command_info = create_str_array(3, "command=/bin/id", "runas_uid=0", NULL);
196
197
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
198
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
199
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
200
VERIFY_PTR(errstr, NULL);
201
VERIFY_INT(python_io->log_stdin("some standard input", strlen("some standard input"), &errstr), SUDO_RC_OK);
202
VERIFY_PTR(errstr, NULL);
203
VERIFY_INT(python_io->log_stdout("some standard output", strlen("some standard output"), &errstr), SUDO_RC_OK);
204
VERIFY_PTR(errstr, NULL);
205
VERIFY_INT(python_io->log_stderr("some standard error", strlen("some standard error"), &errstr), SUDO_RC_OK);
206
VERIFY_PTR(errstr, NULL);
207
VERIFY_INT(python_io->log_suspend(SIGTSTP, &errstr), SUDO_RC_OK);
208
VERIFY_PTR(errstr, NULL);
209
VERIFY_INT(python_io->log_suspend(SIGCONT, &errstr), SUDO_RC_OK);
210
VERIFY_PTR(errstr, NULL);
211
VERIFY_INT(python_io->change_winsize(200, 100, &errstr), SUDO_RC_OK);
212
VERIFY_PTR(errstr, NULL);
213
VERIFY_INT(python_io->log_ttyin("some tty input", strlen("some tty input"), &errstr), SUDO_RC_OK);
214
VERIFY_PTR(errstr, NULL);
215
VERIFY_INT(python_io->log_ttyout("some tty output", strlen("some tty output"), &errstr), SUDO_RC_OK);
216
VERIFY_PTR(errstr, NULL);
217
218
python_io->close(1, 0); // successful execution, command returned 1
219
220
VERIFY_STDOUT(expected_path("check_example_io_plugin_command_log.stdout"));
221
VERIFY_STDERR(expected_path("check_example_io_plugin_command_log.stderr"));
222
VERIFY_FILE("sudo.log", expected_path("check_example_io_plugin_command_log.stored"));
223
224
return true;
225
}
226
227
typedef struct io_plugin * (io_clone_func)(void);
228
229
static int
230
check_example_io_plugin_command_log_multiple(void)
231
{
232
const char *errstr = NULL;
233
234
// verify multiple python io plugin symbols are available
235
io_clone_func *python_io_clone = (io_clone_func *)sudo_dso_findsym(python_plugin_handle, "python_io_clone");
236
VERIFY_PTR_NE(python_io_clone, NULL);
237
238
struct io_plugin *python_io2 = NULL;
239
240
for (int i = 0; i < 7; ++i) {
241
python_io2 = (*python_io_clone)();
242
VERIFY_PTR_NE(python_io2, NULL);
243
VERIFY_PTR_NE(python_io2, python_io);
244
}
245
246
// open the first plugin and let it log to tmp_dir
247
create_io_plugin_options(data.tmp_dir);
248
249
str_array_free(&data.plugin_argv);
250
data.plugin_argc = 2;
251
data.plugin_argv = create_str_array(3, "id", "--help", NULL);
252
253
str_array_free(&data.command_info);
254
data.command_info = create_str_array(3, "command=/bin/id", "runas_uid=0", NULL);
255
256
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
257
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
258
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
259
VERIFY_PTR(errstr, NULL);
260
261
// For verifying the error message of no more plugin. It should be displayed only once.
262
VERIFY_PTR((*python_io_clone)(), NULL);
263
VERIFY_PTR((*python_io_clone)(), NULL);
264
265
// open the second plugin with another log directory
266
VERIFY_TRUE(asprintf(&data.tmp_dir2, TEMP_PATH_TEMPLATE) >= 0);
267
VERIFY_NOT_NULL(mkdtemp(data.tmp_dir2));
268
create_io_plugin_options(data.tmp_dir2);
269
270
str_array_free(&data.plugin_argv);
271
data.plugin_argc = 1;
272
data.plugin_argv = create_str_array(2, "whoami", NULL);
273
274
str_array_free(&data.command_info);
275
data.command_info = create_str_array(3, "command=/bin/whoami", "runas_uid=1", NULL);
276
277
VERIFY_INT(python_io2->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
278
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
279
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
280
VERIFY_PTR(errstr, NULL);
281
282
VERIFY_INT(python_io->log_stdin("stdin for plugin 1", strlen("stdin for plugin 1"), &errstr), SUDO_RC_OK);
283
VERIFY_PTR(errstr, NULL);
284
VERIFY_INT(python_io2->log_stdin("stdin for plugin 2", strlen("stdin for plugin 2"), &errstr), SUDO_RC_OK);
285
VERIFY_PTR(errstr, NULL);
286
VERIFY_INT(python_io->log_stdout("stdout for plugin 1", strlen("stdout for plugin 1"), &errstr), SUDO_RC_OK);
287
VERIFY_PTR(errstr, NULL);
288
VERIFY_INT(python_io2->log_stdout("stdout for plugin 2", strlen("stdout for plugin 2"), &errstr), SUDO_RC_OK);
289
VERIFY_PTR(errstr, NULL);
290
VERIFY_INT(python_io->log_stderr("stderr for plugin 1", strlen("stderr for plugin 1"), &errstr), SUDO_RC_OK);
291
VERIFY_PTR(errstr, NULL);
292
VERIFY_INT(python_io2->log_stderr("stderr for plugin 2", strlen("stderr for plugin 2"), &errstr), SUDO_RC_OK);
293
VERIFY_PTR(errstr, NULL);
294
VERIFY_INT(python_io->log_suspend(SIGTSTP, &errstr), SUDO_RC_OK);
295
VERIFY_PTR(errstr, NULL);
296
VERIFY_INT(python_io2->log_suspend(SIGSTOP, &errstr), SUDO_RC_OK);
297
VERIFY_PTR(errstr, NULL);
298
VERIFY_INT(python_io->log_suspend(SIGCONT, &errstr), SUDO_RC_OK);
299
VERIFY_PTR(errstr, NULL);
300
VERIFY_INT(python_io2->log_suspend(SIGCONT, &errstr), SUDO_RC_OK);
301
VERIFY_PTR(errstr, NULL);
302
VERIFY_INT(python_io->change_winsize(20, 10, &errstr), SUDO_RC_OK);
303
VERIFY_PTR(errstr, NULL);
304
VERIFY_INT(python_io2->change_winsize(30, 40, &errstr), SUDO_RC_OK);
305
VERIFY_PTR(errstr, NULL);
306
VERIFY_INT(python_io->log_ttyin("tty input for plugin 1", strlen("tty input for plugin 1"), &errstr), SUDO_RC_OK);
307
VERIFY_PTR(errstr, NULL);
308
VERIFY_INT(python_io2->log_ttyin("tty input for plugin 2", strlen("tty input for plugin 2"), &errstr), SUDO_RC_OK);
309
VERIFY_PTR(errstr, NULL);
310
VERIFY_INT(python_io->log_ttyout("tty output for plugin 1", strlen("tty output for plugin 1"), &errstr), SUDO_RC_OK);
311
VERIFY_PTR(errstr, NULL);
312
VERIFY_INT(python_io2->log_ttyout("tty output for plugin 2", strlen("tty output for plugin 2"), &errstr), SUDO_RC_OK);
313
VERIFY_PTR(errstr, NULL);
314
315
python_io->close(1, 0); // successful execution, command returned 1
316
python_io2->close(2, 0); // command returned 2
317
318
VERIFY_STDOUT(expected_path("check_example_io_plugin_command_log_multiple.stdout"));
319
VERIFY_STDERR(expected_path("check_example_io_plugin_command_log_multiple.stderr"));
320
VERIFY_FILE("sudo.log", expected_path("check_example_io_plugin_command_log_multiple1.stored"));
321
VERIFY_TRUE(verify_file(data.tmp_dir2, "sudo.log", expected_path("check_example_io_plugin_command_log_multiple2.stored")));
322
323
return true;
324
}
325
326
static int
327
check_example_io_plugin_failed_to_start_command(void)
328
{
329
const char *errstr = NULL;
330
331
create_io_plugin_options(data.tmp_dir);
332
333
str_array_free(&data.plugin_argv);
334
data.plugin_argc = 1;
335
data.plugin_argv = create_str_array(2, "cmd", NULL);
336
337
str_array_free(&data.command_info);
338
data.command_info = create_str_array(3, "command=/usr/share/cmd", "runas_uid=0", NULL);
339
340
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
341
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
342
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
343
VERIFY_PTR(errstr, NULL);
344
345
python_io->close(0, EPERM); // execve returned with error
346
347
VERIFY_STDOUT(expected_path("check_example_io_plugin_failed_to_start_command.stdout"));
348
VERIFY_STDERR(expected_path("check_example_io_plugin_failed_to_start_command.stderr"));
349
VERIFY_FILE("sudo.log", expected_path("check_example_io_plugin_failed_to_start_command.stored"));
350
351
return true;
352
}
353
354
static int
355
check_example_io_plugin_fails_with_python_backtrace(void)
356
{
357
const char *errstr = NULL;
358
359
create_io_plugin_options("/some/not/writable/directory");
360
361
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
362
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
363
data.user_env, data.plugin_options, &errstr), SUDO_RC_ERROR);
364
VERIFY_PTR(errstr, NULL);
365
366
VERIFY_STDOUT(expected_path("check_example_io_plugin_fails_with_python_backtrace.stdout"));
367
VERIFY_STDERR(expected_path("check_example_io_plugin_fails_with_python_backtrace.stderr"));
368
369
python_io->close(0, 0);
370
return true;
371
}
372
373
static int
374
check_io_plugin_reports_error(void)
375
{
376
const char *errstr = NULL;
377
str_array_free(&data.plugin_options);
378
data.plugin_options = create_str_array(
379
3,
380
"ModulePath=" SRC_DIR "/regress/plugin_errorstr.py",
381
"ClassName=ConstructErrorPlugin",
382
NULL
383
);
384
385
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
386
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
387
data.user_env, data.plugin_options, &errstr), SUDO_RC_ERROR);
388
389
VERIFY_STR(errstr, "Something wrong in plugin constructor");
390
errstr = NULL;
391
392
python_io->close(0, 0);
393
394
str_array_free(&data.plugin_options);
395
data.plugin_options = create_str_array(
396
3,
397
"ModulePath=" SRC_DIR "/regress/plugin_errorstr.py",
398
"ClassName=ErrorMsgPlugin",
399
NULL
400
);
401
402
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
403
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
404
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
405
VERIFY_PTR(errstr, NULL);
406
407
VERIFY_INT(python_io->log_stdin("", 0, &errstr), SUDO_RC_ERROR);
408
VERIFY_STR(errstr, "Something wrong in log_stdin");
409
410
errstr = (void *)13;
411
VERIFY_INT(python_io->log_stdout("", 0, &errstr), SUDO_RC_ERROR);
412
VERIFY_STR(errstr, "Something wrong in log_stdout");
413
414
errstr = NULL;
415
VERIFY_INT(python_io->log_stderr("", 0, &errstr), SUDO_RC_ERROR);
416
VERIFY_STR(errstr, "Something wrong in log_stderr");
417
418
errstr = NULL;
419
VERIFY_INT(python_io->log_ttyin("", 0, &errstr), SUDO_RC_ERROR);
420
VERIFY_STR(errstr, "Something wrong in log_ttyin");
421
422
errstr = NULL;
423
VERIFY_INT(python_io->log_ttyout("", 0, &errstr), SUDO_RC_ERROR);
424
VERIFY_STR(errstr, "Something wrong in log_ttyout");
425
426
errstr = NULL;
427
VERIFY_INT(python_io->log_suspend(SIGTSTP, &errstr), SUDO_RC_ERROR);
428
VERIFY_STR(errstr, "Something wrong in log_suspend");
429
430
errstr = NULL;
431
VERIFY_INT(python_io->change_winsize(200, 100, &errstr), SUDO_RC_ERROR);
432
VERIFY_STR(errstr, "Something wrong in change_winsize");
433
434
python_io->close(0, 0);
435
436
VERIFY_STR(data.stderr_str, "");
437
VERIFY_STR(data.stdout_str, "");
438
return true;
439
}
440
441
static int
442
check_example_group_plugin(void)
443
{
444
create_plugin_options("example_group_plugin", "SudoGroupPlugin", NULL);
445
446
VERIFY_INT(group_plugin->init(GROUP_API_VERSION, fake_printf, data.plugin_options), SUDO_RC_OK);
447
448
VERIFY_INT(group_plugin->query("test", "mygroup", NULL), SUDO_RC_OK);
449
VERIFY_INT(group_plugin->query("testuser2", "testgroup", NULL), SUDO_RC_OK);
450
VERIFY_INT(group_plugin->query("testuser2", "mygroup", NULL), SUDO_RC_REJECT);
451
VERIFY_INT(group_plugin->query("test", "testgroup", NULL), SUDO_RC_REJECT);
452
453
group_plugin->cleanup();
454
VERIFY_STR(data.stderr_str, "");
455
VERIFY_STR(data.stdout_str, "");
456
return true;
457
}
458
459
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
460
static const char *
461
create_debug_config(const char *debug_spec)
462
{
463
char *result = NULL;
464
465
static char config_path[PATH_MAX] = "/";
466
snprintf(config_path, sizeof(config_path), "%s/sudo.conf", data.tmp_dir);
467
468
char *content = NULL;
469
if (asprintf(&content, "Debug %s %s/debug.log %s\n",
470
"python_plugin.so", data.tmp_dir, debug_spec) < 0)
471
{
472
puts("Failed to allocate string");
473
goto cleanup;
474
}
475
476
if (fwriteall(config_path, content) != true) {
477
printf("Failed to write '%s'\n", config_path);
478
goto cleanup;
479
}
480
481
result = config_path;
482
483
cleanup:
484
free(content);
485
486
return result;
487
}
488
489
static int
490
check_example_group_plugin_is_able_to_debug(void)
491
{
492
const char *config_path = create_debug_config("py_calls@diag");
493
VERIFY_NOT_NULL(config_path);
494
VERIFY_INT(sudo_conf_read(config_path, SUDO_CONF_ALL), true);
495
496
create_plugin_options("example_group_plugin", "SudoGroupPlugin", NULL);
497
498
group_plugin->init(GROUP_API_VERSION, fake_printf, data.plugin_options);
499
500
group_plugin->query("user", "group", &example_pwd);
501
502
group_plugin->cleanup();
503
504
VERIFY_STR(data.stderr_str, "");
505
VERIFY_STR(data.stdout_str, "");
506
507
VERIFY_LOG_LINES(expected_path("check_example_group_plugin_is_able_to_debug.log"));
508
509
return true;
510
}
511
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
512
513
static int
514
check_plugin_unload(void)
515
{
516
// You can call this test to avoid having a lot of subinterpreters
517
// (each plugin->open starts one, and only plugin unlink closes)
518
// It only verifies that python was shut down correctly.
519
VERIFY_TRUE(Py_IsInitialized());
520
VERIFY_TRUE(_unlink_symbols());
521
VERIFY_FALSE(Py_IsInitialized()); // python interpreter could be stopped
522
return true;
523
}
524
525
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
526
static int
527
check_example_debugging(const char *debug_spec)
528
{
529
const char *errstr = NULL;
530
const char *config_path = create_debug_config(debug_spec);
531
VERIFY_NOT_NULL(config_path);
532
VERIFY_INT(sudo_conf_read(config_path, SUDO_CONF_ALL), true);
533
534
create_debugging_plugin_options();
535
536
str_array_free(&data.settings);
537
char *debug_flags_setting = NULL;
538
VERIFY_TRUE(asprintf(&debug_flags_setting, "debug_flags=%s/debug.log %s", data.tmp_dir, debug_spec) >= 0);
539
540
data.settings = create_str_array(3, debug_flags_setting, "plugin_path=python_plugin.so", NULL);
541
542
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
543
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
544
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
545
VERIFY_PTR(errstr, NULL);
546
python_io->close(0, 0);
547
548
VERIFY_STR(data.stderr_str, "");
549
VERIFY_STR(data.stdout_str, "");
550
551
VERIFY_LOG_LINES(expected_path("check_example_debugging_%s.log", debug_spec));
552
553
free(debug_flags_setting);
554
return true;
555
}
556
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
557
558
static int
559
check_loading_fails(const char *name)
560
{
561
const char *errstr = NULL;
562
563
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
564
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
565
data.user_env, data.plugin_options, &errstr), SUDO_RC_ERROR);
566
VERIFY_PTR(errstr, NULL);
567
python_io->close(0, 0);
568
569
VERIFY_STDOUT(expected_path("check_loading_fails_%s.stdout", name));
570
VERIFY_STDERR(expected_path("check_loading_fails_%s.stderr", name));
571
572
return true;
573
}
574
575
static int
576
check_loading_fails_with_missing_path(void)
577
{
578
str_array_free(&data.plugin_options);
579
data.plugin_options = create_str_array(2, "ClassName=DebugDemoPlugin", NULL);
580
return check_loading_fails("missing_path");
581
}
582
583
static int
584
check_loading_succeeds_with_missing_classname(void)
585
{
586
str_array_free(&data.plugin_options);
587
data.plugin_options = create_str_array(2, "ModulePath=" SRC_DIR "/example_debugging.py", NULL);
588
589
const char *errstr = NULL;
590
591
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
592
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
593
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
594
VERIFY_PTR(errstr, NULL);
595
VERIFY_INT(python_io->show_version(1), SUDO_RC_OK);
596
python_io->close(0, 0);
597
598
VERIFY_STDOUT(expected_path("check_loading_succeeds_with_missing_classname.stdout"));
599
VERIFY_STR(data.stderr_str, "");
600
601
return true;
602
}
603
604
static int
605
check_loading_fails_with_missing_classname(void)
606
{
607
str_array_free(&data.plugin_options);
608
data.plugin_options = create_str_array(2, "ModulePath=" SRC_DIR "/regress/plugin_errorstr.py", NULL);
609
return check_loading_fails("missing_classname");
610
}
611
612
static int
613
check_loading_fails_with_wrong_classname(void)
614
{
615
create_plugin_options("example_debugging", "MispelledPluginName", NULL);
616
return check_loading_fails("wrong_classname");
617
}
618
619
static int
620
check_loading_fails_with_wrong_path(void)
621
{
622
str_array_free(&data.plugin_options);
623
data.plugin_options = create_str_array(3, "ModulePath=/wrong_path.py", "ClassName=PluginName", NULL);
624
return check_loading_fails("wrong_path");
625
}
626
627
static int
628
check_example_conversation_plugin_reason_log(int simulate_suspend, const char *description)
629
{
630
const char *errstr = NULL;
631
632
create_conversation_plugin_options();
633
634
str_array_free(&data.plugin_argv); // have a command run
635
data.plugin_argc = 1;
636
data.plugin_argv = create_str_array(2, "/bin/whoami", NULL);
637
638
data.conv_replies[0] = "my fake reason";
639
data.conv_replies[1] = "my real secret reason";
640
641
sudo_conv_t conversation = simulate_suspend ? fake_conversation_with_suspend : fake_conversation;
642
643
VERIFY_INT(python_io->open(SUDO_API_VERSION, conversation, fake_printf, data.settings,
644
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
645
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
646
VERIFY_PTR(errstr, NULL);
647
python_io->close(0, 0);
648
649
VERIFY_STDOUT(expected_path("check_example_conversation_plugin_reason_log_%s.stdout", description));
650
VERIFY_STDERR(expected_path("check_example_conversation_plugin_reason_log_%s.stderr", description));
651
VERIFY_CONV(expected_path("check_example_conversation_plugin_reason_log_%s.conversation", description));
652
VERIFY_FILE("sudo_reasons.txt", expected_path("check_example_conversation_plugin_reason_log_%s.stored", description));
653
return true;
654
}
655
656
static int
657
check_example_conversation_plugin_user_interrupts(void)
658
{
659
const char *errstr = NULL;
660
661
create_conversation_plugin_options();
662
663
str_array_free(&data.plugin_argv); // have a command run
664
data.plugin_argc = 1;
665
data.plugin_argv = create_str_array(2, "/bin/whoami", NULL);
666
667
data.conv_replies[0] = NULL; // this simulates user interrupt for the first question
668
669
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
670
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
671
data.user_env, data.plugin_options, &errstr), SUDO_RC_REJECT);
672
VERIFY_PTR(errstr, NULL);
673
python_io->close(0, 0);
674
675
VERIFY_STDOUT(expected_path("check_example_conversation_plugin_user_interrupts.stdout"));
676
VERIFY_STDERR(expected_path("check_example_conversation_plugin_user_interrupts.stderr"));
677
VERIFY_CONV(expected_path("check_example_conversation_plugin_user_interrupts.conversation"));
678
return true;
679
}
680
681
static int
682
check_example_policy_plugin_version_display(int is_verbose)
683
{
684
const char *errstr = NULL;
685
686
create_policy_plugin_options();
687
688
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
689
data.user_info, data.user_env, data.plugin_options, &errstr),
690
SUDO_RC_OK);
691
VERIFY_PTR(errstr, NULL);
692
VERIFY_INT(python_policy->show_version(is_verbose), SUDO_RC_OK);
693
694
python_policy->close(0, 0); // this should not call the python plugin close as there was no command run invocation
695
696
if (is_verbose) {
697
// Note: the exact python version is environment dependent
698
VERIFY_STR_CONTAINS(data.stdout_str, "Python interpreter version:");
699
*strstr(data.stdout_str, "Python interpreter version:") = '\0';
700
VERIFY_STDOUT(expected_path("check_example_policy_plugin_version_display_full.stdout"));
701
} else {
702
VERIFY_STDOUT(expected_path("check_example_policy_plugin_version_display.stdout"));
703
}
704
705
VERIFY_STDERR(expected_path("check_example_policy_plugin_version_display.stderr"));
706
707
return true;
708
}
709
710
static int
711
check_example_policy_plugin_accepted_execution(void)
712
{
713
const char *errstr = NULL;
714
715
create_policy_plugin_options();
716
717
str_array_free(&data.plugin_argv);
718
data.plugin_argc = 2;
719
data.plugin_argv = create_str_array(3, "/bin/whoami", "--help", NULL);
720
721
str_array_free(&data.user_env);
722
data.user_env = create_str_array(3, "USER_ENV1=VALUE1", "USER_ENV2=value2", NULL);
723
724
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
725
data.user_info, data.user_env, data.plugin_options, &errstr),
726
SUDO_RC_OK);
727
VERIFY_PTR(errstr, NULL);
728
729
char **env_add = create_str_array(3, "REQUESTED_ENV1=VALUE1", "REQUESTED_ENV2=value2", NULL);
730
731
char **argv_out, **user_env_out, **command_info_out; // free to contain garbage
732
733
VERIFY_INT(python_policy->check_policy(data.plugin_argc, data.plugin_argv, env_add,
734
&command_info_out, &argv_out, &user_env_out, &errstr),
735
SUDO_RC_ACCEPT);
736
VERIFY_PTR(errstr, NULL);
737
738
VERIFY_STR_SET(command_info_out, 4, "command=/bin/whoami", "runas_uid=0", "runas_gid=0", NULL);
739
VERIFY_STR_SET(user_env_out, 5, "USER_ENV1=VALUE1", "USER_ENV2=value2",
740
"REQUESTED_ENV1=VALUE1", "REQUESTED_ENV2=value2", NULL);
741
VERIFY_STR_SET(argv_out, 3, "/bin/whoami", "--help", NULL);
742
743
VERIFY_INT(python_policy->init_session(&example_pwd, &user_env_out, &errstr), SUDO_RC_ACCEPT);
744
VERIFY_PTR(errstr, NULL);
745
746
// init session is able to modify the user env:
747
VERIFY_STR_SET(user_env_out, 6, "USER_ENV1=VALUE1", "USER_ENV2=value2",
748
"REQUESTED_ENV1=VALUE1", "REQUESTED_ENV2=value2", "PLUGIN_EXAMPLE_ENV=1", NULL);
749
750
python_policy->close(3, 0); // successful execution returned exit code 3
751
752
VERIFY_STDOUT(expected_path("check_example_policy_plugin_accepted_execution.stdout"));
753
VERIFY_STDERR(expected_path("check_example_policy_plugin_accepted_execution.stderr"));
754
755
str_array_free(&env_add);
756
str_array_free(&user_env_out);
757
str_array_free(&command_info_out);
758
str_array_free(&argv_out);
759
return true;
760
}
761
762
static int
763
check_example_policy_plugin_failed_execution(void)
764
{
765
const char *errstr = NULL;
766
767
create_policy_plugin_options();
768
769
str_array_free(&data.plugin_argv);
770
data.plugin_argc = 2;
771
data.plugin_argv = create_str_array(3, "/bin/id", "--help", NULL);
772
773
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
774
data.user_info, data.user_env, data.plugin_options, &errstr),
775
SUDO_RC_OK);
776
VERIFY_PTR(errstr, NULL);
777
778
char **argv_out, **user_env_out, **command_info_out; // free to contain garbage
779
780
VERIFY_INT(python_policy->check_policy(data.plugin_argc, data.plugin_argv, NULL,
781
&command_info_out, &argv_out, &user_env_out, &errstr),
782
SUDO_RC_ACCEPT);
783
VERIFY_PTR(errstr, NULL);
784
785
// pwd is unset (user is not part of /etc/passwd)
786
VERIFY_INT(python_policy->init_session(NULL, &user_env_out, &errstr), SUDO_RC_ACCEPT);
787
VERIFY_PTR(errstr, NULL);
788
789
python_policy->close(12345, ENOENT); // failed to execute
790
791
VERIFY_STDOUT(expected_path("check_example_policy_plugin_failed_execution.stdout"));
792
VERIFY_STDERR(expected_path("check_example_policy_plugin_failed_execution.stderr"));
793
794
str_array_free(&user_env_out);
795
str_array_free(&command_info_out);
796
str_array_free(&argv_out);
797
return true;
798
}
799
800
static int
801
check_example_policy_plugin_denied_execution(void)
802
{
803
const char *errstr = NULL;
804
805
create_policy_plugin_options();
806
807
str_array_free(&data.plugin_argv);
808
data.plugin_argc = 1;
809
data.plugin_argv = create_str_array(2, "/bin/passwd", NULL);
810
811
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
812
data.user_info, data.user_env, data.plugin_options, &errstr),
813
SUDO_RC_OK);
814
VERIFY_PTR(errstr, NULL);
815
816
char **argv_out, **user_env_out, **command_info_out; // free to contain garbage
817
818
VERIFY_INT(python_policy->check_policy(data.plugin_argc, data.plugin_argv, NULL,
819
&command_info_out, &argv_out, &user_env_out, &errstr),
820
SUDO_RC_REJECT);
821
VERIFY_PTR(errstr, NULL);
822
823
VERIFY_PTR(command_info_out, NULL);
824
VERIFY_PTR(argv_out, NULL);
825
VERIFY_PTR(user_env_out, NULL);
826
827
python_policy->close(0, 0); // there was no execution
828
829
VERIFY_STDOUT(expected_path("check_example_policy_plugin_denied_execution.stdout"));
830
VERIFY_STDERR(expected_path("check_example_policy_plugin_denied_execution.stderr"));
831
832
return true;
833
}
834
835
static int
836
check_example_policy_plugin_list(void)
837
{
838
const char *errstr = NULL;
839
840
create_policy_plugin_options();
841
842
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
843
data.user_info, data.user_env, data.plugin_options, &errstr),
844
SUDO_RC_OK);
845
VERIFY_PTR(errstr, NULL);
846
847
snprintf_append(data.stdout_str, MAX_OUTPUT, "-- minimal --\n");
848
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, false, NULL, &errstr), SUDO_RC_OK);
849
VERIFY_PTR(errstr, NULL);
850
851
snprintf_append(data.stdout_str, MAX_OUTPUT, "\n-- minimal (verbose) --\n");
852
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, true, NULL, &errstr), SUDO_RC_OK);
853
VERIFY_PTR(errstr, NULL);
854
855
snprintf_append(data.stdout_str, MAX_OUTPUT, "\n-- with user --\n");
856
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, false, "testuser", &errstr), SUDO_RC_OK);
857
VERIFY_PTR(errstr, NULL);
858
859
snprintf_append(data.stdout_str, MAX_OUTPUT, "\n-- with user (verbose) --\n");
860
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, true, "testuser", &errstr), SUDO_RC_OK);
861
VERIFY_PTR(errstr, NULL);
862
863
snprintf_append(data.stdout_str, MAX_OUTPUT, "\n-- with allowed program --\n");
864
str_array_free(&data.plugin_argv);
865
data.plugin_argc = 3;
866
data.plugin_argv = create_str_array(4, "/bin/id", "some", "arguments", NULL);
867
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, false, NULL, &errstr), SUDO_RC_OK);
868
VERIFY_PTR(errstr, NULL);
869
870
snprintf_append(data.stdout_str, MAX_OUTPUT, "\n-- with allowed program (verbose) --\n");
871
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, true, NULL, &errstr), SUDO_RC_OK);
872
VERIFY_PTR(errstr, NULL);
873
874
snprintf_append(data.stdout_str, MAX_OUTPUT, "\n-- with denied program --\n");
875
str_array_free(&data.plugin_argv);
876
data.plugin_argc = 1;
877
data.plugin_argv = create_str_array(2, "/bin/passwd", NULL);
878
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, false, NULL, &errstr), SUDO_RC_OK);
879
VERIFY_PTR(errstr, NULL);
880
881
snprintf_append(data.stdout_str, MAX_OUTPUT, "\n-- with denied program (verbose) --\n");
882
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, true, NULL, &errstr), SUDO_RC_OK);
883
VERIFY_PTR(errstr, NULL);
884
885
python_policy->close(0, 0); // there was no execution
886
887
VERIFY_STDOUT(expected_path("check_example_policy_plugin_list.stdout"));
888
VERIFY_STDERR(expected_path("check_example_policy_plugin_list.stderr"));
889
890
return true;
891
}
892
893
static int
894
check_example_policy_plugin_validate_invalidate(void)
895
{
896
const char *errstr = NULL;
897
898
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
899
// the plugin does not do any meaningful for these, so using log to validate instead
900
const char *config_path = create_debug_config("py_calls@diag");
901
VERIFY_NOT_NULL(config_path);
902
VERIFY_INT(sudo_conf_read(config_path, SUDO_CONF_ALL), true);
903
#endif
904
905
create_policy_plugin_options();
906
907
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
908
data.user_info, data.user_env, data.plugin_options, &errstr),
909
SUDO_RC_OK);
910
VERIFY_PTR(errstr, NULL);
911
912
VERIFY_INT(python_policy->validate(&errstr), SUDO_RC_OK);
913
VERIFY_PTR(errstr, NULL);
914
915
python_policy->invalidate(true);
916
python_policy->invalidate(false);
917
918
python_policy->close(0, 0); // no command execution
919
920
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
921
VERIFY_LOG_LINES(expected_path("check_example_policy_plugin_validate_invalidate.log"));
922
#endif
923
VERIFY_STR(data.stderr_str, "");
924
VERIFY_STR(data.stdout_str, "");
925
return true;
926
}
927
928
static int
929
check_policy_plugin_callbacks_are_optional(void)
930
{
931
const char *errstr = NULL;
932
933
create_debugging_plugin_options();
934
935
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
936
data.user_info, data.user_env, data.plugin_options, &errstr),
937
SUDO_RC_OK);
938
VERIFY_PTR(errstr, NULL);
939
940
VERIFY_PTR(python_policy->list, NULL);
941
VERIFY_PTR(python_policy->validate, NULL);
942
VERIFY_PTR(python_policy->invalidate, NULL);
943
VERIFY_PTR_NE(python_policy->check_policy, NULL); // (not optional)
944
VERIFY_PTR(python_policy->init_session, NULL);
945
946
// show_version always displays the plugin, but it is optional in the python layer
947
VERIFY_PTR_NE(python_policy->show_version, NULL);
948
VERIFY_INT(python_policy->show_version(1), SUDO_RC_OK);
949
950
python_policy->close(0, 0);
951
return true;
952
}
953
954
static int
955
check_policy_plugin_reports_error(void)
956
{
957
const char *errstr = NULL;
958
str_array_free(&data.plugin_options);
959
data.plugin_options = create_str_array(
960
3,
961
"ModulePath=" SRC_DIR "/regress/plugin_errorstr.py",
962
"ClassName=ConstructErrorPlugin",
963
NULL
964
);
965
966
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
967
data.user_info, data.user_env, data.plugin_options, &errstr), SUDO_RC_ERROR);
968
VERIFY_STR(errstr, "Something wrong in plugin constructor");
969
errstr = NULL;
970
971
python_policy->close(0, 0);
972
973
str_array_free(&data.plugin_options);
974
data.plugin_options = create_str_array(
975
3,
976
"ModulePath=" SRC_DIR "/regress/plugin_errorstr.py",
977
"ClassName=ErrorMsgPlugin",
978
NULL
979
);
980
981
data.plugin_argc = 1;
982
str_array_free(&data.plugin_argv);
983
data.plugin_argv = create_str_array(2, "id", NULL);
984
985
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
986
data.user_info, data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
987
VERIFY_PTR(errstr, NULL);
988
989
char **command_info_out = NULL;
990
char **argv_out = NULL;
991
char **user_env_out = NULL;
992
993
VERIFY_INT(python_policy->list(data.plugin_argc, data.plugin_argv, true, NULL, &errstr), SUDO_RC_ERROR);
994
VERIFY_STR(errstr, "Something wrong in list");
995
996
errstr = NULL;
997
VERIFY_INT(python_policy->validate(&errstr), SUDO_RC_ERROR);
998
VERIFY_STR(errstr, "Something wrong in validate");
999
1000
errstr = NULL;
1001
VERIFY_INT(python_policy->check_policy(data.plugin_argc, data.plugin_argv, data.user_env,
1002
&command_info_out, &argv_out, &user_env_out, &errstr),
1003
SUDO_RC_ERROR);
1004
VERIFY_STR(errstr, "Something wrong in check_policy");
1005
1006
errstr = NULL;
1007
VERIFY_INT(python_policy->init_session(&example_pwd, &user_env_out, &errstr), SUDO_RC_ERROR);
1008
VERIFY_STR(errstr, "Something wrong in init_session");
1009
1010
python_policy->close(0, 0);
1011
1012
VERIFY_STR(data.stderr_str, "");
1013
VERIFY_STR(data.stdout_str, "");
1014
return true;
1015
}
1016
1017
static int
1018
check_io_plugin_callbacks_are_optional(void)
1019
{
1020
const char *errstr = NULL;
1021
1022
create_debugging_plugin_options();
1023
1024
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
1025
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
1026
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1027
VERIFY_PTR(errstr, NULL);
1028
1029
VERIFY_PTR(python_io->log_stdin, NULL);
1030
VERIFY_PTR(python_io->log_stdout, NULL);
1031
VERIFY_PTR(python_io->log_stderr, NULL);
1032
VERIFY_PTR(python_io->log_ttyin, NULL);
1033
VERIFY_PTR(python_io->log_ttyout, NULL);
1034
VERIFY_PTR(python_io->change_winsize, NULL);
1035
1036
// show_version always displays the plugin, but it is optional in the python layer
1037
VERIFY_PTR_NE(python_io->show_version, NULL);
1038
VERIFY_INT(python_io->show_version(1), SUDO_RC_OK);
1039
1040
python_io->close(0, 0);
1041
return true;
1042
}
1043
1044
static int
1045
check_python_plugins_do_not_affect_each_other(void)
1046
{
1047
const char *errstr = NULL;
1048
1049
// We test here that one plugin is not able to effect the environment of another
1050
// This is important so they do not ruin or depend on each other's state.
1051
create_plugin_options("regress/plugin_conflict", "ConflictPlugin", "Path=path_for_first_plugin");
1052
1053
VERIFY_INT(python_io->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
1054
data.user_info, data.command_info, data.plugin_argc, data.plugin_argv,
1055
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1056
VERIFY_PTR(errstr, NULL);
1057
1058
create_plugin_options("regress/plugin_conflict", "ConflictPlugin", "Path=path_for_second_plugin");
1059
VERIFY_INT(python_policy->open(SUDO_API_VERSION, fake_conversation, fake_printf, data.settings,
1060
data.user_info, data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1061
VERIFY_PTR(errstr, NULL);
1062
1063
python_io->close(0, 0);
1064
python_policy->close(0, 0);
1065
1066
VERIFY_STDOUT(expected_path("check_python_plugins_do_not_affect_each_other.stdout"));
1067
VERIFY_STR(data.stderr_str, "");
1068
return true;
1069
}
1070
1071
static int
1072
check_example_audit_plugin_receives_accept(void)
1073
{
1074
create_audit_plugin_options("");
1075
const char *errstr = NULL;
1076
1077
str_array_free(&data.plugin_argv);
1078
data.plugin_argv = create_str_array(6, "sudo", "-u", "user", "id", "--help", NULL);
1079
1080
str_array_free(&data.user_env);
1081
data.user_env = create_str_array(3, "KEY1=VALUE1", "KEY2=VALUE2", NULL);
1082
1083
str_array_free(&data.user_info);
1084
data.user_info = create_str_array(3, "user=testuser1", "uid=123", NULL);
1085
1086
VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1087
data.settings, data.user_info, 3, data.plugin_argv,
1088
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1089
VERIFY_PTR(errstr, NULL);
1090
1091
str_array_free(&data.command_info);
1092
data.command_info = create_str_array(2, "command=/sbin/id", NULL);
1093
1094
str_array_free(&data.plugin_argv);
1095
data.plugin_argv = create_str_array(3, "id", "--help", NULL);
1096
1097
VERIFY_INT(python_audit->accept("accepter plugin name", SUDO_POLICY_PLUGIN,
1098
data.command_info, data.plugin_argv,
1099
data.user_env, &errstr), SUDO_RC_OK);
1100
VERIFY_PTR(errstr, NULL);
1101
1102
python_audit->close(SUDO_PLUGIN_WAIT_STATUS, W_EXITCODE(2, 0)); // process exited with 2
1103
1104
VERIFY_STDOUT(expected_path("check_example_audit_plugin_receives_accept.stdout"));
1105
VERIFY_STR(data.stderr_str, "");
1106
1107
return true;
1108
}
1109
1110
static int
1111
check_example_audit_plugin_receives_reject(void)
1112
{
1113
create_audit_plugin_options(NULL);
1114
const char *errstr = NULL;
1115
1116
str_array_free(&data.plugin_argv);
1117
data.plugin_argv = create_str_array(3, "sudo", "passwd", NULL);
1118
1119
str_array_free(&data.user_info);
1120
data.user_info = create_str_array(3, "user=root", "uid=0", NULL);
1121
1122
VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1123
data.settings, data.user_info, 1, data.plugin_argv,
1124
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1125
VERIFY_PTR(errstr, NULL);
1126
1127
VERIFY_INT(python_audit->reject("rejecter plugin name", SUDO_IO_PLUGIN,
1128
"Rejected just because!", data.command_info,
1129
&errstr), SUDO_RC_OK);
1130
VERIFY_PTR(errstr, NULL);
1131
1132
python_audit->close(SUDO_PLUGIN_NO_STATUS, 0); // program was not run
1133
1134
VERIFY_STDOUT(expected_path("check_example_audit_plugin_receives_reject.stdout"));
1135
VERIFY_STR(data.stderr_str, "");
1136
1137
return true;
1138
}
1139
1140
static int
1141
check_example_audit_plugin_receives_error(void)
1142
{
1143
create_audit_plugin_options("");
1144
const char *errstr = NULL;
1145
1146
str_array_free(&data.plugin_argv);
1147
data.plugin_argv = create_str_array(5, "sudo", "-u", "user", "id", NULL);
1148
1149
VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1150
data.settings, data.user_info, 3, data.plugin_argv,
1151
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1152
VERIFY_PTR(errstr, NULL);
1153
1154
str_array_free(&data.command_info);
1155
data.command_info = create_str_array(2, "command=/sbin/id", NULL);
1156
1157
VERIFY_INT(python_audit->error("errorer plugin name", SUDO_AUDIT_PLUGIN,
1158
"Some error has happened", data.command_info,
1159
&errstr), SUDO_RC_OK);
1160
VERIFY_PTR(errstr, NULL);
1161
1162
python_audit->close(SUDO_PLUGIN_SUDO_ERROR, 222);
1163
1164
VERIFY_STDOUT(expected_path("check_example_audit_plugin_receives_error.stdout"));
1165
VERIFY_STR(data.stderr_str, "");
1166
1167
return true;
1168
}
1169
1170
typedef struct audit_plugin * (audit_clone_func)(void);
1171
1172
static int
1173
check_example_audit_plugin_workflow_multiple(void)
1174
{
1175
// verify multiple python audit plugins are available
1176
audit_clone_func *python_audit_clone = (audit_clone_func *)sudo_dso_findsym(
1177
python_plugin_handle, "python_audit_clone");
1178
VERIFY_PTR_NE(python_audit_clone, NULL);
1179
1180
struct audit_plugin *python_audit2 = NULL;
1181
1182
for (int i = 0; i < 7; ++i) {
1183
python_audit2 = (*python_audit_clone)();
1184
VERIFY_PTR_NE(python_audit2, NULL);
1185
VERIFY_PTR_NE(python_audit2, python_audit);
1186
}
1187
1188
const char *errstr = NULL;
1189
1190
str_array_free(&data.plugin_argv);
1191
data.plugin_argv = create_str_array(6, "sudo", "-u", "user", "id", "--help", NULL);
1192
1193
str_array_free(&data.user_env);
1194
data.user_env = create_str_array(3, "KEY1=VALUE1", "KEY2=VALUE2", NULL);
1195
1196
str_array_free(&data.user_info);
1197
data.user_info = create_str_array(3, "user=default", "uid=1000", NULL);
1198
1199
create_audit_plugin_options("Id=1");
1200
VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1201
data.settings, data.user_info, 3, data.plugin_argv,
1202
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1203
VERIFY_PTR(errstr, NULL);
1204
1205
// For verifying the error message of no more plugin. It should be displayed only once.
1206
VERIFY_PTR((*python_audit_clone)(), NULL);
1207
VERIFY_PTR((*python_audit_clone)(), NULL);
1208
1209
create_audit_plugin_options("Id=2");
1210
VERIFY_INT(python_audit2->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1211
data.settings, data.user_info, 3, data.plugin_argv,
1212
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1213
VERIFY_PTR(errstr, NULL);
1214
1215
str_array_free(&data.command_info);
1216
data.command_info = create_str_array(2, "command=/sbin/id", NULL);
1217
1218
str_array_free(&data.plugin_argv);
1219
data.plugin_argv = create_str_array(3, "id", "--help", NULL);
1220
1221
VERIFY_INT(python_audit->accept("accepter plugin name", SUDO_POLICY_PLUGIN,
1222
data.command_info, data.plugin_argv,
1223
data.user_env, &errstr), SUDO_RC_OK);
1224
VERIFY_PTR(errstr, NULL);
1225
1226
VERIFY_INT(python_audit2->accept("accepter plugin name", SUDO_POLICY_PLUGIN,
1227
data.command_info, data.plugin_argv,
1228
data.user_env, &errstr), SUDO_RC_OK);
1229
VERIFY_PTR(errstr, NULL);
1230
1231
python_audit->close(SUDO_PLUGIN_WAIT_STATUS, W_EXITCODE(0, 11)); // process got signal 11
1232
python_audit2->close(SUDO_PLUGIN_WAIT_STATUS, W_EXITCODE(0, 11));
1233
1234
VERIFY_STDOUT(expected_path("check_example_audit_plugin_workflow_multiple.stdout"));
1235
VERIFY_STDERR(expected_path("check_example_audit_plugin_workflow_multiple.stderr"));
1236
1237
return true;
1238
}
1239
1240
static int
1241
check_example_audit_plugin_version_display(void)
1242
{
1243
create_audit_plugin_options(NULL);
1244
const char *errstr = NULL;
1245
1246
str_array_free(&data.user_info);
1247
data.user_info = create_str_array(3, "user=root", "uid=0", NULL);
1248
1249
str_array_free(&data.plugin_argv);
1250
data.plugin_argv = create_str_array(3, "sudo", "-V", NULL);
1251
1252
VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1253
data.settings, data.user_info, 2, data.plugin_argv,
1254
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1255
VERIFY_PTR(errstr, NULL);
1256
1257
VERIFY_INT(python_audit->show_version(false), SUDO_RC_OK);
1258
VERIFY_INT(python_audit->show_version(true), SUDO_RC_OK);
1259
1260
python_audit->close(SUDO_PLUGIN_SUDO_ERROR, 222);
1261
1262
VERIFY_STDOUT(expected_path("check_example_audit_plugin_version_display.stdout"));
1263
VERIFY_STR(data.stderr_str, "");
1264
1265
return true;
1266
}
1267
1268
static int
1269
check_audit_plugin_callbacks_are_optional(void)
1270
{
1271
const char *errstr = NULL;
1272
1273
create_debugging_plugin_options();
1274
1275
VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1276
data.settings, data.user_info, 2, data.plugin_argv,
1277
data.user_env, data.plugin_options, &errstr),
1278
SUDO_RC_OK);
1279
VERIFY_PTR(errstr, NULL);
1280
1281
VERIFY_PTR(python_audit->accept, NULL);
1282
VERIFY_PTR(python_audit->reject, NULL);
1283
VERIFY_PTR(python_audit->error, NULL);
1284
1285
// show_version always displays the plugin, but it is optional in the python layer
1286
VERIFY_PTR_NE(python_audit->show_version, NULL);
1287
VERIFY_INT(python_audit->show_version(1), SUDO_RC_OK);
1288
1289
python_audit->close(SUDO_PLUGIN_NO_STATUS, 0);
1290
return true;
1291
}
1292
1293
static int
1294
check_audit_plugin_reports_error(void)
1295
{
1296
const char *errstr = NULL;
1297
create_plugin_options("regress/plugin_errorstr", "ConstructErrorPlugin", NULL);
1298
1299
VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1300
data.settings, data.user_info, 0, data.plugin_argv,
1301
data.user_env, data.plugin_options, &errstr), SUDO_RC_ERROR);
1302
1303
VERIFY_STR(errstr, "Something wrong in plugin constructor");
1304
errstr = NULL;
1305
1306
python_audit->close(SUDO_PLUGIN_NO_STATUS, 0);
1307
1308
create_plugin_options("regress/plugin_errorstr", "ErrorMsgPlugin", NULL);
1309
1310
VERIFY_INT(python_audit->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1311
data.settings, data.user_info, 0, data.plugin_argv,
1312
data.user_env, data.plugin_options, &errstr), SUDO_RC_ERROR);
1313
VERIFY_STR(errstr, "Something wrong in open");
1314
1315
errstr = NULL;
1316
VERIFY_INT(python_audit->accept("plugin name", SUDO_POLICY_PLUGIN,
1317
data.command_info, data.plugin_argv,
1318
data.user_env, &errstr), SUDO_RC_ERROR);
1319
VERIFY_STR(errstr, "Something wrong in accept");
1320
1321
errstr = NULL;
1322
VERIFY_INT(python_audit->reject("plugin name", SUDO_POLICY_PLUGIN,
1323
"audit message", data.command_info,
1324
&errstr), SUDO_RC_ERROR);
1325
VERIFY_STR(errstr, "Something wrong in reject");
1326
1327
errstr = NULL;
1328
VERIFY_INT(python_audit->error("plugin name", SUDO_POLICY_PLUGIN,
1329
"audit message", data.command_info,
1330
&errstr), SUDO_RC_ERROR);
1331
VERIFY_STR(errstr, "Something wrong in error");
1332
1333
python_audit->close(SUDO_PLUGIN_NO_STATUS, 0);
1334
1335
VERIFY_STR(data.stderr_str, "");
1336
VERIFY_STR(data.stdout_str, "");
1337
return true;
1338
}
1339
1340
static int
1341
check_example_approval_plugin(const char *date_str, const char *expected_error)
1342
{
1343
const char *errstr = NULL;
1344
1345
create_plugin_options("example_approval_plugin", "BusinessHoursApprovalPlugin", NULL);
1346
1347
VERIFY_INT(python_approval->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1348
data.settings, data.user_info, 0, data.plugin_argv,
1349
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1350
1351
VERIFY_TRUE(mock_python_datetime_now("example_approval_plugin", date_str));
1352
1353
int expected_rc = (expected_error == NULL) ? SUDO_RC_ACCEPT : SUDO_RC_REJECT;
1354
1355
VERIFY_INT(python_approval->check(data.command_info, data.plugin_argv, data.user_env, &errstr),
1356
expected_rc);
1357
1358
if (expected_error == NULL) {
1359
VERIFY_PTR(errstr, NULL);
1360
VERIFY_STR(data.stdout_str, "");
1361
} else {
1362
VERIFY_STR(errstr, expected_error);
1363
VERIFY_STR_CONTAINS(data.stdout_str, expected_error); // (ends with \n)
1364
}
1365
VERIFY_STR(data.stderr_str, "");
1366
1367
python_approval->close();
1368
1369
return true;
1370
}
1371
1372
typedef struct approval_plugin * (approval_clone_func)(void);
1373
1374
static int
1375
check_multiple_approval_plugin_and_arguments(void)
1376
{
1377
// verify multiple python approval plugins are available
1378
approval_clone_func *python_approval_clone = (approval_clone_func *)sudo_dso_findsym(
1379
python_plugin_handle, "python_approval_clone");
1380
VERIFY_PTR_NE(python_approval_clone, NULL);
1381
1382
struct approval_plugin *python_approval2 = NULL;
1383
1384
for (int i = 0; i < 7; ++i) {
1385
python_approval2 = (*python_approval_clone)();
1386
VERIFY_PTR_NE(python_approval2, NULL);
1387
VERIFY_PTR_NE(python_approval2, python_approval);
1388
}
1389
1390
const char *errstr = NULL;
1391
create_plugin_options("regress/plugin_approval_test", "ApprovalTestPlugin", "Id=1");
1392
1393
str_array_free(&data.plugin_argv);
1394
data.plugin_argv = create_str_array(6, "sudo", "-u", "user", "whoami", "--help", NULL);
1395
1396
str_array_free(&data.user_env);
1397
data.user_env = create_str_array(3, "USER_ENV1=VALUE1", "USER_ENV2=value2", NULL);
1398
1399
str_array_free(&data.user_info);
1400
data.user_info = create_str_array(3, "INFO1=VALUE1", "info2=value2", NULL);
1401
1402
str_array_free(&data.settings);
1403
data.settings = create_str_array(3, "SETTING1=VALUE1", "setting2=value2", NULL);
1404
1405
VERIFY_INT(python_approval->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1406
data.settings, data.user_info, 3, data.plugin_argv,
1407
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1408
VERIFY_PTR(errstr, NULL);
1409
1410
// For verifying the error message of no more plugin. It should be displayed only once.
1411
VERIFY_PTR((*python_approval_clone)(), NULL);
1412
VERIFY_PTR((*python_approval_clone)(), NULL);
1413
1414
create_plugin_options("regress/plugin_approval_test", "ApprovalTestPlugin", "Id=2");
1415
VERIFY_INT(python_approval2->open(SUDO_API_VERSION, fake_conversation, fake_printf,
1416
data.settings, data.user_info, 3, data.plugin_argv,
1417
data.user_env, data.plugin_options, &errstr), SUDO_RC_OK);
1418
VERIFY_PTR(errstr, NULL);
1419
1420
VERIFY_INT(python_approval->show_version(false), SUDO_RC_OK);
1421
VERIFY_INT(python_approval2->show_version(true), SUDO_RC_OK);
1422
1423
str_array_free(&data.command_info);
1424
data.command_info = create_str_array(3, "CMDINFO1=value1", "CMDINFO2=VALUE2", NULL);
1425
1426
str_array_free(&data.plugin_argv);
1427
data.plugin_argv = create_str_array(3, "whoami", "--help", NULL);
1428
1429
VERIFY_INT(python_approval->check(data.command_info, data.plugin_argv, data.user_env, &errstr),
1430
SUDO_RC_OK);
1431
VERIFY_PTR(errstr, NULL);
1432
1433
VERIFY_INT(python_approval2->check(data.command_info, data.plugin_argv, data.user_env, &errstr),
1434
SUDO_RC_OK);
1435
VERIFY_PTR(errstr, NULL);
1436
1437
python_approval->close();
1438
python_approval2->close();
1439
1440
VERIFY_STDOUT(expected_path("check_multiple_approval_plugin_and_arguments.stdout"));
1441
VERIFY_STDERR(expected_path("check_multiple_approval_plugin_and_arguments.stderr"));
1442
1443
return true;
1444
}
1445
1446
1447
static int
1448
_init_symbols(void)
1449
{
1450
if (python_plugin_handle != NULL) {
1451
// symbols are already loaded, we just restore
1452
RESTORE_PYTHON_PLUGIN(python_io);
1453
RESTORE_PYTHON_PLUGIN(python_policy);
1454
RESTORE_PYTHON_PLUGIN(python_approval);
1455
RESTORE_PYTHON_PLUGIN(python_audit);
1456
RESTORE_PYTHON_PLUGIN(group_plugin);
1457
return true;
1458
}
1459
1460
// we load the symbols
1461
python_plugin_handle = sudo_dso_load(python_plugin_so_path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL);
1462
VERIFY_PTR_NE(python_plugin_handle, NULL);
1463
1464
python_io = sudo_dso_findsym(python_plugin_handle, "python_io");
1465
VERIFY_PTR_NE(python_io, NULL);
1466
1467
group_plugin = sudo_dso_findsym(python_plugin_handle, "group_plugin");
1468
VERIFY_PTR_NE(group_plugin, NULL);
1469
1470
python_policy = sudo_dso_findsym(python_plugin_handle, "python_policy");
1471
VERIFY_PTR_NE(python_policy, NULL);
1472
1473
python_audit = sudo_dso_findsym(python_plugin_handle, "python_audit");
1474
VERIFY_PTR_NE(python_audit, NULL);
1475
1476
python_approval = sudo_dso_findsym(python_plugin_handle, "python_approval");
1477
VERIFY_PTR_NE(python_approval, NULL);
1478
1479
SAVE_PYTHON_PLUGIN(python_io);
1480
SAVE_PYTHON_PLUGIN(python_policy);
1481
SAVE_PYTHON_PLUGIN(python_approval);
1482
SAVE_PYTHON_PLUGIN(python_audit);
1483
SAVE_PYTHON_PLUGIN(group_plugin);
1484
1485
return true;
1486
}
1487
1488
static int
1489
_unlink_symbols(void)
1490
{
1491
python_io = NULL;
1492
group_plugin = NULL;
1493
python_policy = NULL;
1494
python_approval = NULL;
1495
python_audit = NULL;
1496
VERIFY_INT(sudo_dso_unload(python_plugin_handle), 0);
1497
python_plugin_handle = NULL;
1498
VERIFY_FALSE(Py_IsInitialized());
1499
return true;
1500
}
1501
1502
int
1503
main(int argc, char *argv[])
1504
{
1505
int ch, errors = 0, ntests = 0;
1506
1507
while ((ch = getopt(argc, argv, "v")) != -1) {
1508
switch (ch) {
1509
case 'v':
1510
verbose = true;
1511
break;
1512
default:
1513
fprintf(stderr, "usage: %s [-v]\n", getprogname());
1514
return EXIT_FAILURE;
1515
}
1516
}
1517
argc -= optind;
1518
argv += optind;
1519
1520
if (argc != 1) {
1521
printf("Please specify the python_plugin.so as argument!\n");
1522
return EXIT_FAILURE;
1523
}
1524
python_plugin_so_path = argv[0];
1525
1526
// Unbuffer stdout so we don't miss output during a crash.
1527
setvbuf(stdout, NULL, _IONBF, 0);
1528
1529
RUN_TEST(check_example_io_plugin_version_display(true));
1530
RUN_TEST(check_example_io_plugin_version_display(false));
1531
RUN_TEST(check_example_io_plugin_command_log());
1532
RUN_TEST(check_example_io_plugin_command_log_multiple());
1533
RUN_TEST(check_example_io_plugin_failed_to_start_command());
1534
RUN_TEST(check_example_io_plugin_fails_with_python_backtrace());
1535
RUN_TEST(check_io_plugin_callbacks_are_optional());
1536
RUN_TEST(check_io_plugin_reports_error());
1537
RUN_TEST(check_plugin_unload());
1538
1539
RUN_TEST(check_example_group_plugin());
1540
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1541
RUN_TEST(check_example_group_plugin_is_able_to_debug());
1542
#endif
1543
RUN_TEST(check_plugin_unload());
1544
1545
RUN_TEST(check_loading_fails_with_missing_path());
1546
RUN_TEST(check_loading_succeeds_with_missing_classname());
1547
RUN_TEST(check_loading_fails_with_missing_classname());
1548
RUN_TEST(check_loading_fails_with_wrong_classname());
1549
RUN_TEST(check_loading_fails_with_wrong_path());
1550
RUN_TEST(check_plugin_unload());
1551
1552
RUN_TEST(check_example_conversation_plugin_reason_log(false, "without_suspend"));
1553
RUN_TEST(check_example_conversation_plugin_reason_log(true, "with_suspend"));
1554
RUN_TEST(check_example_conversation_plugin_user_interrupts());
1555
RUN_TEST(check_plugin_unload());
1556
1557
RUN_TEST(check_example_policy_plugin_version_display(true));
1558
RUN_TEST(check_example_policy_plugin_version_display(false));
1559
RUN_TEST(check_example_policy_plugin_accepted_execution());
1560
RUN_TEST(check_example_policy_plugin_failed_execution());
1561
RUN_TEST(check_example_policy_plugin_denied_execution());
1562
RUN_TEST(check_example_policy_plugin_list());
1563
RUN_TEST(check_example_policy_plugin_validate_invalidate());
1564
RUN_TEST(check_policy_plugin_callbacks_are_optional());
1565
RUN_TEST(check_policy_plugin_reports_error());
1566
RUN_TEST(check_plugin_unload());
1567
1568
RUN_TEST(check_example_audit_plugin_receives_accept());
1569
RUN_TEST(check_example_audit_plugin_receives_reject());
1570
RUN_TEST(check_example_audit_plugin_receives_error());
1571
RUN_TEST(check_example_audit_plugin_workflow_multiple());
1572
RUN_TEST(check_example_audit_plugin_version_display());
1573
RUN_TEST(check_audit_plugin_callbacks_are_optional());
1574
RUN_TEST(check_audit_plugin_reports_error());
1575
RUN_TEST(check_plugin_unload());
1576
1577
// Monday, too early
1578
RUN_TEST(check_example_approval_plugin(
1579
"2020-02-10T07:55:23", "That is not allowed outside the business hours!"));
1580
// Monday, good time
1581
RUN_TEST(check_example_approval_plugin("2020-02-10T08:05:23", NULL));
1582
// Friday, good time
1583
RUN_TEST(check_example_approval_plugin("2020-02-14T17:59:23", NULL));
1584
// Friday, too late
1585
RUN_TEST(check_example_approval_plugin(
1586
"2020-02-10T18:05:23", "That is not allowed outside the business hours!"));
1587
// Saturday
1588
RUN_TEST(check_example_approval_plugin(
1589
"2020-02-15T08:05:23", "That is not allowed on the weekend!"));
1590
RUN_TEST(check_multiple_approval_plugin_and_arguments());
1591
1592
RUN_TEST(check_python_plugins_do_not_affect_each_other());
1593
RUN_TEST(check_plugin_unload());
1594
1595
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1596
RUN_TEST(check_example_debugging("plugin@err"));
1597
RUN_TEST(check_example_debugging("plugin@info"));
1598
RUN_TEST(check_example_debugging("load@diag"));
1599
RUN_TEST(check_example_debugging("sudo_cb@info"));
1600
RUN_TEST(check_example_debugging("c_calls@diag"));
1601
RUN_TEST(check_example_debugging("c_calls@info"));
1602
RUN_TEST(check_example_debugging("py_calls@diag"));
1603
RUN_TEST(check_example_debugging("py_calls@info"));
1604
RUN_TEST(check_example_debugging("plugin@err"));
1605
RUN_TEST(check_plugin_unload());
1606
#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */
1607
1608
if (ntests != 0) {
1609
printf("%s: %d tests run, %d errors, %d%% success rate\n",
1610
getprogname(), ntests, errors, (ntests - errors) * 100 / ntests);
1611
}
1612
1613
return errors;
1614
}
1615
1616