1SUDO_PLUGIN_PYTHON(5) BSD File Formats Manual SUDO_PLUGIN_PYTHON(5)
2
4 sudo_plugin_python — Sudo Plugin API (Python)
5
7 Starting with version 1.9, sudo plugins can be written in python. The
8 API closely follows the C sudo plugin API described by sudo_plugin(5).
9
10 The supported plugins types are:
11
12 • Policy plugin
13 • I/O plugin
14 • Audit plugin
15 • Approval plugin
16 • Group provider plugin
17
18 Python plugin support needs to be explicitly enabled at build time with
19 the configure option “--enable-python”. Python version 3.0 or higher is
20 required.
21
22 Sudo Python Plugin Base
23 A plugin written in Python should be a class in a python file that inher‐
24 its from sudo.Plugin. The sudo.Plugin base class has no real purpose
25 other than to identify this class as a plugin.
26
27 The only implemented method is a constructor, which stores the keyword
28 arguments it receives as fields (member variables) in the object. This
29 is intended as a convenience to allow you to avoid writing the construc‐
30 tor yourself.
31
32 For example:
33
34 import sudo
35
36 class MySudoPlugin(sudo.Plugin):
37 # example constructor (optional)
38 def __init__(self, *args, **kwargs):
39 super().__init__(*args, **kwargs)
40
41 # example destructor (optional)
42 def __del__(self):
43 pass
44
45 Both the constructor and destructor are optional and can be omitted.
46
47 The customized Plugin class should define a few plugin-specific methods.
48 When the plugin loads, sudo will create an instance of this class and
49 call the methods. The actual methods required depent on the type of the
50 plugin, but most return an “int” result code, as documented in
51 sudo_plugin(@mansctsu@), that indicates whether or not the method was
52 successful. The Python sudo module defines the following constants to
53 improve readability:
54
55 Define Value
56 sudo.RC.OK 1
57 sudo.RC.ACCEPT 1
58 sudo.RC.REJECT 0
59 sudo.RC.ERROR -1
60 sudo.RC.USAGE_ERROR -2
61
62 If a function returns None (for example, if it does not call return), it
63 will be considered to have returned sudo.RC.OK. If an exception is
64 raised (other than sudo.PluginException), the backtrace will be shown to
65 the user and the plugin function will return sudo.RC.ERROR. If that is
66 not acceptable, you must catch the exception and handle it yourself.
67
68 Instead of just returning sudo.RC.ERROR or sudo.RC.REJECT result code the
69 plugin can also provide a message describing the problem. This can be
70 done by raising one of the special exceptions:
71
72 raise sudo.PluginError("Message")
73 raise sudo.PluginReject("Message")
74
75 This added message will be used by the audit plugins. Both exceptions
76 inherit from sudo.PluginException
77
78 Python Plugin Loader
79 Running the Python interpreter and bridging between C and Python is han‐
80 dled by the sudo plugin python_plugin.so. This shared object can be
81 loaded like any other dynamic sudo plugin and should receive the path and
82 the class name of the Python plugin it is loading as arguments.
83
84 Example usage in sudo.conf(5):
85
86 Plugin python_policy python_plugin.so ModulePath=<path> ClassName=<class>
87 Plugin python_io python_plugin.so ModulePath=<path> ClassName=<class>
88 Plugin python_audit python_plugin.so ModulePath=<path> ClassName=<class>
89 Plugin python_approval python_plugin.so ModulePath=<path> ClassName=<class>
90
91 Example group provider plugin usage in the sudoers file:
92
93 Defaults group_plugin="python_plugin.so ModulePath=<path> ClassName=<class>"
94
95 The plugin arguments are as follows:
96
97 ModulePath
98 The path of a python file which contains the class of the sudo
99 Python plugin. It must be either an absolute path or a path rela‐
100 tive to the sudo Python plugin directory:
101 "/usr/libexec/sudo/python".
102
103 ClassName
104 (Optional.) The name of the class implementing the sudo Python
105 plugin. If not supplied, the one and only sudo.Plugin that is
106 present in the module will be used. If there are multiple such
107 plugins in the module (or none), it will result in an error.
108
109 Policy plugin API
110 Policy plugins must be registered in sudo.conf(5). For example:
111
112 Plugin python_policy python_plugin.so ModulePath=<path> ClassName=<class>
113
114 Currently, only a single policy plugin may be specified in sudo.conf(5).
115
116 A policy plugin may have the following member functions:
117
118 constructor
119
120 __init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
121 version: str, user_info: Tuple[str, ...],
122 plugin_options: Tuple[str, ...])
123
124 Implementing this function is optional. The default constructor
125 will set the keyword arguments it receives as member variables in
126 the object.
127
128 The constructor matches the open() function in the C sudo plugin
129 API.
130
131 The function arguments are as follows:
132
133 user_env
134 The user's environment as a tuple of strings in “key=value”
135 format.
136
137 settings
138 A tuple of user-supplied sudo settings in the form of
139 “key=value” strings.
140
141 version
142 The version of the Python Policy Plugin API.
143
144 user_info
145 A tuple of information about the user running the command in
146 the form of “key=value” strings.
147
148 plugin_options
149 The plugin options passed as arguments in the sudo.conf(5)
150 plugin registration. This is a tuple of strings, usually
151 (but not necessarily) in “key=value” format.
152
153 The sudo.options_as_dict() convenience function can be used to con‐
154 vert “key=value” pairs to a dictionary. For a list of recognized
155 keys and their supported values, see the policy plugin open() docu‐
156 mentation in sudo_plugin(5).
157
158 check_policy
159 check_policy(self, argv: Tuple[str, ...], env_add: Tuple[str, ...])
160
161 The check_policy() function is called by sudo to determine whether
162 the user is allowed to run the specified command. Implementing
163 this function is mandatory for a policy plugin.
164
165 The function arguments are as follows:
166
167 argv A tuple describing the command the user wishes to run.
168
169 env_add
170 Additional environment variables specified by the user on the
171 command line in the form of a tuple of “key=value” pairs.
172 The sudo.options_as_dict() convenience function can be used
173 to convert them to a dictionary.
174
175 This function should return a result code or a tuple in the follow‐
176 ing format:
177
178 return (rc, command_info_out, argv_out, user_env_out)
179
180 The tuple values are as follows:
181
182 rc The result of the policy check, one of the sudo.RC.* con‐
183 stants. sudo.RC.ACCEPT if the command is allowed,
184 sudo.RC.REJECT if not allowed, sudo.RC.ERROR for a general
185 error, or sudo.RC.USAGE_ERROR for a usage error.
186
187 command_info_out
188 Optional (only required when the command is accepted). In‐
189 formation about the command being run in the form of
190 “key=value” strings.
191
192 To accept a command, at the very minimum the plugin must set
193 in the command, runas_uid and runas_gid keys.
194
195 For a list of recognized keys and supported values, see the
196 check_policy() documentation in sudo_plugin(5).
197
198 argv_out
199 Optional (only required when the command is accepted). The
200 arguments to pass to the execve(2) system call when executing
201 the command.
202
203 user_env_out
204 Optional (only required when the command is accepted). The
205 environment to use when executing the command in the form of
206 a tuple of strings in “key=value” format.
207
208 init_session
209 init_session(self, user_pwd: Tuple, user_env: Tuple[str, ...])
210
211 Perform session setup (optional). The init_session() function is
212 called before sudo sets up the execution environment for the com‐
213 mand before any uid or gid changes.
214
215 The function arguments are as follows:
216
217 user_pwd
218 A tuple describing the user's passwd entry. Convertible to
219 pwd.struct_passwd or None if the user is not present in the
220 password database.
221
222 Example conversion:
223 user_pwd = pwd.struct_passwd(user_pwd) if user_pwd else None
224
225 user_env
226 The environment the command will run in. This is a tuple of
227 strings in “key=value” format.
228
229 This function should return a result code or a tuple in the follow‐
230 ing format:
231
232 return (rc, user_env_out)
233
234 The tuple values are as follows:
235
236 rc The result of the session init, one of the sudo.RC.* con‐
237 stants. sudo.RC.OK on success, 0 on failure, or
238 sudo.RC.ERROR if an error occurred.
239
240 user_env_out
241 Optional. If the init_session() function needs to modify the
242 user environment, it can return the new environment in
243 user_env_out. If this is omitted, no changes will be made to
244 user_env.
245
246 list
247 list(self, argv: Tuple[str, ...], is_verbose: int, user: str)
248
249 List available privileges for the invoking user.
250
251 The function arguments are as follows:
252
253 argv If not set to None, an argument vector describing a command
254 the user wishes to check against the policy.
255
256 is_verbose
257 Flag indicating whether to list in verbose mode or not.
258
259 user The name of a different user to list privileges for if the
260 policy allows it. If None, the plugin should list the privi‐
261 leges of the invoking user.
262
263 validate
264 validate(self)
265
266 For policy plugins that cache authentication credentials, this
267 function is used to validate and cache the credentials (optional).
268
269 invalidate
270 invalidate(self, remove: int)
271
272 For policy plugins that cache authentication credentials, this
273 function is used to invalidate the credentials (optional).
274
275 The function arguments are as follows:
276
277 remove
278 If this flag is set, the plugin may remove the credentials
279 instead of simply invalidating them.
280
281 show_version
282 show_version(self, is_verbose: int)
283
284 Display the plugin version information to the user. The
285 sudo.log_info() function should be used.
286
287 The function arguments are as follows:
288
289 is_verbose
290 A flag to indicate displaying more verbose information. Cur‐
291 rently this is 1 if ‘sudo -V’ is run as the root user.
292
293 close
294 close(self, exit_status: int, error: int)
295
296 Called when a command finishes executing.
297
298 Works the same as the close() function in the C sudo plugin API,
299 except that it only gets called if sudo attempts to execute the
300 command.
301
302 The function arguments are as follows:
303
304 exit_status
305 The exit status of the command if was executed, otherwise -1.
306
307 error
308 If the command could not be executed, this is set to the
309 value of errno set by the execve(2) system call, otherwise 0.
310
311 Policy plugin example
312 Sudo ships with an example Python policy plugin. To try it, register it
313 by adding the following lines to /etc/sudo.conf:
314
315 Plugin python_policy python_plugin.so \
316 ModulePath=/usr/share/doc/sudo/examples/example_policy_plugin.py \
317 ClassName=SudoPolicyPlugin
318
319 Be aware, however, that you cannot enable the Python policy plugin in ad‐
320 dition to another policy plugin, such as sudoers(5).
321
322 I/O plugin API
323 I/O plugins must be registered in sudo.conf(5). For example:
324
325 Plugin python_io python_plugin.so ModulePath=<path> ClassName=<class>
326
327 Sudo supports loading multiple I/O plugins. Currently only 8 python I/O
328 plugins can be loaded at once.
329
330 An I/O plugin may have the following member functions:
331
332 constructor
333 __init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
334 version: str, user_info: Tuple[str, ...],
335 plugin_options: Tuple[str, ...])
336
337 Implementing this function is optional. The default constructor
338 will set the keyword arguments it receives as member variables in
339 the object.
340
341 The constructor matches the open() function in the C sudo plugin
342 API.
343
344 The function arguments are as follows:
345
346 user_env
347 The user's environment as a tuple of strings in “key=value”
348 format.
349
350 settings
351 A tuple of user-supplied sudo settings in the form of
352 “key=value” strings.
353
354 version
355 The version of the Python I/O Plugin API.
356
357 user_info
358 A tuple of information about the user running the command in
359 the form of “key=value” strings.
360
361 plugin_options
362 The plugin options passed as arguments in the sudo.conf(5)
363 plugin registration. This is a tuple of strings, usually
364 (but not necessarily) in “key=value” format.
365
366 The sudo.options_as_dict() convenience function can be used to con‐
367 vert “key=value” pairs to a dictionary. For a list of recognized
368 keys and their supported values, see the I/O plugin open() documen‐
369 tation in sudo_plugin(5).
370
371 open
372 open(self, argv: Tuple[str, ...],
373 command_info: Tuple[str, ...]) -> int
374
375 Receives the command the user wishes to run.
376
377 Works the same as the open() function in the C sudo plugin API ex‐
378 cept that:
379
380 • It only gets called before the user would execute some com‐
381 mand (and not for a version query for example).
382 • Other arguments of the C API open() function are received
383 through the constructor.
384
385 The function arguments are as follows:
386
387 argv A tuple of the arguments describing the command the user
388 wishes to run.
389
390 command_info
391 Information about the command being run in the form of
392 “key=value” strings.
393
394 The sudo.options_as_dict() convenience function can be used to con‐
395 vert “key=value” pairs to a dictionary. For a list of recognized
396 keys and their supported values, see the I/O plugin open() documen‐
397 tation in sudo_plugin(5).
398
399 The open() function should return a result code, one of the
400 sudo.RC.* constants. If the function returns sudo.RC.REJECT, no
401 I/O will be sent to the plugin.
402
403 log_ttyin, log_ttyout, log_stdin, log_stdout, log_stderr
404 log_ttyin(self, buf: str) -> int
405 log_ttyout(self, buf: str) -> int
406 log_stdin(self, buf: str) -> int
407 log_stdout(self, buf: str) -> int
408 log_stderr(self, buf: str) -> int
409
410 Receive the user input or output of the terminal device and appli‐
411 cation standard input / output / error. See the matching calls in
412 sudo_plugin(5).
413
414 The function arguments are as follows:
415
416 buf The input (or output) buffer in the form of a string.
417
418 The function should return a result code, one of the sudo.RC.* con‐
419 stants.
420
421 If sudo.RC.ERROR is returned, the running command will be termi‐
422 nated and all of the plugin's logging functions will be disabled.
423 Other I/O logging plugins will still receive any remaining input or
424 output that has not yet been processed.
425
426 If an input logging function rejects the data by returning
427 sudo.RC.REJECT, the command will be terminated and the data will
428 not be passed to the command, though it will still be sent to any
429 other I/O logging plugins. If an output logging function rejects
430 the data by returning sudo.RC.REJECT, the command will be termi‐
431 nated and the data will not be written to the terminal, though it
432 will still be sent to any other I/O logging plugins.
433
434 change_winsize
435 change_winsize(self, line: int, cols: int) -> int
436
437 Called whenever the window size of the terminal changes. The func‐
438 tion arguments are as follows:
439
440 line The number of lines of the terminal.
441
442 cols The number of columns of the terminal.
443
444 log_suspend
445 log_suspend(self, signo: int) -> int
446 Called whenever a command is suspended or resumed.
447
448 The function arguments are as follows:
449
450 signo
451 The number of the signal that caused the command to be sus‐
452 pended or SIGCONT if the command was resumed.
453
454 show_version
455 show_version(self, is_verbose: int)
456 Display the plugin version information to the user. The
457 sudo.log_info() function should be used.
458
459 The function arguments are as follows:
460
461 is_verbose
462 A flag to indicate displaying more verbose information. Cur‐
463 rently this is 1 if ‘sudo -V’ is run as the root user.
464
465 close
466 close(self, exit_status: int, error: int) -> None
467 Called when a command execution finished.
468
469 Works the same as the close() function in the C sudo plugin API,
470 except that it only gets called if sudo attempts to execute the
471 command.
472
473 The function arguments are as follows:
474
475 exit_status
476 The exit status of the command if was executed, otherwise -1.
477
478 error
479 If the command could not be executed, this is set to the
480 value of errno set by the execve(2) system call, otherwise 0.
481
482 I/O plugin example
483 Sudo ships a Python I/O plugin example. To try it, register it by adding
484 the following lines to /etc/sudo.conf:
485
486 Plugin python_io python_plugin.so \
487 ModulePath=/usr/share/doc/sudo/examples/example_io_plugin.py \
488 ClassName=SudoIOPlugin
489
490 Audit plugin API
491 Audit plugins must be registered in sudo.conf(5). For example:
492
493 Plugin python_audit python_plugin.so ModulePath=<path> ClassName=<class>
494
495 Sudo supports loading multiple audit plugins. Currently only 8 python
496 audit plugins can be loaded at once.
497
498 An audit plugin may have the following member functions (all of them are
499 optional):
500
501 constructor
502 __init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
503 version: str, user_info: Tuple[str, ...], plugin_options: Tuple[str, ...])
504
505 The default constructor will set the keyword arguments it receives
506 as member variables in the object.
507
508 The constructor matches the open() function in the C sudo plugin
509 API.
510
511 The function arguments are as follows:
512
513 user_env
514 The user's environment as a tuple of strings in “key=value”
515 format.
516
517 settings
518 A tuple of user-supplied sudo settings in the form of
519 “key=value” strings.
520
521 version
522 The version of the Python Audit Plugin API.
523
524 user_info
525 A tuple of information about the user running the command in
526 the form of “key=value” strings.
527
528 plugin_options
529 The plugin options passed as arguments in the sudo.conf(5)
530 plugin registration. This is a tuple of strings, usually
531 (but not necessarily) in “key=value” format.
532
533 open
534 open(self, submit_optind: int,
535 submit_argv: Tuple[str, ...]) -> int
536
537 The function arguments are as follows:
538
539 submit_optind
540 The index into submit_argv that corresponds to the first en‐
541 try that is not a command line option.
542
543 submit_argv
544 The argument vector sudo was invoked with, including all com‐
545 mand line options.
546
547 close
548 close(self, status_type: int, status: int) -> None
549
550 Called when sudo is finished, shortly before it exits.
551
552 The function arguments are as follows:
553
554 status_type
555 The type of status being passed. One of the sudo.EXIT_REA‐
556 SON.* constants.
557
558 status
559 Depending on the value of status_type, this value is either
560 ignored, the command's exit status as returned by the wait(2)
561 system call, the value of errno set by the execve(2) system
562 call, or the value of errno resulting from an error in the
563 sudo front end.
564
565 show_version
566 show_version(self, is_verbose: int) -> int
567
568 Display the plugin version information to the user. The
569 sudo.log_info() function should be used.
570
571 The function arguments are as follows:
572
573 is_verbose
574 A flag to indicate displaying more verbose information. Cur‐
575 rently this is 1 if ‘sudo -V’ is run as the root user.
576
577 accept
578 accept(self, plugin_name: str, plugin_type: int, command_info: Tuple[str, ...],
579 run_argv: Tuple[str, ...], run_envp: Tuple[str, ...]) -> int
580
581 This function is called when a command or action is accepted by a
582 policy or approval plugin. The function arguments are as follows:
583
584 plugin_name
585 The name of the plugin that accepted the command or “sudo”
586 for the sudo front-end.
587
588 plugin_type
589 The type of plugin that accepted the command, currently ei‐
590 ther sudo.PLUGIN_TYPE.POLICY, sudo.PLUGIN_TYPE.APPROVAL or
591 sudo.PLUGIN_TYPE.SUDO. The accept() function is called mul‐
592 tiple times--once for each policy or approval plugin that
593 succeeds and once for the sudo front-end. When called on be‐
594 half of the sudo front-end, command_info may include informa‐
595 tion from an I/O logging plugin as well.
596
597 Typically, an audit plugin is interested in either the accept
598 status from the sudo front-end or from the various policy and
599 approval plugins, but not both. It is possible for the pol‐
600 icy plugin to accept a command that is later rejected by an
601 approval plugin, in which case the audit plugin's accept()
602 and reject() functions will both be called.
603
604 command_info
605 A vector of information describing the command being run.
606 See the sudo_plugin(5) manual for possible values.
607
608 run_argv
609 Argument vector describing a command that will be run.
610
611 run_envp
612 The environment the command will be run with.
613
614 reject
615 reject(self, plugin_name: str, plugin_type: int, audit_msg: str,
616 command_info: Tuple[str, ...]) -> int
617
618 This function is called when a command or action is rejected by the
619 policy plugin. The function arguments are as follows:
620
621 plugin_name
622 The name of the plugin that rejected the command.
623
624 plugin_type
625 The type of plugin that rejected the command, currently ei‐
626 ther sudo.PLUGIN_TYPE.POLICY, sudo.PLUGIN_TYPE.APPROVAL or
627 sudo.PLUGIN_TYPE.IO.
628
629 Unlike the accept() function, the reject() function is not
630 called on behalf of the sudo front-end.
631
632 audit_msg
633 An optional string describing the reason the command was re‐
634 jected by the plugin. If the plugin did not provide a rea‐
635 son, audit_msg will be None
636
637 command_info
638 A vector of information describing the rejected command. See
639 the sudo_plugin(5) manual for possible values.
640
641 error
642 error(self, plugin_name: str, plugin_type: int, audit_msg: str,
643 command_info: Tuple[str, ...]) -> int
644
645 This function is called when a plugin or the sudo front-end returns
646 an error. The function arguments are as follows:
647
648 plugin_name
649 The name of the plugin that generated the error or “sudo” for
650 the sudo front-end.
651
652 plugin_type
653 The type of plugin that generated the error, or
654 SUDO_FRONT_END for the sudo front-end.
655
656 audit_msg
657 An optional string describing the plugin error. If the
658 plugin did not provide a description, it will be None
659
660 command_info
661 A vector of information describing the command. See the
662 sudo_plugin(5) manual for possible values.
663
664 Audit plugin example
665 Sudo ships a Python Audit plugin example. To try it, register it by
666 adding the following lines to /etc/sudo.conf:
667
668 Plugin python_audit python_plugin.so \
669 ModulePath=/usr/share/doc/sudo/examples/example_audit_plugin.py \
670 ClassName=SudoAuditPlugin
671
672 It will log the plugin accept / reject / error results to the output.
673
674 Approval plugin API
675 Approval plugins must be registered in sudo.conf(5). For example:
676
677 Plugin python_approval python_plugin.so ModulePath=<path> ClassName=<class>
678
679 Sudo supports loading multiple approval plugins. Currently only 8 python
680 approval plugins can be loaded at once.
681
682 An approval plugin may have the following member functions:
683
684 constructor
685 __init__(self, user_env: Tuple[str, ...], settings: Tuple[str, ...],
686 version: str, user_info: Tuple[str, ...], plugin_options: Tuple[str, ...],
687 submit_optind: int, submit_argv: Tuple[str, ...])
688
689 Optional. The default constructor will set the keyword arguments
690 it receives as member variables in the object.
691
692 The constructor matches the open() function in the C sudo plugin
693 API.
694
695 The function arguments are as follows:
696
697 user_env
698 The user's environment as a tuple of strings in “key=value”
699 format.
700
701 settings
702 A tuple of user-supplied sudo settings in the form of
703 “key=value” strings.
704
705 version
706 The version of the Python Approval Plugin API.
707
708 user_info
709 A tuple of information about the user running the command in
710 the form of “key=value” strings.
711
712 plugin_options
713 The plugin options passed as arguments in the sudo.conf(5)
714 plugin registration. This is a tuple of strings, usually
715 (but not necessarily) in “key=value” format.
716
717 submit_optind
718 The index into submit_argv that corresponds to the first en‐
719 try that is not a command line option.
720
721 submit_argv
722 The argument vector sudo was invoked with, including all com‐
723 mand line options.
724
725 show_version
726 show_version(self, is_verbose: int) -> int
727
728 Display the version. (Same as for all the other plugins.)
729
730 check
731 check(self, command_info: Tuple[str, ...], run_argv: Tuple[str, ...],
732 run_env: Tuple[str, ...]) -> int
733
734 This function is called after policy plugin's check_policy has suc‐
735 ceeded. It can reject execution of the command by returning
736 sudo.RC.REJECT or raising the special exception:
737
738 raise sudo.PluginReject("some message")
739
740 with the message describing the problem. In the latter case, the
741 audit plugins will get the description.
742
743 The function arguments are as follows:
744
745 command_info
746 A vector of information describing the command that will run.
747 See the sudo_plugin(5) manual for possible values.
748
749 run_argv
750 Argument vector describing a command that will be run.
751
752 run_env
753 The environment the command will be run with.
754
755 Approval plugin example
756 Sudo ships a Python Approval plugin example. To try it, register it by
757 adding the following lines to /etc/sudo.conf:
758
759 Plugin python_approval python_plugin.so \
760 ModulePath=/usr/share/doc/sudo/examples/example_approval_plugin.py \
761 ClassName=BusinessHoursApprovalPlugin
762
763 It will only allow execution of commands in the "business hours" (from
764 Monday to Friday between 8:00 and 17:59:59).
765
766 Sudoers group provider plugin API
767 A group provider plugin is registered in the sudoers(5) file. For exam‐
768 ple:
769
770 Defaults group_plugin="python_plugin.so ModulePath=<path> ClassName=<class>"
771
772 Currently, only a single group plugin can be registered in sudoers.
773
774 A group provider plugin may have the following member functions:
775
776 constructor
777 __init__(self, args: Tuple[str, ...], version: str)
778
779 Implementing this function is optional. The default constructor
780 will set the keyword arguments it receives as member variables in
781 the object.
782
783 The function arguments are as follows:
784
785 args The plugin options passed as arguments in the sudoers file
786 plugin registration. All the arguments are free form strings
787 (not necessarily in “key=value” format).
788
789 version
790 The version of the Python Group Plugin API.
791
792 query
793 query(self, user: str, group: str, user_pwd: Tuple)
794
795 The query() function is used to ask the group plugin whether user
796 is a member of group. This method is required.
797
798 The function arguments are as follows:
799
800 user The name of the user being looked up in the external group data‐
801 base.
802
803 group
804 The name of the group being queried.
805
806 user_pwd
807 The password database entry for the user, if any. If user is not
808 present in the password database, user_pwd will be NULL.
809
810 Group plugin example
811 Sudo ships a Python group plugin example. To try it, register it in the
812 sudoers file by adding the following lines:
813
814 Defaults group_plugin="python_plugin.so \
815 ModulePath=/usr/share/doc/sudo/examples/example_group_plugin.py \
816 ClassName=SudoGroupPlugin"
817
818 The example plugin will tell sudo that the user test is part of the non-
819 unix group mygroup. If you add a rule that uses this group, it will af‐
820 fect the test user. For example:
821
822 %:mygroup ALL=(ALL) NOPASSWD: ALL
823
824 Will allow user test to run sudo without a password.
825
826 Hook function API
827 The hook function API is currently not supported for plugins written in
828 Python.
829
830 Conversation API
831 A Python plugin can interact with the user using the sudo.conv() function
832 which displays one or more messages described by the sudo.ConvMessage
833 class. This is the Python equivalent of the conversation() function in
834 the C sudo plugin API. A plugin should not attempt to read directly from
835 the standard input or the user's tty (neither of which are guaranteed to
836 exist).
837
838 The sudo.ConvMessage class specifies how the user interaction should oc‐
839 cur:
840
841 sudo.ConvMessage(msg_type: int, msg: str, timeout: int)
842
843 sudo.ConvMessage member variables:
844
845 msg_type
846 Specifies the type of the conversation. See the sudo.CONV.* con‐
847 stants below.
848
849 msg The message to display to the user. The caller must include a
850 trailing newline in msg if one is to be displayed.
851
852 timeout
853 Optional. The maximum amount of time for the conversation in sec‐
854 onds. If the timeout is exceeded, the sudo.conv() function will
855 raise a sudo.ConversationInterrupted exception. The default is to
856 wait forever (no timeout).
857
858 To specify the message type, the following constants are available:
859
860 • sudo.CONV.PROMPT_ECHO_OFF
861 • sudo.CONV.PROMPT_ECHO_ON
862 • sudo.CONV.ERROR_MSG
863 • sudo.CONV.INFO_MSG
864 • sudo.CONV.PROMPT_MASK
865 • sudo.CONV.PROMPT_ECHO_OK
866 • sudo.CONV.PREFER_TTY
867
868 See the sudo_plugin(5) manual for a description of the message types.
869
870 The sudo.conv() function performs the actual user interaction:
871
872 sudo.conv(message(s), on_suspend=suspend_function,
873 on_resume=resume_function)
874
875 The function arguments are as follows:
876
877 message(s)
878 One of more messages (of type sudo.ConvMessage), each describing a
879 conversation. At least one message is required.
880
881 on_suspend
882 An optional callback function which gets called if the conversation
883 is suspended, for example by the user pressing control-Z. The
884 specified function must take a single argument which will be filled
885 with the number of the signal that caused the process to be sus‐
886 pended.
887
888 on_resume
889 An optional callback function which gets called when the previously
890 suspended conversation is resumed. The specified function must
891 take a single argument which will be filled with the number of the
892 signal that caused the process to be suspended.
893
894 The sudo.conv() function can raise the following exceptions:
895
896 sudo.SudoException
897 If the conversation fails, for example when the conversation func‐
898 tion is not available.
899
900 sudo.ConversationInterrupted
901 If the conversation function returns an error, e.g., the timeout
902 passed or the user interrupted the conversation by pressing con‐
903 trol-C.
904
905 Conversation example
906 Sudo ships with an example plugin demonstrating the Python conversation
907 API. To try it, register it by adding the following lines to
908 /etc/sudo.conf:
909
910 Plugin python_io python_plugin.so \
911 ModulePath=/usr/share/doc/sudo/examples/example_conversation.py \
912 ClassName=ReasonLoggerIOPlugin
913
914 Information / error display API
915 sudo.log_info(string(s), sep=" ", end="\n")
916 sudo.log_error(string(s), sep=" ", end="\n")
917
918 To display information to the user, the sudo.log_info() function can be
919 used. To display error messages, use sudo.log_error(). The syntax is
920 similar to the Python print() function.
921
922 The function arguments are as follows:
923
924 string(s)
925 One or more strings to display.
926
927 sep An optional string which will be used as the separator between the
928 specified strings. The default is a space character, (‘ ’).
929
930 end An optional string which will be displayed at the end of the mes‐
931 sage. The default is a new line character (‘\n’).
932
933 Debug API
934 Debug messages are not visible to the user and are only logged debugging
935 is explicitly enabled in sudo.conf(5). Python plugins can use the
936 sudo.debug() function to make use of sudo's debug system.
937
938 Enabling debugging in sudo.conf
939
940 To enable debug messages, add a Debug line to sudo.conf(5) with the pro‐
941 gram set to python_plugin.so. For example, to store debug output in
942 /var/log/sudo_python_debug, use a line like the following:
943
944 Debug python_plugin.so /var/log/sudo_python_debug \
945 plugin@trace,c_calls@trace
946
947 The debug options are in the form of multiple “subsystem@level” strings,
948 separated by commas (‘,’). For example to just see the debug output of
949 sudo.debug() calls, use:
950
951 Debug python_plugin.so /var/log/sudo_python_debug plugin@trace
952
953 See sudo_conf(5) for more details.
954
955 The most interesting subsystems for Python plugin development are:
956
957 plugin
958 Logs each sudo.debug() API call.
959
960 py_calls
961 Logs whenever a C function calls into the python module. For exam‐
962 ple, calling the __init__() function.
963
964 c_calls
965 Logs whenever python calls into a C sudo API function.
966
967 internal
968 Logs internal functions of the python language wrapper plugin.
969
970 sudo_cb
971 Logs when sudo calls into the python plugin API.
972
973 load Logs python plugin loading / unloading events.
974
975 You can also specify “all” as the subsystem name to log debug messages
976 for all subsystems.
977
978 The sudo.debug() function is defined as:
979
980 sudo.debug(level, message(s))
981
982 The function arguments are as follows:
983
984 level
985 an integer, use one of the log level constants below
986
987 message(s)
988 one or more messages to log
989
990 Available log levels:
991
992 sudo.conf name Python constant description
993 crit sudo.DEBUG.CRIT only critical messages
994 err sudo.DEBUG.ERROR
995 warn sudo.DEBUG.WARN
996 notice sudo.DEBUG.NOTICE
997 diag sudo.DEBUG.DIAG
998 info sudo.DEBUG.INFO
999 trace sudo.DEBUG.TRACE
1000 debug sudo.DEBUG.DEBUG very extreme verbose debugging
1001
1002 Using the logging module
1003
1004 Alternatively, a plugin can use the built in logging module of Python as
1005 well. Sudo adds its log handler to the root logger, so by default all
1006 output of a logger will get forwarded to sudo log system, as it would
1007 call sudo.debug.
1008
1009 The log handler of sudo will map each Python log level of a message to
1010 the appropriate sudo debug level. Note however, that sudo debug system
1011 will only get the messages not filtered out by the Python loggers. For
1012 example, the log level of the python logger will be an additional filter
1013 for the log messages, and is usually very different from what level is
1014 set in sudo.conf for the sudo debug system.
1015
1016 Debug example
1017 Sudo ships an example debug plugin by default. To try it, register it by
1018 adding the following lines to /etc/sudo.conf:
1019
1020 Plugin python_io python_plugin.so \
1021 ModulePath=/usr/share/doc/sudo/examples/example_debugging.py \
1022 ClassName=DebugDemoPlugin
1023
1024 Debug python_plugin.so \
1025 /var/log/sudo_python_debug plugin@trace,c_calls@trace
1026
1027 Option conversion API
1028 The Python plugin API includes two convenience functions to convert op‐
1029 tions in “key=value” format to a dictionary and vice versa.
1030
1031 options_as_dict
1032 options_as_dict(options)
1033
1034 The function arguments are as follows:
1035
1036 options
1037 An iterable (tuple, list, etc.) of strings, each in
1038 “key=value” format. This is how the plugin API passes op‐
1039 tions and settings to a Python plugin.
1040
1041 The function returns the resulting dictionary. Each string of the
1042 passed in options will be split at the first equal sign (‘=’) into
1043 a key and value. Dictionary keys will never contain this symbol
1044 (but values may).
1045
1046 options_from_dict
1047 options_from_dict(options_dict)
1048
1049 The function arguments are as follows:
1050
1051 options_dict
1052 A dictionary where both the key and the value are strings.
1053 Note that the key should not contain an equal sign (‘=’),
1054 otherwise the resulting string will have a different meaning.
1055 However, this is not currently enforced.
1056
1057 The function returns a tuple containing the strings in “key=value”
1058 form for each key and value in the options_dict dictionary passed
1059 in. This is how the plugin API accepts options and settings.
1060
1062 None yet
1063
1065 Only a maximum number of 8 python I/O plugins can be loaded at once. If
1066 /etc/sudo.conf contains more, those will be rejected with a warning mes‐
1067 sage.
1068
1069 The Event API and the hook function API is currently not accessible for
1070 Python plugins.
1071
1073 sudo.conf(5), sudo_plugin(5), sudoers(5), sudo(8)
1074
1076 Many people have worked on sudo over the years; this version consists of
1077 code written primarily by:
1078
1079 Todd C. Miller
1080
1081 See the CONTRIBUTORS file in the sudo distribution
1082 (https://www.sudo.ws/contributors.html) for an exhaustive list of people
1083 who have contributed to sudo.
1084
1086 Python plugin support is currently considered experimental.
1087
1088 If you feel you have found a bug in sudo, please submit a bug report at
1089 https://bugzilla.sudo.ws/
1090
1092 All Python plugin handling is implemented inside the python_plugin.so dy‐
1093 namic plugin. Therefore, if no Python plugin is registered in
1094 sudo.conf(5) or the sudoers file, sudo will not load the Python inter‐
1095 preter or the Python libraries.
1096
1097 By default, a Python plugin can only import Python modules which are
1098 owned by root and are only writable by the owner. The reason for this is
1099 to prevent a file getting imported accidentally which is modifiable by a
1100 non-root user. As sudo plugins run as root, accidentally importing such
1101 file would make it possible for any user (having write access) to execute
1102 any code with administrative rights.
1103
1104 However, during development of a plugin this might not be very conve‐
1105 nient. The sudo.conf(5) developer_mode option can be used to disable it.
1106 For example:
1107 Set developer_mode true
1108
1109 Please note that this creates a security risk, so it is not recommended
1110 on critical systems such as a desktop machine for daily use, but is in‐
1111 tended to be used in development environments (VM, container, etc). Be‐
1112 fore enabling developer mode, ensure you understand the implications.
1113
1115 Limited free support is available via the sudo-users mailing list, see
1116 https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search
1117 the archives.
1118
1120 sudo is provided “AS IS” and any express or implied warranties, includ‐
1121 ing, but not limited to, the implied warranties of merchantability and
1122 fitness for a particular purpose are disclaimed. See the LICENSE file
1123 distributed with sudo or https://www.sudo.ws/license.html for complete
1124 details.
1125
1126Sudo 1.9.8p2 February 19, 2020 Sudo 1.9.8p2