1: .\"
2: .\" Copyright (c) 2009-2013 Todd C. Miller <Todd.Miller@courtesan.com>
3: .\"
4: .\" Permission to use, copy, modify, and distribute this software for any
5: .\" purpose with or without fee is hereby granted, provided that the above
6: .\" copyright notice and this permission notice appear in all copies.
7: .\"
8: .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9: .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10: .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11: .\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12: .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13: .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14: .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15: .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16: .\"
17: .Dd December 20, 2013
18: .Dt SUDO_PLUGIN @mansectform@
19: .Os Sudo @PACKAGE_VERSION@
20: .Sh NAME
21: .Nm sudo_plugin
22: .Nd Sudo Plugin API
23: .Sh DESCRIPTION
24: Starting with version 1.8,
25: .Nm sudo
26: supports a plugin API
27: for policy and session logging.
28: Plugins may be compiled as dynamic shared objects (the default on
29: systems that support them) or compiled statically into the
30: .Nm sudo
31: binary itself.
32: By default, the
33: .Nm sudoers
34: policy plugin and an associated I/O logging plugin are used.
35: Via the plugin API,
36: .Nm sudo
37: can be configured to use alternate policy and/or I/O logging plugins
38: provided by third parties.
39: The plugins to be used are specified in the
40: .Xr sudo.conf @mansectform@
41: file.
42: .Pp
43: The API is versioned with a major and minor number.
44: The minor version number is incremented when additions are made.
45: The major number is incremented when incompatible changes are made.
46: A plugin should be check the version passed to it and make sure that the
47: major version matches.
48: .Pp
49: The plugin API is defined by the
50: .Li sudo_plugin.h
51: header file.
52: .Ss Policy plugin API
53: A policy plugin must declare and populate a
54: .Li policy_plugin
55: struct in the global scope.
56: This structure contains pointers to the functions that implement the
57: .Nm sudo
58: policy checks.
59: The name of the symbol should be specified in
60: .Xr sudo.conf @mansectform@
61: along with a path to the plugin so that
62: .Nm sudo
63: can load it.
64: .Bd -literal
65: struct policy_plugin {
66: #define SUDO_POLICY_PLUGIN 1
67: unsigned int type; /* always SUDO_POLICY_PLUGIN */
68: unsigned int version; /* always SUDO_API_VERSION */
69: int (*open)(unsigned int version, sudo_conv_t conversation,
70: sudo_printf_t plugin_printf, char * const settings[],
71: char * const user_info[], char * const user_env[],
72: char * const plugin_options[]);
73: void (*close)(int exit_status, int error);
74: int (*show_version)(int verbose);
75: int (*check_policy)(int argc, char * const argv[],
76: char *env_add[], char **command_info[],
77: char **argv_out[], char **user_env_out[]);
78: int (*list)(int argc, char * const argv[], int verbose,
79: const char *list_user);
80: int (*validate)(void);
81: void (*invalidate)(int remove);
82: int (*init_session)(struct passwd *pwd, char **user_env[]);
83: void (*register_hooks)(int version,
84: int (*register_hook)(struct sudo_hook *hook));
85: void (*deregister_hooks)(int version,
86: int (*deregister_hook)(struct sudo_hook *hook));
87: };
88: .Ed
89: .Pp
90: The policy_plugin struct has the following fields:
91: .Bl -tag -width 4n
92: .It type
93: The
94: .Li type
95: field should always be set to SUDO_POLICY_PLUGIN.
96: .It version
97: The
98: .Li version
99: field should be set to
100: .Dv SUDO_API_VERSION .
101: .Pp
102: This allows
103: .Nm sudo
104: to determine the API version the plugin was
105: built against.
106: .It open
107: .Bd -literal -compact
108: int (*open)(unsigned int version, sudo_conv_t conversation,
109: sudo_printf_t plugin_printf, char * const settings[],
110: char * const user_info[], char * const user_env[],
111: char * const plugin_options[]);
112: .Ed
113: .Pp
114: Returns 1 on success, 0 on failure, \-1 if a general error occurred,
115: or \-2 if there was a usage error.
116: In the latter case,
117: .Nm sudo
118: will print a usage message before it exits.
119: If an error occurs, the plugin may optionally call the
120: .Fn conversation
121: or
122: .Fn plugin_printf
123: function with
124: .Dv SUDO_CONF_ERROR_MSG
125: to present additional error information to the user.
126: .Pp
127: The function arguments are as follows:
128: .Bl -tag -width 4n
129: .It version
130: The version passed in by
131: .Nm sudo
132: allows the plugin to determine the
133: major and minor version number of the plugin API supported by
134: .Nm sudo .
135: .It conversation
136: A pointer to the
137: .Fn conversation
138: function that can be used by the plugin to interact with the user (see below).
139: Returns 0 on success and \-1 on failure.
140: .It plugin_printf
141: A pointer to a
142: .Fn printf Ns -style
143: function that may be used to display informational or error messages
144: (see below).
145: Returns the number of characters printed on success and \-1 on failure.
146: .It settings
147: A vector of user-supplied
148: .Nm sudo
149: settings in the form of
150: .Dq name=value
151: strings.
152: The vector is terminated by a
153: .Dv NULL
154: pointer.
155: These settings correspond to flags the user specified when running
156: .Nm sudo .
157: As such, they will only be present when the corresponding flag has
158: been specified on the command line.
159: .Pp
160: When parsing
161: .Em settings ,
162: the plugin should split on the
163: .Sy first
164: equal sign
165: .Pq Ql =
166: since the
167: .Em name
168: field will never include one
169: itself but the
170: .Em value
171: might.
172: .Bl -tag -width 4n
173: .It bsdauth_type=string
174: Authentication type, if specified by the
175: .Fl a
176: flag, to use on
177: systems where BSD authentication is supported.
178: .It closefrom=number
179: If specified, the user has requested via the
180: .Fl C
181: flag that
182: .Nm sudo
183: close all files descriptors with a value of
184: .Em number
185: or higher.
186: The plugin may optionally pass this, or another value, back in the
187: .Em command_info
188: list.
189: .It debug_flags=string
190: A comma-separated list of debug flags that correspond to
191: .Nm sudo Ns 's
192: .Li Debug
193: entry in
194: .Xr sudo.conf @mansectform@ ,
195: if there is one.
196: The flags are passed to the plugin as they appear in
197: .Xr sudo.conf @mansectform@ .
198: The syntax used by
199: .Nm sudo
200: and the
201: .Nm sudoers
202: plugin is
203: .Em subsystem Ns @ Ns Em priority
204: but the plugin is free to use a different
205: format so long as it does not include a comma
206: .Pq Ql ,\& .
207: There is not currently a way to specify a set of debug flags specific
208: to the plugin--the flags are shared by
209: .Nm sudo
210: and the plugin.
211: .It debug_level=number
212: This setting has been deprecated in favor of
213: .Em debug_flags .
214: .It ignore_ticket=bool
215: Set to true if the user specified the
216: .Fl k
217: flag along with a
218: command, indicating that the user wishes to ignore any cached
219: authentication credentials.
220: .Em implied_shell
221: to true.
222: This allows
223: .Nm sudo
224: with no arguments
225: to be used similarly to
226: .Xr su 1 .
227: If the plugin does not to support this usage, it may return a value of \-2
228: from the
229: .Fn check_policy
230: function, which will cause
231: .Nm sudo
232: to print a usage message and
233: exit.
234: .It implied_shell=bool
235: If the user does not specify a program on the command line,
236: .Nm sudo
237: will pass the plugin the path to the user's shell and set
238: .It login_class=string
239: BSD login class to use when setting resource limits and nice value,
240: if specified by the
241: .Fl c
242: flag.
243: .It login_shell=bool
244: Set to true if the user specified the
245: .Fl i
246: flag, indicating that
247: the user wishes to run a login shell.
248: .It max_groups=int
249: The maximum number of groups a user may belong to.
250: This will only be present if there is a corresponding setting in
251: .Xr sudo.conf @mansectform@ .
252: .It network_addrs=list
253: A space-separated list of IP network addresses and netmasks in the
254: form
255: .Dq addr/netmask ,
256: e.g.\&
257: .Dq 192.168.1.2/255.255.255.0 .
258: The address and netmask pairs may be either IPv4 or IPv6, depending on
259: what the operating system supports.
260: If the address contains a colon
261: .Pq Ql :\& ,
262: it is an IPv6 address, else it is IPv4.
263: .It noninteractive=bool
264: Set to true if the user specified the
265: .Fl n
266: flag, indicating that
267: .Nm sudo
268: should operate in non-interactive mode.
269: The plugin may reject a command run in non-interactive mode if user
270: interaction is required.
271: .It plugin_dir=string
272: The default plugin directory used by the
273: .Nm sudo
274: front end.
275: This is the default directory set at compile time and may not
276: correspond to the directory the running plugin was loaded from.
277: It may be used by a plugin to locate support files.
278: .It preserve_environment=bool
279: Set to true if the user specified the
280: .Fl E
281: flag, indicating that
282: the user wishes to preserve the environment.
283: .It preserve_groups=bool
284: Set to true if the user specified the
285: .Fl P
286: flag, indicating that
287: the user wishes to preserve the group vector instead of setting it
288: based on the runas user.
289: .It progname=string
290: The command name that sudo was run as, typically
291: .Dq sudo
292: or
293: .Dq sudoedit .
294: .It prompt=string
295: The prompt to use when requesting a password, if specified via
296: the
297: .Fl p
298: flag.
299: .It remote_host=string
300: The name of the remote host to run the command on, if specified via
301: the
302: .Fl h
303: option.
304: Support for running the command on a remote host is meant to be implemented
305: via a helper program that is executed in place of the user-specified command.
306: The
307: .Nm sudo
308: front end is only capable of executing commands on the local host.
309: Only available starting with API version 1.4.
310: .It run_shell=bool
311: Set to true if the user specified the
312: .Fl s
313: flag, indicating that the user wishes to run a shell.
314: .It runas_group=string
315: The group name or gid to run the command as, if specified via
316: the
317: .Fl g
318: flag.
319: .It runas_user=string
320: The user name or uid to run the command as, if specified via the
321: .Fl u
322: flag.
323: .It selinux_role=string
324: SELinux role to use when executing the command, if specified by
325: the
326: .Fl r
327: flag.
328: .It selinux_type=string
329: SELinux type to use when executing the command, if specified by
330: the
331: .Fl t
332: flag.
333: .It set_home=bool
334: Set to true if the user specified the
335: .Fl H
336: flag.
337: If true, set the
338: .Li HOME
339: environment variable to the target user's home directory.
340: .It sudoedit=bool
341: Set to true when the
342: .Fl e
343: flag is is specified or if invoked as
344: .Nm sudoedit .
345: The plugin shall substitute an editor into
346: .Em argv
347: in the
348: .Fn check_policy
349: function or return \-2 with a usage error
350: if the plugin does not support
351: .Em sudoedit .
352: For more information, see the
353: .Em check_policy
354: section.
355: .El
356: .Pp
357: Additional settings may be added in the future so the plugin should
358: silently ignore settings that it does not recognize.
359: .It user_info
360: A vector of information about the user running the command in the form of
361: .Dq name=value
362: strings.
363: The vector is terminated by a
364: .Dv NULL
365: pointer.
366: .Pp
367: When parsing
368: .Em user_info ,
369: the plugin should split on the
370: .Sy first
371: equal sign
372: .Pq Ql =
373: since the
374: .Em name
375: field will never include one
376: itself but the
377: .Em value
378: might.
379: .Bl -tag -width 4n
380: .It cols=int
381: The number of columns the user's terminal supports.
382: If there is no terminal device available, a default value of 80 is used.
383: .It cwd=string
384: The user's current working directory.
385: .It egid=gid_t
386: The effective group ID of the user invoking
387: .Nm sudo .
388: .It euid=uid_t
389: The effective user ID of the user invoking
390: .Nm sudo .
391: .It gid=gid_t
392: The real group ID of the user invoking
393: .Nm sudo .
394: .It groups=list
395: The user's supplementary group list formatted as a string of
396: comma-separated group IDs.
397: .It host=string
398: The local machine's hostname as returned by the
399: .Xr gethostname 2
400: system call.
401: .It lines=int
402: The number of lines the user's terminal supports.
403: If there is
404: no terminal device available, a default value of 24 is used.
405: .It pgid=int
406: The ID of the process group that the running
407: .Nm sudo
408: process is a member of.
409: Only available starting with API version 1.2.
410: .It pid=int
411: The process ID of the running
412: .Nm sudo
413: process.
414: Only available starting with API version 1.2.
415: .It plugin_options
416: Any (non-comment) strings immediately after the plugin path are
417: passed as arguments to the plugin.
418: These arguments are split on a white space boundary and are passed to
419: the plugin in the form of a
420: .Dv NULL Ns -terminated
421: array of strings.
422: If no arguments were
423: specified,
424: .Em plugin_options
425: will be the
426: .Dv NULL
427: pointer.
428: .Pp
429: NOTE: the
430: .Em plugin_options
431: parameter is only available starting with
432: API version 1.2.
433: A plugin
434: .Sy must
435: check the API version specified
436: by the
437: .Nm sudo
438: front end before using
439: .Em plugin_options .
440: Failure to do so may result in a crash.
441: .It ppid=int
442: The parent process ID of the running
443: .Nm sudo
444: process.
445: Only available starting with API version 1.2.
446: .It sid=int
447: The session ID of the running
448: .Nm sudo
449: process or 0 if
450: .Nm sudo
451: is not part of a POSIX job control session.
452: Only available starting with API version 1.2.
453: .It tcpgid=int
454: The ID of the foreground process group associated with the terminal
455: device associated with the
456: .Nm sudo
457: process or \-1 if there is no
458: terminal present.
459: Only available starting with API version 1.2.
460: .It tty=string
461: The path to the user's terminal device.
462: If the user has no terminal device associated with the session,
463: the value will be empty, as in
464: .Dq Li tty= .
465: .It uid=uid_t
466: The real user ID of the user invoking
467: .Nm sudo .
468: .It user=string
469: The name of the user invoking
470: .Nm sudo .
471: .El
472: .It user_env
473: The user's environment in the form of a
474: .Dv NULL Ns -terminated vector of
475: .Dq name=value
476: strings.
477: .Pp
478: When parsing
479: .Em user_env ,
480: the plugin should split on the
481: .Sy first
482: equal sign
483: .Pq Ql =
484: since the
485: .Em name
486: field will never include one
487: itself but the
488: .Em value
489: might.
490: .El
491: .It close
492: .Bd -literal -compact
493: void (*close)(int exit_status, int error);
494: .Ed
495: .Pp
496: The
497: .Fn close
498: function is called when the command being run by
499: .Nm sudo
500: finishes.
501: .Pp
502: The function arguments are as follows:
503: .Bl -tag -width 4n
504: .It exit_status
505: The command's exit status, as returned by the
506: .Xr wait 2
507: system call.
508: The value of
509: .Li exit_status
510: is undefined if
511: .Li error
512: is non-zero.
513: .It error
514: If the command could not be executed, this is set to the value of
515: .Li errno
516: set by the
517: .Xr execve 2
518: system call.
519: The plugin is responsible for displaying error information via the
520: .Fn conversation
521: or
522: .Fn plugin_printf
523: function.
524: If the command was successfully executed, the value of
525: .Li error
526: is 0.
527: .El
528: .Pp
529: If no
530: .Fn close
531: function is defined, no I/O logging plugins are loaded,
532: and neither the
533: .Em timeout
534: not
535: .Em use_pty
536: options are set in the
537: .Li command_info
538: list, the
539: .Nm sudo
540: front end may execute the command directly instead of running
541: it as a child process.
542: .It show_version
543: .Bd -literal -compact
544: int (*show_version)(int verbose);
545: .Ed
546: .Pp
547: The
548: .Fn show_version
549: function is called by
550: .Nm sudo
551: when the user specifies
552: the
553: .Fl V
554: option.
555: The plugin may display its version information to the user via the
556: .Fn conversation
557: or
558: .Fn plugin_printf
559: function using
560: .Dv SUDO_CONV_INFO_MSG .
561: If the user requests detailed version information, the verbose flag will be set.
562: .It check_policy
563: .Bd -literal -compact
564: int (*check_policy)(int argc, char * const argv[]
565: char *env_add[], char **command_info[],
566: char **argv_out[], char **user_env_out[]);
567: .Ed
568: .Pp
569: The
570: .Fn check_policy
571: function is called by
572: .Nm sudo
573: to determine
574: whether the user is allowed to run the specified commands.
575: .Pp
576: If the
577: .Em sudoedit
578: option was enabled in the
579: .Em settings
580: array
581: passed to the
582: .Fn open
583: function, the user has requested
584: .Em sudoedit
585: mode.
586: .Em sudoedit
587: is a mechanism for editing one or more files
588: where an editor is run with the user's credentials instead of with
589: elevated privileges.
590: .Nm sudo
591: achieves this by creating user-writable
592: temporary copies of the files to be edited and then overwriting the
593: originals with the temporary copies after editing is complete.
594: If the plugin supports
595: .Em sudoedit ,
596: it should choose the editor to be used, potentially from a variable
597: in the user's environment, such as
598: .Li EDITOR ,
599: and include it in
600: .Em argv_out
601: (note that environment
602: variables may include command line flags).
603: The files to be edited should be copied from
604: .Em argv
605: into
606: .Em argv_out ,
607: separated from the
608: editor and its arguments by a
609: .Dq Li --
610: element.
611: The
612: .Dq Li --
613: will
614: be removed by
615: .Nm sudo
616: before the editor is executed.
617: The plugin should also set
618: .Em sudoedit=true
619: in the
620: .Em command_info
621: list.
622: .Pp
623: The
624: .Fn check_policy
625: function returns 1 if the command is allowed,
626: 0 if not allowed, \-1 for a general error, or \-2 for a usage error
627: or if
628: .Em sudoedit
629: was specified but is unsupported by the plugin.
630: In the latter case,
631: .Nm sudo
632: will print a usage message before it
633: exits.
634: If an error occurs, the plugin may optionally call the
635: .Fn conversation
636: or
637: .Fn plugin_printf
638: function with
639: .Dv SUDO_CONF_ERROR_MSG
640: to present additional error information to the user.
641: .Pp
642: The function arguments are as follows:
643: .Bl -tag -width 4n
644: .It argc
645: The number of elements in
646: .Em argv ,
647: not counting the final
648: .Dv NULL
649: pointer.
650: .It argv
651: The argument vector describing the command the user wishes to run,
652: in the same form as what would be passed to the
653: .Xr execve 2
654: system call.
655: The vector is terminated by a
656: .Dv NULL
657: pointer.
658: .It env_add
659: Additional environment variables specified by the user on the command
660: line in the form of a
661: .Dv NULL Ns -terminated
662: vector of
663: .Dq name=value
664: strings.
665: The plugin may reject the command if one or more variables
666: are not allowed to be set, or it may silently ignore such variables.
667: .Pp
668: When parsing
669: .Em env_add ,
670: the plugin should split on the
671: .Sy first
672: equal sign
673: .Pq Ql =
674: since the
675: .Em name
676: field will never include one
677: itself but the
678: .Em value
679: might.
680: .It command_info
681: Information about the command being run in the form of
682: .Dq name=value
683: strings.
684: These values are used by
685: .Nm sudo
686: to set the execution
687: environment when running a command.
688: The plugin is responsible for creating and populating the vector,
689: which must be terminated with a
690: .Dv NULL
691: pointer.
692: The following values are recognized by
693: .Nm sudo :
694: .Bl -tag -width 4n
695: .It chroot=string
696: The root directory to use when running the command.
697: .It closefrom=number
698: If specified,
699: .Nm sudo
700: will close all files descriptors with a value
701: of
702: .Em number
703: or higher.
704: .It command=string
705: Fully qualified path to the command to be executed.
706: .It cwd=string
707: The current working directory to change to when executing the command.
708: .It exec_background=bool
709: By default,
710: .Nm sudo
711: runs a command as the foreground process as long as
712: .Nm sudo
713: itself is running in the foreground.
714: When
715: .Em exec_background
716: is enabled and the command is being run in a pty (due to I/O logging
717: or the
718: .Em use_pty
719: setting), the command will be run as a background process.
720: Attempts to read from the controlling terminal (or to change terminal
721: settings) will result in the command being suspended with the
722: .Dv SIGTTIN
723: signal (or
724: .Dv SIGTTOU
725: in the case of terminal settings).
726: If this happens when
727: .Nm sudo
728: is a foreground process, the command will be granted the controlling terminal
729: and resumed in the foreground with no user intervention required.
730: The advantage of initially running the command in the background is that
731: .Nm sudo
732: need not read from the terminal unless the command explicitly requests it.
733: Otherwise, any terminal input must be passed to the command, whether it
734: has required it or not (the kernel buffers terminals so it is not possible
735: to tell whether the command really wants the input).
736: This is different from historic
737: .Em sudo
738: behavior or when the command is not being run in a pty.
739: .Pp
740: For this to work seamlessly, the operating system must support the
741: automatic restarting of system calls.
742: Unfortunately, not all operating systems do this by default,
743: and even those that do may have bugs.
744: For example, Mac OS X fails to restart the
745: .Fn tcgetattr
746: and
747: .Fn tcsetattr
748: system calls (this is a bug in Mac OS X).
749: Furthermore, because this behavior depends on the command stopping with the
750: .Dv SIGTTIN
751: or
752: .Dv SIGTTOU
753: signals, programs that catch these signals and suspend themselves
754: with a different signal (usually
755: .Dv SIGTOP )
756: will not be automatically foregrounded.
757: Some versions of the linux
758: .Xr su 1
759: command behave this way.
760: Because of this, a plugin should not set
761: .Em exec_background
762: unless it is explicitly enabled by the administrator and there should
763: be a way to enabled or disable it on a per-command basis.
764: .Pp
765: This setting has no effect unless I/O logging is enabled or
766: .Em use_pty
767: is enabled.
768: .It iolog_compress=bool
769: Set to true if the I/O logging plugins, if any, should compress the
770: log data.
771: This is a hint to the I/O logging plugin which may choose to ignore it.
772: .It iolog_path=string
773: Fully qualified path to the file or directory in which I/O log is
774: to be stored.
775: This is a hint to the I/O logging plugin which may choose to ignore it.
776: If no I/O logging plugin is loaded, this setting has no effect.
777: .It iolog_stdin=bool
778: Set to true if the I/O logging plugins, if any, should log the
779: standard input if it is not connected to a terminal device.
780: This is a hint to the I/O logging plugin which may choose to ignore it.
781: .It iolog_stdout=bool
782: Set to true if the I/O logging plugins, if any, should log the
783: standard output if it is not connected to a terminal device.
784: This is a hint to the I/O logging plugin which may choose to ignore it.
785: .It iolog_stderr=bool
786: Set to true if the I/O logging plugins, if any, should log the
787: standard error if it is not connected to a terminal device.
788: This is a hint to the I/O logging plugin which may choose to ignore it.
789: .It iolog_ttyin=bool
790: Set to true if the I/O logging plugins, if any, should log all
791: terminal input.
792: This only includes input typed by the user and not from a pipe or
793: redirected from a file.
794: This is a hint to the I/O logging plugin which may choose to ignore it.
795: .It iolog_ttyout=bool
796: Set to true if the I/O logging plugins, if any, should log all
797: terminal output.
798: This only includes output to the screen, not output to a pipe or file.
799: This is a hint to the I/O logging plugin which may choose to ignore it.
800: .It login_class=string
801: BSD login class to use when setting resource limits and nice value
802: (optional).
803: This option is only set on systems that support login classes.
804: .It nice=int
805: Nice value (priority) to use when executing the command.
806: The nice value, if specified, overrides the priority associated with the
807: .Em login_class
808: on BSD systems.
809: .It noexec=bool
810: If set, prevent the command from executing other programs.
811: .It preserve_fds=list
812: A comma-separated list of file descriptors that should be
813: preserved, regardless of the value of the
814: .Em closefrom
815: setting.
816: Only available starting with API version 1.5.
817: .It preserve_groups=bool
818: If set,
819: .Nm sudo
820: will preserve the user's group vector instead of
821: initializing the group vector based on
822: .Li runas_user .
823: .It runas_egid=gid
824: Effective group ID to run the command as.
825: If not specified, the value of
826: .Em runas_gid
827: is used.
828: .It runas_euid=uid
829: Effective user ID to run the command as.
830: If not specified, the value of
831: .Em runas_uid
832: is used.
833: .It runas_gid=gid
834: Group ID to run the command as.
835: .It runas_groups=list
836: The supplementary group vector to use for the command in the form
837: of a comma-separated list of group IDs.
838: If
839: .Em preserve_groups
840: is set, this option is ignored.
841: .It runas_uid=uid
842: User ID to run the command as.
843: .It selinux_role=string
844: SELinux role to use when executing the command.
845: .It selinux_type=string
846: SELinux type to use when executing the command.
847: .It set_utmp=bool
848: Create a utmp (or utmpx) entry when a pseudo-tty is allocated.
849: By default, the new entry will be a copy of the user's existing utmp
850: entry (if any), with the tty, time, type and pid fields updated.
851: .It sudoedit=bool
852: Set to true when in
853: .Em sudoedit
854: mode.
855: The plugin may enable
856: .Em sudoedit
857: mode even if
858: .Nm sudo
859: was not invoked as
860: .Nm sudoedit .
861: This allows the plugin to perform command substitution and transparently
862: enable
863: .Em sudoedit
864: when the user attempts to run an editor.
865: .It timeout=int
866: Command timeout.
867: If non-zero then when the timeout expires the command will be killed.
868: .It umask=octal
869: The file creation mask to use when executing the command.
870: .It use_pty=bool
871: Allocate a pseudo-tty to run the command in, regardless of whether
872: or not I/O logging is in use.
873: By default,
874: .Nm sudo
875: will only run
876: the command in a pty when an I/O log plugin is loaded.
877: .It utmp_user=string
878: User name to use when constructing a new utmp (or utmpx) entry when
879: .Em set_utmp
880: is enabled.
881: This option can be used to set the user field in the utmp entry to
882: the user the command runs as rather than the invoking user.
883: If not set,
884: .Nm sudo
885: will base the new entry on
886: the invoking user's existing entry.
887: .El
888: .Pp
889: Unsupported values will be ignored.
890: .It argv_out
891: The
892: .Dv NULL Ns -terminated
893: argument vector to pass to the
894: .Xr execve 2
895: system call when executing the command.
896: The plugin is responsible for allocating and populating the vector.
897: .It user_env_out
898: The
899: .Dv NULL Ns -terminated
900: environment vector to use when executing the command.
901: The plugin is responsible for allocating and populating the vector.
902: .El
903: .It list
904: .Bd -literal -compact
905: int (*list)(int verbose, const char *list_user,
906: int argc, char * const argv[]);
907: .Ed
908: .Pp
909: List available privileges for the invoking user.
910: Returns 1 on success, 0 on failure and \-1 on error.
911: On error, the plugin may optionally call the
912: .Fn conversation
913: or
914: .Fn plugin_printf
915: function with
916: .Dv SUDO_CONF_ERROR_MSG
917: to present additional error information to
918: the user.
919: .Pp
920: Privileges should be output via the
921: .Fn conversation
922: or
923: .Fn plugin_printf
924: function using
925: .Dv SUDO_CONV_INFO_MSG ,
926: .Bl -tag -width 4n
927: .It verbose
928: Flag indicating whether to list in verbose mode or not.
929: .It list_user
930: The name of a different user to list privileges for if the policy
931: allows it.
932: If
933: .Dv NULL ,
934: the plugin should list the privileges of the invoking user.
935: .It argc
936: The number of elements in
937: .Em argv ,
938: not counting the final
939: .Dv NULL
940: pointer.
941: .It argv
942: If
943: .No non- Ns Dv NULL ,
944: an argument vector describing a command the user
945: wishes to check against the policy in the same form as what would
946: be passed to the
947: .Xr execve 2
948: system call.
949: If the command is permitted by the policy, the fully-qualified path
950: to the command should be displayed along with any command line arguments.
951: .El
952: .It validate
953: .Bd -literal -compact
954: int (*validate)(void);
955: .Ed
956: .Pp
957: The
958: .Fn validate
959: function is called when
960: .Nm sudo
961: is run with the
962: .Fl v
963: flag.
964: For policy plugins such as
965: .Nm sudoers
966: that cache
967: authentication credentials, this function will validate and cache
968: the credentials.
969: .Pp
970: The
971: .Fn validate
972: function should be
973: .Dv NULL
974: if the plugin does not support credential caching.
975: .Pp
976: Returns 1 on success, 0 on failure and \-1 on error.
977: On error, the plugin may optionally call the
978: .Fn conversation
979: or
980: .Fn plugin_printf
981: function with
982: .Dv SUDO_CONF_ERROR_MSG
983: to present additional
984: error information to the user.
985: .It invalidate
986: .Bd -literal -compact
987: void (*invalidate)(int remove);
988: .Ed
989: .Pp
990: The
991: .Fn invalidate
992: function is called when
993: .Nm sudo
994: is called with
995: the
996: .Fl k
997: or
998: .Fl K
999: flag.
1000: For policy plugins such as
1001: .Nm sudoers
1002: that
1003: cache authentication credentials, this function will invalidate the
1004: credentials.
1005: If the
1006: .Em remove
1007: flag is set, the plugin may remove
1008: the credentials instead of simply invalidating them.
1009: .Pp
1010: The
1011: .Fn invalidate
1012: function should be
1013: .Dv NULL
1014: if the plugin does not support credential caching.
1015: .It init_session
1016: .Bd -literal -compact
1017: int (*init_session)(struct passwd *pwd, char **user_envp[);
1018: .Ed
1019: .Pp
1020: The
1021: .Fn init_session
1022: function is called before
1023: .Nm sudo
1024: sets up the
1025: execution environment for the command.
1026: It is run in the parent
1027: .Nm sudo
1028: process and before any uid or gid changes.
1029: This can be used to perform session setup that is not supported by
1030: .Em command_info ,
1031: such as opening the PAM session.
1032: The
1033: .Fn close
1034: function can be
1035: used to tear down the session that was opened by
1036: .Li init_session .
1037: .Pp
1038: The
1039: .Em pwd
1040: argument points to a passwd struct for the user the
1041: command will be run as if the uid the command will run as was found
1042: in the password database, otherwise it will be
1043: .Dv NULL .
1044: .Pp
1045: The
1046: .Em user_env
1047: argument points to the environment the command will
1048: run in, in the form of a
1049: .Dv NULL Ns -terminated
1050: vector of
1051: .Dq name=value
1052: strings.
1053: This is the same string passed back to the front end via
1054: the Policy Plugin's
1055: .Em user_env_out
1056: parameter.
1057: If the
1058: .Fn init_session
1059: function needs to modify the user environment, it should update the
1060: pointer stored in
1061: .Em user_env .
1062: The expected use case is to merge the contents of the PAM environment
1063: (if any) with the contents of
1064: .Em user_env .
1065: NOTE: the
1066: .Em user_env
1067: parameter is only available
1068: starting with API version 1.2.
1069: A plugin
1070: .Sy must
1071: check the API
1072: version specified by the
1073: .Nm sudo
1074: front end before using
1075: .Em user_env .
1076: Failure to do so may result in a crash.
1077: .Pp
1078: Returns 1 on success, 0 on failure and \-1 on error.
1079: On error, the plugin may optionally call the
1080: .Fn conversation
1081: or
1082: .Fn plugin_printf
1083: function with
1084: .Dv SUDO_CONF_ERROR_MSG
1085: to present additional
1086: error information to the user.
1087: .It register_hooks
1088: .Bd -literal -compact
1089: void (*register_hooks)(int version,
1090: int (*register_hook)(struct sudo_hook *hook));
1091: .Ed
1092: .Pp
1093: The
1094: .Fn register_hooks
1095: function is called by the sudo front end to
1096: register any hooks the plugin needs.
1097: If the plugin does not support hooks,
1098: .Li register_hooks
1099: should be set to the
1100: .Dv NULL
1101: pointer.
1102: .Pp
1103: The
1104: .Em version
1105: argument describes the version of the hooks API
1106: supported by the
1107: .Nm sudo
1108: front end.
1109: .Pp
1110: The
1111: .Fn register_hook
1112: function should be used to register any supported
1113: hooks the plugin needs.
1114: It returns 0 on success, 1 if the hook type is not supported and \-1
1115: if the major version in
1116: .Li struct hook
1117: does not match the front end's major hook API version.
1118: .Pp
1119: See the
1120: .Sx Hook function API
1121: section below for more information
1122: about hooks.
1123: .Pp
1124: NOTE: the
1125: .Fn register_hooks
1126: function is only available starting
1127: with API version 1.2.
1128: If the
1129: .Nm sudo
1130: front end doesn't support API
1131: version 1.2 or higher,
1132: .Li register_hooks
1133: will not be called.
1134: .It deregister_hooks
1135: .Bd -literal -compact
1136: void (*deregister_hooks)(int version,
1137: int (*deregister_hook)(struct sudo_hook *hook));
1138: .Ed
1139: .Pp
1140: The
1141: .Fn deregister_hooks
1142: function is called by the sudo front end
1143: to deregister any hooks the plugin has registered.
1144: If the plugin does not support hooks,
1145: .Li deregister_hooks
1146: should be set to the
1147: .Dv NULL
1148: pointer.
1149: .Pp
1150: The
1151: .Em version
1152: argument describes the version of the hooks API
1153: supported by the
1154: .Nm sudo
1155: front end.
1156: .Pp
1157: The
1158: .Fn deregister_hook
1159: function should be used to deregister any
1160: hooks that were put in place by the
1161: .Fn register_hook
1162: function.
1163: If the plugin tries to deregister a hook that the front end does not support,
1164: .Li deregister_hook
1165: will return an error.
1166: .Pp
1167: See the
1168: .Sx Hook function API
1169: section below for more information
1170: about hooks.
1171: .Pp
1172: NOTE: the
1173: .Fn deregister_hooks
1174: function is only available starting
1175: with API version 1.2.
1176: If the
1177: .Nm sudo
1178: front end doesn't support API
1179: version 1.2 or higher,
1180: .Li deregister_hooks
1181: will not be called.
1182: .El
1183: .Pp
1184: .Em Policy Plugin Version Macros
1185: .Bd -literal
1186: /* Plugin API version major/minor. */
1187: #define SUDO_API_VERSION_MAJOR 1
1188: #define SUDO_API_VERSION_MINOR 2
1189: #define SUDO_API_MKVERSION(x, y) ((x << 16) | y)
1190: #define SUDO_API_VERSION SUDO_API_MKVERSION(SUDO_API_VERSION_MAJOR,\e
1191: SUDO_API_VERSION_MINOR)
1192:
1193: /* Getters and setters for API version */
1194: #define SUDO_API_VERSION_GET_MAJOR(v) ((v) >> 16)
1195: #define SUDO_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
1196: #define SUDO_API_VERSION_SET_MAJOR(vp, n) do { \e
1197: *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e
1198: } while(0)
1199: #define SUDO_VERSION_SET_MINOR(vp, n) do { \e
1200: *(vp) = (*(vp) & 0xffff0000) | (n); \e
1201: } while(0)
1202: .Ed
1203: .Ss I/O plugin API
1204: .Bd -literal
1205: struct io_plugin {
1206: #define SUDO_IO_PLUGIN 2
1207: unsigned int type; /* always SUDO_IO_PLUGIN */
1208: unsigned int version; /* always SUDO_API_VERSION */
1209: int (*open)(unsigned int version, sudo_conv_t conversation,
1210: sudo_printf_t plugin_printf, char * const settings[],
1211: char * const user_info[], char * const command_info[],
1212: int argc, char * const argv[], char * const user_env[],
1213: char * const plugin_options[]);
1214: void (*close)(int exit_status, int error); /* wait status or error */
1215: int (*show_version)(int verbose);
1216: int (*log_ttyin)(const char *buf, unsigned int len);
1217: int (*log_ttyout)(const char *buf, unsigned int len);
1218: int (*log_stdin)(const char *buf, unsigned int len);
1219: int (*log_stdout)(const char *buf, unsigned int len);
1220: int (*log_stderr)(const char *buf, unsigned int len);
1221: void (*register_hooks)(int version,
1222: int (*register_hook)(struct sudo_hook *hook));
1223: void (*deregister_hooks)(int version,
1224: int (*deregister_hook)(struct sudo_hook *hook));
1225: };
1226: .Ed
1227: .Pp
1228: When an I/O plugin is loaded,
1229: .Nm sudo
1230: runs the command in a pseudo-tty.
1231: This makes it possible to log the input and output from the user's
1232: session.
1233: If any of the standard input, standard output or standard error do not
1234: correspond to a tty,
1235: .Nm sudo
1236: will open a pipe to capture
1237: the I/O for logging before passing it on.
1238: .Pp
1239: The log_ttyin function receives the raw user input from the terminal
1240: device (note that this will include input even when echo is disabled,
1241: such as when a password is read).
1242: The log_ttyout function receives output from the pseudo-tty that is
1243: suitable for replaying the user's session at a later time.
1244: The
1245: .Fn log_stdin ,
1246: .Fn log_stdout
1247: and
1248: .Fn log_stderr
1249: functions are only called if the standard input, standard output
1250: or standard error respectively correspond to something other than
1251: a tty.
1252: .Pp
1253: Any of the logging functions may be set to the
1254: .Dv NULL
1255: pointer if no logging is to be performed.
1256: If the open function returns 0, no I/O will be sent to the plugin.
1257: .Pp
1258: The io_plugin struct has the following fields:
1259: .Bl -tag -width 4n
1260: .It type
1261: The
1262: .Li type
1263: field should always be set to
1264: .Dv SUDO_IO_PLUGIN .
1265: .It version
1266: The
1267: .Li version
1268: field should be set to
1269: .Dv SUDO_API_VERSION .
1270: .Pp
1271: This allows
1272: .Nm sudo
1273: to determine the API version the plugin was
1274: built against.
1275: .It open
1276: .Bd -literal -compact
1277: int (*open)(unsigned int version, sudo_conv_t conversation,
1278: sudo_printf_t plugin_printf, char * const settings[],
1279: char * const user_info[], int argc, char * const argv[],
1280: char * const user_env[], char * const plugin_options[]);
1281: .Ed
1282: .Pp
1283: The
1284: .Fn open
1285: function is run before the
1286: .Fn log_input ,
1287: .Fn log_output
1288: or
1289: .Fn show_version
1290: functions are called.
1291: It is only called if the version is being requested or the
1292: .Fn check_policy
1293: function has
1294: returned successfully.
1295: It returns 1 on success, 0 on failure, \-1 if a general error occurred,
1296: or \-2 if there was a usage error.
1297: In the latter case,
1298: .Nm sudo
1299: will print a usage message before it exits.
1300: If an error occurs, the plugin may optionally call the
1301: .Fn conversation
1302: or
1303: .Fn plugin_printf
1304: function with
1305: .Dv SUDO_CONF_ERROR_MSG
1306: to present
1307: additional error information to the user.
1308: .Pp
1309: The function arguments are as follows:
1310: .Bl -tag -width 4n
1311: .It version
1312: The version passed in by
1313: .Nm sudo
1314: allows the plugin to determine the
1315: major and minor version number of the plugin API supported by
1316: .Nm sudo .
1317: .It conversation
1318: A pointer to the
1319: .Fn conversation
1320: function that may be used by the
1321: .Fn show_version
1322: function to display version information (see
1323: .Fn show_version
1324: below).
1325: The
1326: .Fn conversation
1327: function may also be used to display additional error message to the user.
1328: The
1329: .Fn conversation
1330: function returns 0 on success and \-1 on failure.
1331: .It plugin_printf
1332: A pointer to a
1333: .Fn printf Ns -style
1334: function that may be used by the
1335: .Fn show_version
1336: function to display version information (see
1337: show_version below).
1338: The
1339: .Fn plugin_printf
1340: function may also be used to display additional error message to the user.
1341: The
1342: .Fn plugin_printf
1343: function returns number of characters printed on success and \-1 on failure.
1344: .It settings
1345: A vector of user-supplied
1346: .Nm sudo
1347: settings in the form of
1348: .Dq name=value
1349: strings.
1350: The vector is terminated by a
1351: .Dv NULL
1352: pointer.
1353: These settings correspond to flags the user specified when running
1354: .Nm sudo .
1355: As such, they will only be present when the corresponding flag has
1356: been specified on the command line.
1357: .Pp
1358: When parsing
1359: .Em settings ,
1360: the plugin should split on the
1361: .Sy first
1362: equal sign
1363: .Pq Ql =
1364: since the
1365: .Em name
1366: field will never include one
1367: itself but the
1368: .Em value
1369: might.
1370: .Pp
1371: See the
1372: .Sx Policy plugin API
1373: section for a list of all possible settings.
1374: .It user_info
1375: A vector of information about the user running the command in the form of
1376: .Dq name=value
1377: strings.
1378: The vector is terminated by a
1379: .Dv NULL
1380: pointer.
1381: .Pp
1382: When parsing
1383: .Em user_info ,
1384: the plugin should split on the
1385: .Sy first
1386: equal sign
1387: .Pq Ql =
1388: since the
1389: .Em name
1390: field will never include one
1391: itself but the
1392: .Em value
1393: might.
1394: .Pp
1395: See the
1396: .Sx Policy plugin API
1397: section for a list of all possible strings.
1398: .It argc
1399: The number of elements in
1400: .Em argv ,
1401: not counting the final
1402: .Dv NULL
1403: pointer.
1404: .It argv
1405: If
1406: .No non- Ns Dv NULL ,
1407: an argument vector describing a command the user
1408: wishes to run in the same form as what would be passed to the
1409: .Xr execve 2
1410: system call.
1411: .It user_env
1412: The user's environment in the form of a
1413: .Dv NULL Ns -terminated
1414: vector of
1415: .Dq name=value
1416: strings.
1417: .Pp
1418: When parsing
1419: .Em user_env ,
1420: the plugin should split on the
1421: .Sy first
1422: equal sign
1423: .Pq Ql =
1424: since the
1425: .Em name
1426: field will never include one
1427: itself but the
1428: .Em value
1429: might.
1430: .It plugin_options
1431: Any (non-comment) strings immediately after the plugin path are
1432: treated as arguments to the plugin.
1433: These arguments are split on a white space boundary and are passed to
1434: the plugin in the form of a
1435: .Dv NULL Ns -terminated
1436: array of strings.
1437: If no arguments were specified,
1438: .Em plugin_options
1439: will be the
1440: .Dv NULL
1441: pointer.
1442: .Pp
1443: NOTE: the
1444: .Em plugin_options
1445: parameter is only available starting with
1446: API version 1.2.
1447: A plugin
1448: .Sy must
1449: check the API version specified
1450: by the
1451: .Nm sudo
1452: front end before using
1453: .Em plugin_options .
1454: Failure to do so may result in a crash.
1455: .El
1456: .It close
1457: .Bd -literal -compact
1458: void (*close)(int exit_status, int error);
1459: .Ed
1460: .Pp
1461: The
1462: .Fn close
1463: function is called when the command being run by
1464: .Nm sudo
1465: finishes.
1466: .Pp
1467: The function arguments are as follows:
1468: .Bl -tag -width 4n
1469: .It exit_status
1470: The command's exit status, as returned by the
1471: .Xr wait 2
1472: system call.
1473: The value of
1474: .Li exit_status
1475: is undefined if
1476: .Li error
1477: is non-zero.
1478: .It error
1479: If the command could not be executed, this is set to the value of
1480: .Li errno
1481: set by the
1482: .Xr execve 2
1483: system call.
1484: If the command was successfully executed, the value of
1485: .Li error
1486: is 0.
1487: .El
1488: .It show_version
1489: .Bd -literal -compact
1490: int (*show_version)(int verbose);
1491: .Ed
1492: .Pp
1493: The
1494: .Fn show_version
1495: function is called by
1496: .Nm sudo
1497: when the user specifies
1498: the
1499: .Fl V
1500: option.
1501: The plugin may display its version information to the user via the
1502: .Fn conversation
1503: or
1504: .Fn plugin_printf
1505: function using
1506: .Dv SUDO_CONV_INFO_MSG .
1507: If the user requests detailed version information, the verbose flag will be set.
1508: .It log_ttyin
1509: .Bd -literal -compact
1510: int (*log_ttyin)(const char *buf, unsigned int len);
1511: .Ed
1512: .Pp
1513: The
1514: .Fn log_ttyin
1515: function is called whenever data can be read from
1516: the user but before it is passed to the running command.
1517: This allows the plugin to reject data if it chooses to (for instance
1518: if the input contains banned content).
1519: Returns 1 if the data should be passed to the command, 0 if the data
1520: is rejected (which will terminate the command) or \-1 if an error occurred.
1521: .Pp
1522: The function arguments are as follows:
1523: .Bl -tag -width 4n
1524: .It buf
1525: The buffer containing user input.
1526: .It len
1527: The length of
1528: .Em buf
1529: in bytes.
1530: .El
1531: .It log_ttyout
1532: .Bd -literal -compact
1533: int (*log_ttyout)(const char *buf, unsigned int len);
1534: .Ed
1535: .Pp
1536: The
1537: .Fn log_ttyout
1538: function is called whenever data can be read from
1539: the command but before it is written to the user's terminal.
1540: This allows the plugin to reject data if it chooses to (for instance
1541: if the output contains banned content).
1542: Returns 1 if the data should be passed to the user, 0 if the data is rejected
1543: (which will terminate the command) or \-1 if an error occurred.
1544: .Pp
1545: The function arguments are as follows:
1546: .Bl -tag -width 4n
1547: .It buf
1548: The buffer containing command output.
1549: .It len
1550: The length of
1551: .Em buf
1552: in bytes.
1553: .El
1554: .It log_stdin
1555: .Bd -literal -compact
1556: int (*log_stdin)(const char *buf, unsigned int len);
1557: .Ed
1558: .Pp
1559: The
1560: .Fn log_stdin
1561: function is only used if the standard input does
1562: not correspond to a tty device.
1563: It is called whenever data can be read from the standard input but
1564: before it is passed to the running command.
1565: This allows the plugin to reject data if it chooses to
1566: (for instance if the input contains banned content).
1567: Returns 1 if the data should be passed to the command, 0 if the data is
1568: rejected (which will terminate the command) or \-1 if an error occurred.
1569: .Pp
1570: The function arguments are as follows:
1571: .Bl -tag -width 4n
1572: .It buf
1573: The buffer containing user input.
1574: .It len
1575: The length of
1576: .Em buf
1577: in bytes.
1578: .El
1579: .It log_stdout
1580: .Bd -literal -compact
1581: int (*log_stdout)(const char *buf, unsigned int len);
1582: .Ed
1583: .Pp
1584: The
1585: .Fn log_stdout
1586: function is only used if the standard output does not correspond
1587: to a tty device.
1588: It is called whenever data can be read from the command but before
1589: it is written to the standard output.
1590: This allows the plugin to reject data if it chooses to
1591: (for instance if the output contains banned content).
1592: Returns 1 if the data should be passed to the user, 0 if the data is
1593: rejected (which will terminate the command) or \-1 if an error occurred.
1594: .Pp
1595: The function arguments are as follows:
1596: .Bl -tag -width 4n
1597: .It buf
1598: The buffer containing command output.
1599: .It len
1600: The length of
1601: .Em buf
1602: in bytes.
1603: .El
1604: .It log_stderr
1605: .Bd -literal -compact
1606: int (*log_stderr)(const char *buf, unsigned int len);
1607: .Ed
1608: .Pp
1609: The
1610: .Fn log_stderr
1611: function is only used if the standard error does
1612: not correspond to a tty device.
1613: It is called whenever data can be read from the command but before it
1614: is written to the standard error.
1615: This allows the plugin to reject data if it chooses to
1616: (for instance if the output contains banned content).
1617: Returns 1 if the data should be passed to the user, 0 if the data is
1618: rejected (which will terminate the command) or \-1 if an error occurred.
1619: .Pp
1620: The function arguments are as follows:
1621: .Bl -tag -width 4n
1622: .It buf
1623: The buffer containing command output.
1624: .It len
1625: The length of
1626: .Em buf
1627: in bytes.
1628: .El
1629: .It register_hooks
1630: See the
1631: .Sx Policy plugin API
1632: section for a description of
1633: .Li register_hooks .
1634: .It deregister_hooks
1635: See the
1636: .Sx Policy plugin API
1637: section for a description of
1638: .Li deregister_hooks.
1639: .El
1640: .Pp
1641: .Em I/O Plugin Version Macros
1642: .Pp
1643: Same as for the
1644: .Sx Policy plugin API .
1645: .Ss Signal handlers
1646: The
1647: .Nm sudo
1648: front end installs default signal handlers to trap common signals
1649: while the plugin functions are run.
1650: The following signals are trapped by default before the command is
1651: executed:
1652: .Pp
1653: .Bl -bullet -compact
1654: .It
1655: .Dv SIGALRM
1656: .It
1657: .Dv SIGHUP
1658: .It
1659: .Dv SIGINT
1660: .It
1661: .Dv SIGQUIT
1662: .It
1663: .Dv SIGTERM
1664: .It
1665: .Dv SIGTSTP
1666: .It
1667: .Dv SIGUSR1
1668: .It
1669: .Dv SIGUSR2
1670: .El
1671: .Pp
1672: If a fatal signal is received before the command is executed,
1673: .Nm sudo
1674: will call the plugin's
1675: .Fn close
1676: function with an exit status of 128 plus the value of the signal
1677: that was received.
1678: This allows for consistent logging of commands killed by a signal
1679: for plugins that log such information in their
1680: .Fn close
1681: function.
1682: .Pp
1683: A plugin may temporarily install its own signal handlers but must
1684: restore the original handler before the plugin function returns.
1685: .Ss Hook function API
1686: Beginning with plugin API version 1.2, it is possible to install
1687: hooks for certain functions called by the
1688: .Nm sudo
1689: front end.
1690: .Pp
1691: Currently, the only supported hooks relate to the handling of
1692: environment variables.
1693: Hooks can be used to intercept attempts to get, set, or remove
1694: environment variables so that these changes can be reflected in
1695: the version of the environment that is used to execute a command.
1696: A future version of the API will support hooking internal
1697: .Nm sudo
1698: front end functions as well.
1699: .Pp
1700: .Em Hook structure
1701: .Pp
1702: Hooks in
1703: .Nm sudo
1704: are described by the following structure:
1705: .Bd -literal
1706: typedef int (*sudo_hook_fn_t)();
1707:
1708: struct sudo_hook {
1709: int hook_version;
1710: int hook_type;
1711: sudo_hook_fn_t hook_fn;
1712: void *closure;
1713: };
1714: .Ed
1715: .Pp
1716: The
1717: .Li sudo_hook
1718: structure has the following fields:
1719: .Bl -tag -width 4n
1720: .It hook_version
1721: The
1722: .Li hook_version
1723: field should be set to
1724: .Dv SUDO_HOOK_VERSION .
1725: .It hook_type
1726: The
1727: .Li hook_type
1728: field may be one of the following supported hook types:
1729: .Bl -tag -width 4n
1730: .It Dv SUDO_HOOK_SETENV
1731: The C library
1732: .Xr setenv 3
1733: function.
1734: Any registered hooks will run before the C library implementation.
1735: The
1736: .Li hook_fn
1737: field should
1738: be a function that matches the following typedef:
1739: .Bd -literal
1740: typedef int (*sudo_hook_fn_setenv_t)(const char *name,
1741: const char *value, int overwrite, void *closure);
1742: .Ed
1743: .Pp
1744: If the registered hook does not match the typedef the results are
1745: unspecified.
1746: .It Dv SUDO_HOOK_UNSETENV
1747: The C library
1748: .Xr unsetenv 3
1749: function.
1750: Any registered hooks will run before the C library implementation.
1751: The
1752: .Li hook_fn
1753: field should
1754: be a function that matches the following typedef:
1755: .Bd -literal
1756: typedef int (*sudo_hook_fn_unsetenv_t)(const char *name,
1757: void *closure);
1758: .Ed
1759: .It Dv SUDO_HOOK_GETENV
1760: The C library
1761: .Xr getenv 3
1762: function.
1763: Any registered hooks will run before the C library implementation.
1764: The
1765: .Li hook_fn
1766: field should
1767: be a function that matches the following typedef:
1768: .Bd -literal
1769: typedef int (*sudo_hook_fn_getenv_t)(const char *name,
1770: char **value, void *closure);
1771: .Ed
1772: .Pp
1773: If the registered hook does not match the typedef the results are
1774: unspecified.
1775: .It Dv SUDO_HOOK_PUTENV
1776: The C library
1777: .Xr putenv 3
1778: function.
1779: Any registered hooks will run before the C library implementation.
1780: The
1781: .Li hook_fn
1782: field should
1783: be a function that matches the following typedef:
1784: .Bd -literal
1785: typedef int (*sudo_hook_fn_putenv_t)(char *string,
1786: void *closure);
1787: .Ed
1788: .Pp
1789: If the registered hook does not match the typedef the results are
1790: unspecified.
1791: .El
1792: .It hook_fn
1793: sudo_hook_fn_t hook_fn;
1794: .Pp
1795: The
1796: .Li hook_fn
1797: field should be set to the plugin's hook implementation.
1798: The actual function arguments will vary depending on the
1799: .Li hook_type
1800: (see
1801: .Li hook_type
1802: above).
1803: In all cases, the
1804: .Li closure
1805: field of
1806: .Li struct sudo_hook
1807: is passed as the last function parameter.
1808: This can be used to pass arbitrary data to the plugin's hook implementation.
1809: .Pp
1810: The function return value may be one of the following:
1811: .Bl -tag -width 4n
1812: .It Dv SUDO_HOOK_RET_ERROR
1813: The hook function encountered an error.
1814: .It Dv SUDO_HOOK_RET_NEXT
1815: The hook completed without error, go on to the next hook (including
1816: the native implementation if applicable).
1817: For example, a
1818: .Xr getenv 3
1819: hook might return
1820: .Dv SUDO_HOOK_RET_NEXT
1821: if the specified variable was not found in the private copy of the environment.
1822: .It Dv SUDO_HOOK_RET_STOP
1823: The hook completed without error, stop processing hooks for this invocation.
1824: This can be used to replace the native implementation.
1825: For example, a
1826: .Li setenv
1827: hook that operates on a private copy of
1828: the environment but leaves
1829: .Li environ
1830: unchanged.
1831: .El
1832: .El
1833: .Pp
1834: Note that it is very easy to create an infinite loop when hooking
1835: C library functions.
1836: For example, a
1837: .Xr getenv 3
1838: hook that calls the
1839: .Xr snprintf 3
1840: function may create a loop if the
1841: .Xr snprintf 3
1842: implementation calls
1843: .Xr getenv 3
1844: to check the locale.
1845: To prevent this, you may wish to use a static variable in the hook
1846: function to guard against nested calls.
1847: For example:
1848: .Bd -literal
1849: static int in_progress = 0; /* avoid recursion */
1850: if (in_progress)
1851: return SUDO_HOOK_RET_NEXT;
1852: in_progress = 1;
1853: \&...
1854: in_progress = 0;
1855: return SUDO_HOOK_RET_STOP;
1856: .Ed
1857: .Pp
1858: .Em Hook API Version Macros
1859: .Bd -literal
1860: /* Hook API version major/minor */
1861: #define SUDO_HOOK_VERSION_MAJOR 1
1862: #define SUDO_HOOK_VERSION_MINOR 0
1863: #define SUDO_HOOK_MKVERSION(x, y) ((x << 16) | y)
1864: #define SUDO_HOOK_VERSION SUDO_HOOK_MKVERSION(SUDO_HOOK_VERSION_MAJOR,\e
1865: SUDO_HOOK_VERSION_MINOR)
1866:
1867: /* Getters and setters for hook API version */
1868: #define SUDO_HOOK_VERSION_GET_MAJOR(v) ((v) >> 16)
1869: #define SUDO_HOOK_VERSION_GET_MINOR(v) ((v) & 0xffff)
1870: #define SUDO_HOOK_VERSION_SET_MAJOR(vp, n) do { \e
1871: *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e
1872: } while(0)
1873: #define SUDO_HOOK_VERSION_SET_MINOR(vp, n) do { \e
1874: *(vp) = (*(vp) & 0xffff0000) | (n); \e
1875: } while(0)
1876: .Ed
1877: .Ss Remote command execution
1878: The
1879: .Nm sudo
1880: front end does not have native support for running remote commands.
1881: However, starting with
1882: .Nm sudo
1883: 1.8.8, the
1884: .Fl h
1885: option may be used to specify a remote host that is passed
1886: to the policy plugin.
1887: A plugin may also accept a
1888: .Em runas_user
1889: in the form of
1890: .Dq user@hostname
1891: which will work with older versions of
1892: .Nm sudo .
1893: It is anticipated that remote commands will be supported by executing a
1894: .Dq helper
1895: program.
1896: The policy plugin should setup the execution environment such that the
1897: .Nm sudo
1898: front end will run the helper which, in turn, will connect to the
1899: remote host and run the command.
1900: .Pp
1901: For example, the policy plugin could utilize
1902: .Nm ssh
1903: to perform remote command execution.
1904: The helper program would be responsible for running
1905: .Nm ssh
1906: with the proper options to use a private key or certificate
1907: that the remote host will accept and run a program
1908: on the remote host that would setup the execution environment
1909: accordingly.
1910: .Pp
1911: Note that remote
1912: .Nm sudoedit
1913: functionality must be handled by the policy plugin, not
1914: .Nm sudo
1915: itself as the front end has no knowledge that a remote command is
1916: being executed.
1917: This may be addressed in a future revision of the plugin API.
1918: .Ss Conversation API
1919: If the plugin needs to interact with the user, it may do so via the
1920: .Fn conversation
1921: function.
1922: A plugin should not attempt to read directly from the standard input
1923: or the user's tty (neither of which are guaranteed to exist).
1924: The caller must include a trailing newline in
1925: .Li msg
1926: if one is to be printed.
1927: .Pp
1928: A
1929: .Fn printf Ns -style
1930: function is also available that can be used to display informational
1931: or error messages to the user, which is usually more convenient for
1932: simple messages where no use input is required.
1933: .Bd -literal
1934: struct sudo_conv_message {
1935: #define SUDO_CONV_PROMPT_ECHO_OFF 0x0001 /* do not echo user input */
1936: #define SUDO_CONV_PROMPT_ECHO_ON 0x0002 /* echo user input */
1937: #define SUDO_CONV_ERROR_MSG 0x0003 /* error message */
1938: #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */
1939: #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */
1940: #define SUDO_CONV_DEBUG_MSG 0x0006 /* debugging message */
1941: #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */
1942: int msg_type;
1943: int timeout;
1944: const char *msg;
1945: };
1946:
1947: #define SUDO_CONV_REPL_MAX 255
1948:
1949: struct sudo_conv_reply {
1950: char *reply;
1951: };
1952:
1953: typedef int (*sudo_conv_t)(int num_msgs,
1954: const struct sudo_conv_message msgs[],
1955: struct sudo_conv_reply replies[]);
1956:
1957: typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
1958: .Ed
1959: .Pp
1960: Pointers to the
1961: .Fn conversation
1962: and
1963: .Fn printf Ns -style
1964: functions are passed
1965: in to the plugin's
1966: .Fn open
1967: function when the plugin is initialized.
1968: .Pp
1969: To use the
1970: .Fn conversation
1971: function, the plugin must pass an array of
1972: .Li sudo_conv_message
1973: and
1974: .Li sudo_conv_reply
1975: structures.
1976: There must be a
1977: .Li struct sudo_conv_message
1978: and
1979: .Li struct sudo_conv_reply
1980: for
1981: each message in the conversation.
1982: The plugin is responsible for freeing the reply buffer located in each
1983: .Li struct sudo_conv_reply ,
1984: if it is not
1985: .Dv NULL .
1986: .Dv SUDO_CONV_REPL_MAX
1987: represents the maximum length of the reply buffer (not including
1988: the trailing NUL character).
1989: In practical terms, this is the longest password
1990: .Nm sudo
1991: will support.
1992: It is also useful as a maximum value for the
1993: .Fn memset_s
1994: function when clearing passwords filled in by the conversation function.
1995: .Pp
1996: The
1997: .Fn printf Ns -style
1998: function uses the same underlying mechanism as the
1999: .Fn conversation
2000: function but only supports
2001: .Dv SUDO_CONV_INFO_MSG ,
2002: .Dv SUDO_CONV_ERROR_MSG
2003: and
2004: .Dv SUDO_CONV_DEBUG_MSG
2005: for the
2006: .Em msg_type
2007: parameter.
2008: It can be more convenient than using the
2009: .Fn conversation
2010: function if no user reply is needed and supports standard
2011: .Fn printf
2012: escape sequences.
2013: .Pp
2014: Unlike,
2015: .Dv SUDO_CONV_INFO_MSG
2016: and
2017: Dv SUDO_CONV_ERROR_MSG ,
2018: messages
2019: sent with the
2020: .Dv SUDO_CONV_DEBUG_MSG
2021: .Em msg_type
2022: are not directly
2023: user-visible.
2024: Instead, they are logged to the file specified in the
2025: .Li Debug
2026: statement (if any) in the
2027: .Xr sudo.conf @mansectform@ .
2028: file.
2029: This allows a plugin to log debugging information and is intended
2030: to be used in conjunction with the
2031: .Em debug_flags
2032: setting.
2033: .Pp
2034: See the sample plugin for an example of the
2035: .Fn conversation
2036: function usage.
2037: .Ss Sudoers group plugin API
2038: The
2039: .Nm sudoers
2040: plugin supports its own plugin interface to allow non-Unix
2041: group lookups.
2042: This can be used to query a group source other than the standard Unix
2043: group database.
2044: Two sample group plugins are bundled with
2045: .Nm sudo ,
2046: .Em group_file
2047: and
2048: .Em system_group ,
2049: are detailed in
2050: .Xr sudoers @mansectform@ .
2051: Third party group plugins include a QAS AD plugin available from Quest Software.
2052: .Pp
2053: A group plugin must declare and populate a
2054: .Li sudoers_group_plugin
2055: struct in the global scope.
2056: This structure contains pointers to the functions that implement plugin
2057: initialization, cleanup and group lookup.
2058: .Bd -literal
2059: struct sudoers_group_plugin {
2060: unsigned int version;
2061: int (*init)(int version, sudo_printf_t sudo_printf,
2062: char *const argv[]);
2063: void (*cleanup)(void);
2064: int (*query)(const char *user, const char *group,
2065: const struct passwd *pwd);
2066: };
2067: .Ed
2068: .Pp
2069: The
2070: .Li sudoers_group_plugin
2071: struct has the following fields:
2072: .Bl -tag -width 4n
2073: .It version
2074: The
2075: .Li version
2076: field should be set to GROUP_API_VERSION.
2077: .Pp
2078: This allows
2079: .Nm sudoers
2080: to determine the API version the group plugin
2081: was built against.
2082: .It init
2083: .Bd -literal -compact
2084: int (*init)(int version, sudo_printf_t plugin_printf,
2085: char *const argv[]);
2086: .Ed
2087: .Pp
2088: The
2089: .Fn init
2090: function is called after
2091: .Em sudoers
2092: has been parsed but
2093: before any policy checks.
2094: It returns 1 on success, 0 on failure (or if the plugin is not configured),
2095: and \-1 if a error occurred.
2096: If an error occurs, the plugin may call the
2097: .Fn plugin_printf
2098: function with
2099: .Dv SUDO_CONF_ERROR_MSG
2100: to present additional error information
2101: to the user.
2102: .Pp
2103: The function arguments are as follows:
2104: .Bl -tag -width 4n
2105: .It version
2106: The version passed in by
2107: .Nm sudoers
2108: allows the plugin to determine the
2109: major and minor version number of the group plugin API supported by
2110: .Nm sudoers .
2111: .It plugin_printf
2112: A pointer to a
2113: .Fn printf Ns -style
2114: function that may be used to display informational or error message to the user.
2115: Returns the number of characters printed on success and \-1 on failure.
2116: .It argv
2117: A
2118: .Dv NULL Ns -terminated
2119: array of arguments generated from the
2120: .Em group_plugin
2121: option in
2122: .Em sudoers .
2123: If no arguments were given,
2124: .Em argv
2125: will be
2126: .Dv NULL .
2127: .El
2128: .It cleanup
2129: .Bd -literal -compact
2130: void (*cleanup)();
2131: .Ed
2132: .Pp
2133: The
2134: .Fn cleanup
2135: function is called when
2136: .Nm sudoers
2137: has finished its
2138: group checks.
2139: The plugin should free any memory it has allocated and close open file handles.
2140: .It query
2141: .Bd -literal -compact
2142: int (*query)(const char *user, const char *group,
2143: const struct passwd *pwd);
2144: .Ed
2145: .Pp
2146: The
2147: .Fn query
2148: function is used to ask the group plugin whether
2149: .Em user
2150: is a member of
2151: .Em group .
2152: .Pp
2153: The function arguments are as follows:
2154: .Bl -tag -width 4n
2155: .It user
2156: The name of the user being looked up in the external group database.
2157: .It group
2158: The name of the group being queried.
2159: .It pwd
2160: The password database entry for
2161: .Em user ,
2162: if any.
2163: If
2164: .Em user
2165: is not
2166: present in the password database,
2167: .Em pwd
2168: will be
2169: .Dv NULL .
2170: .El
2171: .El
2172: .Pp
2173: .Em Group API Version Macros
2174: .Bd -literal
2175: /* Sudoers group plugin version major/minor */
2176: #define GROUP_API_VERSION_MAJOR 1
2177: #define GROUP_API_VERSION_MINOR 0
2178: #define GROUP_API_VERSION ((GROUP_API_VERSION_MAJOR << 16) | \e
2179: GROUP_API_VERSION_MINOR)
2180:
2181: /* Getters and setters for group version */
2182: #define GROUP_API_VERSION_GET_MAJOR(v) ((v) >> 16)
2183: #define GROUP_API_VERSION_GET_MINOR(v) ((v) & 0xffff)
2184: #define GROUP_API_VERSION_SET_MAJOR(vp, n) do { \e
2185: *(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \e
2186: } while(0)
2187: #define GROUP_API_VERSION_SET_MINOR(vp, n) do { \e
2188: *(vp) = (*(vp) & 0xffff0000) | (n); \e
2189: } while(0)
2190: .Ed
2191: .Sh PLUGIN API CHANGELOG
2192: The following revisions have been made to the Sudo Plugin API.
2193: .Bl -tag -width 4n
2194: .It Version 1.0
2195: Initial API version.
2196: .It Version 1.1 (sudo 1.8.0)
2197: The I/O logging plugin's
2198: .Fn open
2199: function was modified to take the
2200: .Li command_info
2201: list as an argument.
2202: .It Version 1.2 (sudo 1.8.5)
2203: The Policy and I/O logging plugins'
2204: .Fn open
2205: functions are now passed
2206: a list of plugin parameters if any are specified in
2207: .Xr sudo.conf @mansectform@ .
2208: .Pp
2209: A simple hooks API has been introduced to allow plugins to hook in to the
2210: system's environment handling functions.
2211: .Pp
2212: The
2213: .Li init_session
2214: Policy plugin function is now passed a pointer
2215: to the user environment which can be updated as needed.
2216: This can be used to merge in environment variables stored in the PAM
2217: handle before a command is run.
2218: .It Version 1.3 (sudo 1.8.7)
2219: Support for the
2220: .Em exec_background
2221: entry has been added to the
2222: .Li command_info
2223: list.
2224: .Pp
2225: The
2226: .Em max_groups
2227: and
2228: .Em plugin_dir
2229: entries were added to the
2230: .Li settings
2231: list.
2232: .Pp
2233: The
2234: .Fn version
2235: and
2236: .Fn close
2237: functions are now optional.
2238: Previously, a missing
2239: .Fn version
2240: or
2241: .Fn close
2242: function would result in a crash.
2243: If no policy plugin
2244: .Fn close
2245: function is defined, a default
2246: .Fn close
2247: function will be provided by the
2248: .Nm sudo
2249: front end that displays a warning if the command could not be
2250: executed.
2251: .Pp
2252: The
2253: .Nm sudo
2254: front end now installs default signal handlers to trap common signals
2255: while the plugin functions are run.
2256: .It Version 1.4 (sudo 1.8.8)
2257: The
2258: .Em remote_host
2259: entry was added to the
2260: .Li settings
2261: list.
2262: .It Version 1.5 (sudo 1.8.9)
2263: The
2264: .em preserve_fds
2265: entry was added to the
2266: .Li command_info
2267: list.
2268: .El
2269: .Sh SEE ALSO
2270: .Xr sudo.conf @mansectform@ ,
2271: .Xr sudoers @mansectform@ ,
2272: .Xr sudo @mansectsu@
2273: .Sh BUGS
2274: If you feel you have found a bug in
2275: .Nm sudo ,
2276: please submit a bug report at http://www.sudo.ws/sudo/bugs/
2277: .Sh SUPPORT
2278: Limited free support is available via the sudo-users mailing list,
2279: see http://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or
2280: search the archives.
2281: .Sh DISCLAIMER
2282: .Nm sudo
2283: is provided
2284: .Dq AS IS
2285: and any express or implied warranties, including, but not limited
2286: to, the implied warranties of merchantability and fitness for a
2287: particular purpose are disclaimed.
2288: See the LICENSE file distributed with
2289: .Nm sudo
2290: or http://www.sudo.ws/sudo/license.html for complete details.
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>