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

PLUGIN API CHANGELOG (Python)

1068     None yet
1069

LIMITATIONS

1071     A maximum of 8 python I/O plugins can be loaded at once.  If
1072     /etc/sudo.conf contains more, those will be rejected with a warning mes‐
1073     sage.
1074
1075     The Event API and the hook function API is currently not accessible for
1076     Python plugins.
1077

SEE ALSO

1079     sudo.conf(5), sudo_plugin(5), sudoers(5), sudo(8)
1080

AUTHORS

1082     Many people have worked on sudo over the years; this version consists of
1083     code written primarily by:
1084
1085           Todd C. Miller
1086
1087     See the CONTRIBUTORS.md file in the sudo distribution
1088     (https://www.sudo.ws/about/contributors/) for an exhaustive list of peo‐
1089     ple who have contributed to sudo.
1090

BUGS

1092     Python plugin support is currently considered experimental.
1093
1094     If you believe you have found a bug in sudo, you can submit a bug report
1095     at https://bugzilla.sudo.ws/
1096

SECURITY CONSIDERATIONS

1098     All Python plugin handling is implemented inside the python_plugin.so dy‐
1099     namic plugin.  Therefore, if no Python plugin is registered in
1100     sudo.conf(5) or the sudoers file, sudo will not load the Python inter‐
1101     preter or the Python libraries.
1102
1103     As sudo runs plugins as root, care must be taken when writing Python
1104     plugins to avoid creating security vulnerabilities, just as one would
1105     when writing plugins in C.
1106

SUPPORT

1108     Limited free support is available via the sudo-users mailing list, see
1109     https://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search
1110     the archives.
1111

DISCLAIMER

1113     sudo is provided “AS IS” and any express or implied warranties, includ‐
1114     ing, but not limited to, the implied warranties of merchantability and
1115     fitness for a particular purpose are disclaimed.  See the LICENSE.md file
1116     distributed with sudo or https://www.sudo.ws/about/license/ for complete
1117     details.
1118
1119Sudo 1.9.13p2                  January 16, 2023                  Sudo 1.9.13p2
Impressum