Annotation of embedaddon/sudo/doc/sudo_plugin.mdoc.in, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>