1SUDO_PLUGIN_PYTHON(5)       BSD File Formats Manual      SUDO_PLUGIN_PYTHON(5)
2

NAME

4     sudo_plugin_python — Sudo Plugin API (Python)
5

DESCRIPTION

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).
189                 Information 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
320     addition 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
378           except 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
541                 entry 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
590                 either 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
594                 behalf of the sudo front-end, command_info may include infor‐
595                 mation 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
626                 either 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
634                 rejected 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 plug‐
658                 in 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
719                 entry 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
820     affect 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
839     occur:
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
1029     options 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
1039                 options 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

PLUGIN API CHANGELOG (Python)

1062     None yet
1063

LIMITATIONS

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

SEE ALSO

1073     sudo.conf(5), sudo_plugin(5), sudoers(5), sudo(8)
1074

AUTHORS

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

BUGS

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

SECURITY CONSIDERATIONS

1092     All Python plugin handling is implemented inside the python_plugin.so
1093     dynamic 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
1111     intended to be used in development environments (VM, container, etc).
1112     Before enabling developer mode, ensure you understand the implications.
1113

SUPPORT

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

DISCLAIMER

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.5p2                   February 19, 2020                  Sudo 1.9.5p2
Impressum