{
    "content": [
        {
            "type": "text",
            "text": "# sudo_plugin (man)\n\n## NAME\n\nsudoplugin — Sudo Plugin API\n\n## DESCRIPTION\n\nStarting with version 1.8, sudo supports a plugin API for policy and session logging.  Plugins\nmay be compiled as dynamic shared objects (the default on systems that support them) or com‐\npiled statically into the sudo binary itself.  By default, the sudoers plugin provides audit,\nsecurity policy and I/O logging capabilities.  Via the plugin API, sudo can be configured to\nuse alternate plugins provided by third parties.  The plugins to be used are specified in the\nsudo.conf(5) file.\n\n## Sections\n\n- **NAME**\n- **DESCRIPTION** (11 subsections)\n- **PLUGIN API CHANGELOG**\n- **SEE ALSO**\n- **AUTHORS**\n- **BUGS**\n- **SUPPORT**\n- **DISCLAIMER**\n- **Sudo 1.9.9                     January 20, 2022                     Sudo 1.9.9**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "sudo_plugin",
        "section": "",
        "mode": "man",
        "summary": "sudoplugin — Sudo Plugin API",
        "synopsis": null,
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [],
        "see_also": [
            {
                "name": "sudo.conf",
                "section": "5",
                "url": "https://www.chedong.com/phpMan.php/man/sudo.conf/5/json"
            },
            {
                "name": "sudoers",
                "section": "5",
                "url": "https://www.chedong.com/phpMan.php/man/sudoers/5/json"
            },
            {
                "name": "sudo",
                "section": "8",
                "url": "https://www.chedong.com/phpMan.php/man/sudo/8/json"
            }
        ],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "DESCRIPTION",
                "lines": 13,
                "subsections": [
                    {
                        "name": "Policy plugin API",
                        "lines": 985
                    },
                    {
                        "name": "I/O plugin API",
                        "lines": 393
                    },
                    {
                        "name": "Audit plugin API",
                        "lines": 297
                    },
                    {
                        "name": "Approval plugin API",
                        "lines": 171
                    },
                    {
                        "name": "Signal handlers",
                        "lines": 23
                    },
                    {
                        "name": "Hook function API",
                        "lines": 114
                    },
                    {
                        "name": "Event API",
                        "lines": 142
                    },
                    {
                        "name": "Remote command execution",
                        "lines": 17
                    },
                    {
                        "name": "Conversation API",
                        "lines": 119
                    },
                    {
                        "name": "Plugin invocation order",
                        "lines": 26
                    },
                    {
                        "name": "Sudoers group plugin API",
                        "lines": 79
                    }
                ]
            },
            {
                "name": "PLUGIN API CHANGELOG",
                "lines": 110,
                "subsections": []
            },
            {
                "name": "SEE ALSO",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "AUTHORS",
                "lines": 8,
                "subsections": []
            },
            {
                "name": "BUGS",
                "lines": 3,
                "subsections": []
            },
            {
                "name": "SUPPORT",
                "lines": 3,
                "subsections": []
            },
            {
                "name": "DISCLAIMER",
                "lines": 5,
                "subsections": []
            },
            {
                "name": "Sudo 1.9.9                     January 20, 2022                     Sudo 1.9.9",
                "lines": 1,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "sudoplugin — Sudo Plugin API\n",
                "subsections": []
            },
            "DESCRIPTION": {
                "content": "Starting with version 1.8, sudo supports a plugin API for policy and session logging.  Plugins\nmay be compiled as dynamic shared objects (the default on systems that support them) or com‐\npiled statically into the sudo binary itself.  By default, the sudoers plugin provides audit,\nsecurity policy and I/O logging capabilities.  Via the plugin API, sudo can be configured to\nuse alternate plugins provided by third parties.  The plugins to be used are specified in the\nsudo.conf(5) file.\n\nThe API is versioned with a major and minor number.  The minor version number is incremented\nwhen additions are made.  The major number is incremented when incompatible changes are made.\nA plugin should be check the version passed to it and make sure that the major version matches.\n\nThe plugin API is defined by the sudoplugin.h header file.\n",
                "subsections": [
                    {
                        "name": "Policy plugin API",
                        "content": "A policy plugin must declare and populate a policyplugin struct in the global scope.  This\nstructure contains pointers to the functions that implement the sudo policy checks.  The name\nof the symbol should be specified in sudo.conf(5) along with a path to the plugin so that sudo\ncan load it.\n\nstruct policyplugin {\n#define SUDOPOLICYPLUGIN     1\nunsigned int type; /* always SUDOPOLICYPLUGIN */\nunsigned int version; /* always SUDOAPIVERSION */\nint (*open)(unsigned int version, sudoconvt conversation,\nsudoprintft pluginprintf, char * const settings[],\nchar * const userinfo[], char * const userenv[],\nchar * const pluginoptions[], const char errstr);\nvoid (*close)(int exitstatus, int error);\nint (*showversion)(int verbose);\nint (*checkpolicy)(int argc, char * const argv[],\nchar *envadd[], char commandinfo[],\nchar argvout[], char userenvout[], const char errstr);\nint (*list)(int argc, char * const argv[], int verbose,\nconst char *listuser, const char errstr);\nint (*validate)(const char errstr);\nvoid (*invalidate)(int remove);\nint (*initsession)(struct passwd *pwd, char userenv[],\nconst char errstr);\nvoid (*registerhooks)(int version,\nint (*registerhook)(struct sudohook *hook));\nvoid (*deregisterhooks)(int version,\nint (*deregisterhook)(struct sudohook *hook));\nstruct sudopluginevent * (*eventalloc)(void);\n};\n\nThe policyplugin struct has the following fields:\n\ntype  The type field should always be set to SUDOPOLICYPLUGIN.\n\nversion\nThe version field should be set to SUDOAPIVERSION.\n\nThis allows sudo to determine the API version the plugin was built against.\n\nopen\nint (*open)(unsigned int version, sudoconvt conversation,\nsudoprintft pluginprintf, char * const settings[],\nchar * const userinfo[], char * const userenv[],\nchar * const pluginoptions[], const char errstr);\n\nReturns 1 on success, 0 on failure, -1 if a general error occurred, or -2 if there was a\nusage error.  In the latter case, sudo will print a usage message before it exits.  If an\nerror occurs, the plugin may optionally call the conversation() or pluginprintf() func‐\ntion with SUDOCONFERRORMSG to present additional error information to the user.\n\nThe function arguments are as follows:\n\nversion\nThe version passed in by sudo allows the plugin to determine the major and minor\nversion number of the plugin API supported by sudo.\n\nconversation\nA pointer to the conversation() function that can be used by the plugin to interact\nwith the user (see Conversation API for details).  Returns 0 on success and -1 on\nfailure.\n\npluginprintf\nA pointer to a printf()-style function that may be used to display informational or\nerror messages (see Conversation API for details).  Returns the number of charac‐\nters printed on success and -1 on failure.\n\nsettings\nA vector of user-supplied sudo settings in the form of “name=value” strings.  The\nvector is terminated by a NULL pointer.  These settings correspond to options the\nuser specified when running sudo.  As such, they will only be present when the cor‐\nresponding option has been specified on the command line.\n\nWhen parsing settings, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nThe following values may be set by sudo:\n\nbsdauthtype=string\nAuthentication type, if specified by the -a option, to use on systems where\nBSD authentication is supported.\n\nclosefrom=number\nIf specified, the user has requested via the -C option that sudo close all\nfiles descriptors with a value of number or higher.  The plugin may option‐\nally pass this, or another value, back in the commandinfo list.\n\ncmndchroot=string\nThe root directory (see chroot(2)) to run the command in, as specified by the\nuser via the -R option.  The plugin may ignore or restrict the user's ability\nto specify a new root directory.  Only available starting with API version\n1.16.\n\ncmndcwd=string\nThe working directory to run the command in, as specified by the user via the\n-D option.  The plugin may ignore or restrict the user's ability to specify a\nnew working directory.  Only available starting with API version 1.16.\n\ndebugflags=string\nA debug file path name followed by a space and a comma-separated list of de‐\nbug flags that correspond to the plugin's Debug entry in sudo.conf(5), if\nthere is one.  The flags are passed to the plugin exactly as they appear in\nsudo.conf(5).  The syntax used by sudo and the sudoers plugin is\nsubsystem@priority but a plugin is free to use a different format so long as\nit does not include a comma (‘,’).  Prior to sudo 1.8.12, there was no way to\nspecify plugin-specific debugflags so the value was always the same as that\nused by the sudo front-end and did not include a path name, only the flags\nthemselves.  As of version 1.7 of the plugin interface, sudo will only pass\ndebugflags if sudo.conf(5) contains a plugin-specific Debug entry.\n\nignoreticket=bool\nSet to true if the user specified the -k option along with a command, indi‐\ncating that the user wishes to ignore any cached authentication credentials.\nimpliedshell to true.  This allows sudo with no arguments to be used simi‐\nlarly to su(1).  If the plugin does not to support this usage, it may return\na value of -2 from the checkpolicy() function, which will cause sudo to\nprint a usage message and exit.\n\nimpliedshell=bool\nIf the user does not specify a program on the command line, sudo will pass\nthe plugin the path to the user's shell and set\n\nloginclass=string\nBSD login class to use when setting resource limits and nice value, if speci‐\nfied by the -c option.\n\nloginshell=bool\nSet to true if the user specified the -i option, indicating that the user\nwishes to run a login shell.\n\nmaxgroups=int\nThe maximum number of groups a user may belong to.  This will only be present\nif there is a corresponding setting in sudo.conf(5).\n\nnetworkaddrs=list\nA space-separated list of IP network addresses and netmasks in the form\n“addr/netmask”, e.g., “192.168.1.2/255.255.255.0”.  The address and netmask\npairs may be either IPv4 or IPv6, depending on what the operating system sup‐\nports.  If the address contains a colon (‘:’), it is an IPv6 address, else it\nis IPv4.\n\nnoninteractive=bool\nSet to true if the user specified the -n option, indicating that sudo should\noperate in non-interactive mode.  The plugin may reject a command run in non-\ninteractive mode if user interaction is required.\n\nplugindir=string\nThe default plugin directory used by the sudo front-end.  This is the default\ndirectory set at compile time and may not correspond to the directory the\nrunning plugin was loaded from.  It may be used by a plugin to locate support\nfiles.\n\npluginpath=string\nThe path name of plugin loaded by the sudo front-end.  The path name will be\na fully-qualified unless the plugin was statically compiled into sudo.\n\npreserveenvironment=bool\nSet to true if the user specified the -E option, indicating that the user\nwishes to preserve the environment.\n\npreservegroups=bool\nSet to true if the user specified the -P option, indicating that the user\nwishes to preserve the group vector instead of setting it based on the runas\nuser.\n\nprogname=string\nThe command name that sudo was run as, typically “sudo” or “sudoedit”.\n\nprompt=string\nThe prompt to use when requesting a password, if specified via the -p option.\n\nremotehost=string\nThe name of the remote host to run the command on, if specified via the -h\noption.  Support for running the command on a remote host is meant to be im‐\nplemented via a helper program that is executed in place of the user-speci‐\nfied command.  The sudo front-end is only capable of executing commands on\nthe local host.  Only available starting with API version 1.4.\n\nrunshell=bool\nSet to true if the user specified the -s option, indicating that the user\nwishes to run a shell.\n\nrunasgroup=string\nThe group name or group-ID to run the command as, if specified via the -g op‐\ntion.\n\nrunasuser=string\nThe user name or user-ID to run the command as, if specified via the -u op‐\ntion.\n\nselinuxrole=string\nSELinux role to use when executing the command, if specified by the -r op‐\ntion.\n\nselinuxtype=string\nSELinux type to use when executing the command, if specified by the -t op‐\ntion.\n\nsethome=bool\nSet to true if the user specified the -H option.  If true, set the HOME envi‐\nronment variable to the target user's home directory.\n\nsudoedit=bool\nSet to true when the -e option is specified or if invoked as sudoedit.  The\nplugin shall substitute an editor into argv in the checkpolicy() function or\nreturn -2 with a usage error if the plugin does not support sudoedit.  For\nmore information, see the checkpolicy section.\n\ntimeout=string\nCommand timeout specified by the user via the -T option.  Not all plugins\nsupport command timeouts and the ability of the user to set a timeout may be\nrestricted by policy.  The format of the timeout string is plugin-specific.\n\nAdditional settings may be added in the future so the plugin should silently ignore\nsettings that it does not recognize.\n\nuserinfo\nA vector of information about the user running the command in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing userinfo, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nThe following values may be set by sudo:\n\ncols=int\nThe number of columns the user's terminal supports.  If there is no terminal\ndevice available, a default value of 80 is used.\n\ncwd=string\nThe user's current working directory.\n\negid=gidt\nThe effective group-ID of the user invoking sudo.\n\neuid=uidt\nThe effective user-ID of the user invoking sudo.\n\ngid=gidt\nThe real group-ID of the user invoking sudo.\n\ngroups=list\nThe user's supplementary group list formatted as a string of comma-separated\ngroup-IDs.\n\nhost=string\nThe local machine's hostname as returned by the gethostname(2) system call.\n\nlines=int\nThe number of lines the user's terminal supports.  If there is no terminal\ndevice available, a default value of 24 is used.\n\npgid=int\nThe ID of the process group that the running sudo process is a member of.\nOnly available starting with API version 1.2.\n\npid=int\nThe process ID of the running sudo process.  Only available starting with API\nversion 1.2.\n\nppid=int\nThe parent process ID of the running sudo process.  Only available starting\nwith API version 1.2.\n\nrlimitas=soft,hard\nThe maximum size to which the process's address space may grow (in bytes), if\nsupported by the operating system.  The soft and hard limits are separated by\na comma.  A value of “infinity” indicates that there is no limit.  Only\navailable starting with API version 1.16.\n\nrlimitcore=soft,hard\nThe largest size core dump file that may be created (in bytes).  The soft and\nhard limits are separated by a comma.  A value of “infinity” indicates that\nthere is no limit.  Only available starting with API version 1.16.\n\nrlimitcpu=soft,hard\nThe maximum amount of CPU time that the process may use (in seconds).  The\nsoft and hard limits are separated by a comma.  A value of “infinity” indi‐\ncates that there is no limit.  Only available starting with API version 1.16.\n\nrlimitdata=soft,hard\nThe maximum size of the data segment for the process (in bytes).  The soft\nand hard limits are separated by a comma.  A value of “infinity” indicates\nthat there is no limit.  Only available starting with API version 1.16.\n\nrlimitfsize=soft,hard\nThe largest size file that the process may create (in bytes).  The soft and\nhard limits are separated by a comma.  A value of “infinity” indicates that\nthere is no limit.  Only available starting with API version 1.16.\n\nrlimitlocks=soft,hard\nThe maximum number of locks that the process may establish, if supported by\nthe operating system.  The soft and hard limits are separated by a comma.  A\nvalue of “infinity” indicates that there is no limit.  Only available start‐\ning with API version 1.16.\n\nrlimitmemlock=soft,hard\nThe maximum size that the process may lock in memory (in bytes), if supported\nby the operating system.  The soft and hard limits are separated by a comma.\nA value of “infinity” indicates that there is no limit.  Only available\nstarting with API version 1.16.\n\nrlimitnofile=soft,hard\nThe maximum number of files that the process may have open.  The soft and\nhard limits are separated by a comma.  A value of “infinity” indicates that\nthere is no limit.  Only available starting with API version 1.16.\n\nrlimitnproc=soft,hard\nThe maximum number of processes that the user may run simultaneously.  The\nsoft and hard limits are separated by a comma.  A value of “infinity” indi‐\ncates that there is no limit.  Only available starting with API version 1.16.\n\nrlimitrss=soft,hard\nThe maximum size to which the process's resident set size may grow (in\nbytes).  The soft and hard limits are separated by a comma.  A value of\n“infinity” indicates that there is no limit.  Only available starting with\nAPI version 1.16.\n\nrlimitstack=soft,hard\nThe maximum size to which the process's stack may grow (in bytes).  The soft\nand hard limits are separated by a comma.  A value of “infinity” indicates\nthat there is no limit.  Only available starting with API version 1.16.\n\nsid=int\nThe session ID of the running sudo process or 0 if sudo is not part of a\nPOSIX job control session.  Only available starting with API version 1.2.\n\ntcpgid=int\nThe ID of the foreground process group associated with the terminal device\nassociated with the sudo process or 0 if there is no terminal present.  Only\navailable starting with API version 1.2.\n\ntty=string\nThe path to the user's terminal device.  If the user has no terminal device\nassociated with the session, the value will be empty, as in “tty=”.\n\nuid=uidt\nThe real user-ID of the user invoking sudo.\n\numask=octal\nThe invoking user's file creation mask.  Only available starting with API\nversion 1.10.\n\nuser=string\nThe name of the user invoking sudo.\n\nuserenv\nThe user's environment in the form of a NULL-terminated vector of “name=value”\nstrings.\n\nWhen parsing userenv, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\npluginoptions\nAny (non-comment) strings immediately after the plugin path are passed as arguments\nto the plugin.  These arguments are split on a white space boundary and are passed\nto the plugin in the form of a NULL-terminated array of strings.  If no arguments\nwere specified, pluginoptions will be the NULL pointer.\n\nNOTE: the pluginoptions parameter is only available starting with API version 1.2.\nA plugin must check the API version specified by the sudo front-end before using\npluginoptions.  Failure to do so may result in a crash.\n\nerrstr\nIf the open() function returns a value other than 1, the plugin may store a message\ndescribing the failure or error in errstr.  The sudo front-end will then pass this\nvalue to any registered audit plugins.  The string stored in errstr must remain\nvalid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nclose\nvoid (*close)(int exitstatus, int error);\n\nThe close() function is called when sudo is finished, shortly before it exits.  Starting\nwith API version 1.15, close() is called regardless of whether or not a command was actu‐\nally executed.  This makes it possible for plugins to perform cleanup even when a command\nwas not run.  It is not possible to tell whether a command was run based solely on the\narguments passed to the close() function.  To determine if a command was actually run,\nthe plugin must keep track of whether or not the checkpolicy() function returned suc‐\ncessfully.\n\nThe function arguments are as follows:\n\nexitstatus\nThe command's exit status, as returned by the wait(2) system call, or zero if no\ncommand was run.  The value of exitstatus is undefined if error is non-zero.\n\nerror\nIf the command could not be executed, this is set to the value of errno set by the\nexecve(2) system call.  The plugin is responsible for displaying error information\nvia the conversation() or pluginprintf() function.  If the command was success‐\nfully executed, the value of error is zero.\n\nIf no close() function is defined, no I/O logging plugins are loaded, and neither the\ntimeout not usepty options are set in the commandinfo list, the sudo front-end may exe‐\ncute the command directly instead of running it as a child process.\n\nshowversion\nint (*showversion)(int verbose);\n\nThe showversion() function is called by sudo when the user specifies the -V option.  The\nplugin may display its version information to the user via the conversation() or\npluginprintf() function using SUDOCONVINFOMSG.  If the user requests detailed version\ninformation, the verbose flag will be set.\n\nReturns 1 on success, 0 on failure, -1 if a general error occurred, or -2 if there was a\nusage error, although the return value is currently ignored.\n\ncheckpolicy\nint (*checkpolicy)(int argc, char * const argv[], char *envadd[],\nchar commandinfo[], char argvout[], char userenvout[],\nconst char errstr);\n\nThe checkpolicy() function is called by sudo to determine whether the user is allowed to\nrun the specified commands.\n\nIf the sudoedit option was enabled in the settings array passed to the open() function,\nthe user has requested sudoedit mode.  sudoedit is a mechanism for editing one or more\nfiles where an editor is run with the user's credentials instead of with elevated privi‐\nleges.  sudo achieves this by creating user-writable temporary copies of the files to be\nedited and then overwriting the originals with the temporary copies after editing is com‐\nplete.  If the plugin supports sudoedit, it should choose the editor to be used, poten‐\ntially from a variable in the user's environment, such as EDITOR, and include it in\nargvout (note that environment variables may include command line options).  The files\nto be edited should be copied from argv into argvout, separated from the editor and its\narguments by a “--” element.  The “--” will be removed by sudo before the editor is exe‐\ncuted.  The plugin should also set sudoedit=true in the commandinfo list.\n\nThe checkpolicy() function returns 1 if the command is allowed, 0 if not allowed, -1 for\na general error, or -2 for a usage error or if sudoedit was specified but is unsupported\nby the plugin.  In the latter case, sudo will print a usage message before it exits.  If\nan error occurs, the plugin may optionally call the conversation() or pluginprintf()\nfunction with SUDOCONFERRORMSG to present additional error information to the user.\n\nThe function arguments are as follows:\n\nargc  The number of elements in argv, not counting the final NULL pointer.\n\nargv  The argument vector describing the command the user wishes to run, in the same form\nas what would be passed to the execve(2) system call.  The vector is terminated by\na NULL pointer.\n\nenvadd\nAdditional environment variables specified by the user on the command line in the\nform of a NULL-terminated vector of “name=value” strings.  The plugin may reject\nthe command if one or more variables are not allowed to be set, or it may silently\nignore such variables.\n\nWhen parsing envadd, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\ncommandinfo\nInformation about the command being run in the form of “name=value” strings.  These\nvalues are used by sudo to set the execution environment when running a command.\nThe plugin is responsible for creating and populating the vector, which must be\nterminated with a NULL pointer.  The following values are recognized by sudo:\n\nchroot=string\nThe root directory to use when running the command.\n\nclosefrom=number\nIf specified, sudo will close all files descriptors with a value of number or\nhigher.\n\ncommand=string\nFully qualified path to the command to be executed.\n\ncwd=string\nThe current working directory to change to when executing the command.  If\nsudo is unable to change to the new working directory, the command will not\nbe run unless cwdoptional is also set (see below).\n\ncwdoptional=bool\nIf enabled, sudo will treat an inability to change to the new working direc‐\ntory as a non-fatal error.  This setting has no effect unless cwd is also\nset.\n\nexecbackground=bool\nBy default, sudo runs a command as the foreground process as long as sudo it‐\nself is running in the foreground.  When execbackground is enabled and the\ncommand is being run in a pseudo-terminal (due to I/O logging or the usepty\nsetting), the command will be run as a background process.  Attempts to read\nfrom the controlling terminal (or to change terminal settings) will result in\nthe command being suspended with the SIGTTIN signal (or SIGTTOU in the case\nof terminal settings).  If this happens when sudo is a foreground process,\nthe command will be granted the controlling terminal and resumed in the fore‐\nground with no user intervention required.  The advantage of initially run‐\nning the command in the background is that sudo need not read from the termi‐\nnal unless the command explicitly requests it.  Otherwise, any terminal input\nmust be passed to the command, whether it has required it or not (the kernel\nbuffers terminals so it is not possible to tell whether the command really\nwants the input).  This is different from historic sudo behavior or when the\ncommand is not being run in a pseudo-terminal.\n\nFor this to work seamlessly, the operating system must support the automatic\nrestarting of system calls.  Unfortunately, not all operating systems do this\nby default, and even those that do may have bugs.  For example, macOS fails\nto restart the tcgetattr() and tcsetattr() system calls (this is a bug in\nmacOS).  Furthermore, because this behavior depends on the command stopping\nwith the SIGTTIN or SIGTTOU signals, programs that catch these signals and\nsuspend themselves with a different signal (usually SIGTOP) will not be auto‐\nmatically foregrounded.  Some versions of the linux su(1) command behave this\nway.  Because of this, a plugin should not set execbackground unless it is\nexplicitly enabled by the administrator and there should be a way to enabled\nor disable it on a per-command basis.\n\nThis setting has no effect unless I/O logging is enabled or usepty is en‐\nabled.\n\nexecfd=number\nIf specified, sudo will use the fexecve(2) system call to execute the command\ninstead of execve(2).  The specified number must refer to an open file de‐\nscriptor.\n\niologcompress=bool\nSet to true if the I/O logging plugins, if any, should compress the log data.\nThis is a hint to the I/O logging plugin which may choose to ignore it.\n\niologgroup=string\nThe group that will own newly created I/O log files and directories.  This is\na hint to the I/O logging plugin which may choose to ignore it.\n\niologmode=octal\nThe file permission mode to use when creating I/O log files and directories.\nThis is a hint to the I/O logging plugin which may choose to ignore it.\n\niologuser=string\nThe user that will own newly created I/O log files and directories.  This is\na hint to the I/O logging plugin which may choose to ignore it.\n\niologpath=string\nFully qualified path to the file or directory in which I/O log is to be\nstored.  This is a hint to the I/O logging plugin which may choose to ignore\nit.  If no I/O logging plugin is loaded, this setting has no effect.\n\niologstdin=bool\nSet to true if the I/O logging plugins, if any, should log the standard input\nif it is not connected to a terminal device.  This is a hint to the I/O log‐\nging plugin which may choose to ignore it.\n\niologstdout=bool\nSet to true if the I/O logging plugins, if any, should log the standard out‐\nput if it is not connected to a terminal device.  This is a hint to the I/O\nlogging plugin which may choose to ignore it.\n\niologstderr=bool\nSet to true if the I/O logging plugins, if any, should log the standard error\nif it is not connected to a terminal device.  This is a hint to the I/O log‐\nging plugin which may choose to ignore it.\n\niologttyin=bool\nSet to true if the I/O logging plugins, if any, should log all terminal in‐\nput.  This only includes input typed by the user and not from a pipe or redi‐\nrected from a file.  This is a hint to the I/O logging plugin which may\nchoose to ignore it.\n\niologttyout=bool\nSet to true if the I/O logging plugins, if any, should log all terminal out‐\nput.  This only includes output to the screen, not output to a pipe or file.\nThis is a hint to the I/O logging plugin which may choose to ignore it.\n\nloginclass=string\nBSD login class to use when setting resource limits and nice value (op‐\ntional).  This option is only set on systems that support login classes.\n\nnice=int\nNice value (priority) to use when executing the command.  The nice value, if\nspecified, overrides the priority associated with the loginclass on BSD sys‐\ntems.\n\nnoexec=bool\nIf set, prevent the command from executing other programs.\n\npreservefds=list\nA comma-separated list of file descriptors that should be preserved, regard‐\nless of the value of the closefrom setting.  Only available starting with API\nversion 1.5.\n\npreservegroups=bool\nIf set, sudo will preserve the user's group vector instead of initializing\nthe group vector based on runasuser.\n\nrlimitas=soft,hard\nThe maximum size to which the process's address space may grow (in bytes), if\nsupported by the operating system.  The soft and hard limits are separated by\na comma.  If only a single value is specified, both the hard and soft limits\nare set.  A value of “infinity” indicates that there is no limit.  A value of\n“user” will cause the invoking user's resource limit to be preserved.  A\nvalue of “default” will cause the target user's default resource limit to be\nused on systems that allow per-user resource limits to be configured.  Only\navailable starting with API version 1.17.\n\nrlimitcore=soft,hard\nThe largest size core dump file that may be created (in bytes).  The soft and\nhard limits are separated by a comma.  If only a single value is specified,\nboth the hard and soft limits are set.  A value of “infinity” indicates that\nthere is no limit.  A value of “user” will cause the invoking user's resource\nlimit to be preserved.  A value of “default” will cause the target user's de‐\nfault resource limit to be used on systems that allow per-user resource lim‐\nits to be configured.  Only available starting with API version 1.17.\n\nrlimitcpu=soft,hard\nThe maximum amount of CPU time that the process may use (in seconds).  The\nsoft and hard limits are separated by a comma.  If only a single value is\nspecified, both the hard and soft limits are set.  A value of “infinity” in‐\ndicates that there is no limit.  A value of “user” will cause the invoking\nuser's resource limit to be preserved.  A value of “default” will cause the\ntarget user's default resource limit to be used on systems that allow per-\nuser resource limits to be configured.  Only available starting with API ver‐\nsion 1.17.\n\nrlimitdata=soft,hard\nThe maximum size of the data segment for the process (in bytes).  The soft\nand hard limits are separated by a comma.  If only a single value is speci‐\nfied, both the hard and soft limits are set.  A value of “infinity” indicates\nthat there is no limit.  A value of “user” will cause the invoking user's re‐\nsource limit to be preserved.  A value of “default” will cause the target\nuser's default resource limit to be used on systems that allow per-user re‐\nsource limits to be configured.  Only available starting with API version\n1.17.\n\nrlimitfsize=soft,hard\nThe largest size file that the process may create (in bytes).  The soft and\nhard limits are separated by a comma.  If only a single value is specified,\nboth the hard and soft limits are set.  A value of “infinity” indicates that\nthere is no limit.  A value of “user” will cause the invoking user's resource\nlimit to be preserved.  A value of “default” will cause the target user's de‐\nfault resource limit to be used on systems that allow per-user resource lim‐\nits to be configured.  Only available starting with API version 1.17.\n\nrlimitlocks=soft,hard\nThe maximum number of locks that the process may establish, if supported by\nthe operating system.  The soft and hard limits are separated by a comma.  If\nonly a single value is specified, both the hard and soft limits are set.  A\nvalue of “infinity” indicates that there is no limit.  A value of “user” will\ncause the invoking user's resource limit to be preserved.  A value of\n“default” will cause the target user's default resource limit to be used on\nsystems that allow per-user resource limits to be configured.  Only available\nstarting with API version 1.17.\n\nrlimitmemlock=soft,hard\nThe maximum size that the process may lock in memory (in bytes), if supported\nby the operating system.  The soft and hard limits are separated by a comma.\nIf only a single value is specified, both the hard and soft limits are set.\nA value of “infinity” indicates that there is no limit.  A value of “user”\nwill cause the invoking user's resource limit to be preserved.  A value of\n“default” will cause the target user's default resource limit to be used on\nsystems that allow per-user resource limits to be configured.  Only available\nstarting with API version 1.17.\n\nrlimitnofile=soft,hard\nThe maximum number of files that the process may have open.  The soft and\nhard limits are separated by a comma.  If only a single value is specified,\nboth the hard and soft limits are set.  A value of “infinity” indicates that\nthere is no limit.  A value of “user” will cause the invoking user's resource\nlimit to be preserved.  A value of “default” will cause the target user's de‐\nfault resource limit to be used on systems that allow per-user resource lim‐\nits to be configured.  Only available starting with API version 1.17.\n\nrlimitnproc=soft,hard\nThe maximum number of processes that the user may run simultaneously.  The\nsoft and hard limits are separated by a comma.  If only a single value is\nspecified, both the hard and soft limits are set.  A value of “infinity” in‐\ndicates that there is no limit.  A value of “user” will cause the invoking\nuser's resource limit to be preserved.  A value of “default” will cause the\ntarget user's default resource limit to be used on systems that allow per-\nuser resource limits to be configured.  Only available starting with API ver‐\nsion 1.17.\n\nrlimitrss=soft,hard\nThe maximum size to which the process's resident set size may grow (in\nbytes).  The soft and hard limits are separated by a comma.  If only a single\nvalue is specified, both the hard and soft limits are set.  A value of\n“infinity” indicates that there is no limit.  A value of “user” will cause\nthe invoking user's resource limit to be preserved.  A value of “default”\nwill cause the target user's default resource limit to be used on systems\nthat allow per-user resource limits to be configured.  Only available start‐\ning with API version 1.17.\n\nrlimitstack=soft,hard\nThe maximum size to which the process's stack may grow (in bytes).  The soft\nand hard limits are separated by a comma.  If only a single value is speci‐\nfied, both the hard and soft limits are set.  A value of “infinity” indicates\nthat there is no limit.  A value of “user” will cause the invoking user's re‐\nsource limit to be preserved.  A value of “default” will cause the target\nuser's default resource limit to be used on systems that allow per-user re‐\nsource limits to be configured.  Only available starting with API version\n1.17.\n\nrunasegid=gid\nEffective group-ID to run the command as.  If not specified, the value of\nrunasgid is used.\n\nrunaseuid=uid\nEffective user-ID to run the command as.  If not specified, the value of\nrunasuid is used.\n\nrunasgid=gid\nGroup-ID to run the command as.\n\nrunasgroup=string\nThe name of the group the command will run as, if it is different from the\nrunasuser's default group.  This value is provided for auditing purposes\nonly, the sudo front-end uses runasegid and runasgid when executing the\ncommand.\n\nrunasgroups=list\nThe supplementary group vector to use for the command in the form of a comma-\nseparated list of group-IDs.  If preservegroups is set, this option is ig‐\nnored.\n\nrunasuid=uid\nUser-ID to run the command as.\n\nrunasuser=string\nThe name of the user the command will run as, which should correspond to\nrunaseuid (or runasuid if runaseuid is not set).  This value is provided\nfor auditing purposes only, the sudo front-end uses runaseuid and runasuid\nwhen executing the command.\n\nselinuxrole=string\nSELinux role to use when executing the command.\n\nselinuxtype=string\nSELinux type to use when executing the command.\n\nsetutmp=bool\nCreate a utmp (or utmpx) entry when a pseudo-terminal is allocated.  By de‐\nfault, the new entry will be a copy of the user's existing utmp entry (if\nany), with the tty, time, type, and pid fields updated.\n\nsudoedit=bool\nSet to true when in sudoedit mode.  The plugin may enable sudoedit mode even\nif sudo was not invoked as sudoedit.  This allows the plugin to perform com‐\nmand substitution and transparently enable sudoedit when the user attempts to\nrun an editor.\n\nsudoeditcheckdir=bool\nSet to false to disable directory writability checks in sudoedit.  By de‐\nfault, sudoedit 1.8.16 and higher will check all directory components of the\npath to be edited for writability by the invoking user.  Symbolic links will\nnot be followed in writable directories and sudoedit will refuse to edit a\nfile located in a writable directory.  These restrictions are not enforced\nwhen sudoedit is run by root.  The sudoeditfollow option can be set to false\nto disable this check.  Only available starting with API version 1.8.\n\nsudoeditfollow=bool\nSet to true to allow sudoedit to edit files that are symbolic links.  By de‐\nfault, sudoedit 1.8.15 and higher will refuse to open a symbolic link.  The\nsudoeditfollow option can be used to restore the older behavior and allow\nsudoedit to open symbolic links.  Only available starting with API version\n1.8.\n\ntimeout=int\nCommand timeout.  If non-zero then when the timeout expires the command will\nbe killed.\n\numask=octal\nThe file creation mask to use when executing the command.  This value may be\noverridden by PAM or login.conf on some systems unless the umaskoverride op‐\ntion is also set.\n\numaskoverride=bool\nForce the value specified by the umask option to override any umask set by\nPAM or login.conf.\n\nusepty=bool\nAllocate a pseudo-terminal to run the command in, regardless of whether or\nnot I/O logging is in use.  By default, sudo will only run the command in a\npseudo-terminal when an I/O log plugin is loaded.\n\nutmpuser=string\nUser name to use when constructing a new utmp (or utmpx) entry when setutmp\nis enabled.  This option can be used to set the user field in the utmp entry\nto the user the command runs as rather than the invoking user.  If not set,\nsudo will base the new entry on the invoking user's existing entry.\n\nUnsupported values will be ignored.\n\nargvout\nThe NULL-terminated argument vector to pass to the execve(2) system call when exe‐\ncuting the command.  The plugin is responsible for allocating and populating the\nvector.\n\nuserenvout\nThe NULL-terminated environment vector to use when executing the command.  The\nplugin is responsible for allocating and populating the vector.\n\nerrstr\nIf the checkpolicy() function returns a value other than 1, the plugin may store a\nmessage describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nlist\nint (*list)(int argc, char * const argv[], int verbose,\nconst char *listuser, const char errstr);\n\nList available privileges for the invoking user.  Returns 1 on success, 0 on failure, and\n-1 on error.  On error, the plugin may optionally call the conversation() or\npluginprintf() function with SUDOCONFERRORMSG to present additional error information\nto the user.\n\nPrivileges should be output via the conversation() or pluginprintf() function using\nSUDOCONVINFOMSG.\n\nThe function arguments are as follows:\n\nargc  The number of elements in argv, not counting the final NULL pointer.\n\nargv  If non-NULL, an argument vector describing a command the user wishes to check\nagainst the policy in the same form as what would be passed to the execve(2) system\ncall.  If the command is permitted by the policy, the fully-qualified path to the\ncommand should be displayed along with any command line arguments.\n\nverbose\nFlag indicating whether to list in verbose mode or not.\n\nlistuser\nThe name of a different user to list privileges for if the policy allows it.  If\nNULL, the plugin should list the privileges of the invoking user.\n\nerrstr\nIf the list() function returns a value other than 1, the plugin may store a message\ndescribing the failure or error in errstr.  The sudo front-end will then pass this\nvalue to any registered audit plugins.  The string stored in errstr must remain\nvalid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nvalidate\nint (*validate)(const char errstr);\n\nThe validate() function is called when sudo is run with the -v option.  For policy plug‐\nins such as sudoers that cache authentication credentials, this function will validate\nand cache the credentials.\n\nThe validate() function should be NULL if the plugin does not support credential caching.\n\nReturns 1 on success, 0 on failure, and -1 on error.  On error, the plugin may optionally\ncall the conversation() or pluginprintf() function with SUDOCONFERRORMSG to present\nadditional error information to the user.\n\nThe function arguments are as follows:\n\nerrstr\nIf the validate() function returns a value other than 1, the plugin may store a\nmessage describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\ninvalidate\nvoid (*invalidate)(int remove);\n\nThe invalidate() function is called when sudo is run with the -k or -K option.  For pol‐\nicy plugins such as sudoers that cache authentication credentials, this function will in‐\nvalidate the credentials.  If the remove flag is set, the plugin may remove the creden‐\ntials instead of simply invalidating them.\n\nThe invalidate() function should be NULL if the plugin does not support credential\ncaching.\n\ninitsession\nint (*initsession)(struct passwd *pwd, char userenvout[]);\n\nThe initsession() function is called before sudo sets up the execution environment for\nthe command.  It is run in the parent sudo process and before any user-ID or group-ID\nchanges.  This can be used to perform session setup that is not supported by\ncommandinfo, such as opening the PAM session.  The close() function can be used to tear\ndown the session that was opened by initsession.\n\nThe pwd argument points to a passwd struct for the user the command will be run as if the\nuser-ID the command will run as was found in the password database, otherwise it will be\nNULL.\n\nThe userenvout argument points to the environment the command will run in, in the form\nof a NULL-terminated vector of “name=value” strings.  This is the same string passed back\nto the front-end via the Policy Plugin's userenvout parameter.  If the initsession()\nfunction needs to modify the user environment, it should update the pointer stored in\nuserenvout.  The expected use case is to merge the contents of the PAM environment (if\nany) with the contents of userenvout.  NOTE: the userenvout parameter is only avail‐\nable starting with API version 1.2.  A plugin must check the API version specified by the\nsudo front-end before using userenvout.  Failure to do so may result in a crash.\n\nReturns 1 on success, 0 on failure, and -1 on error.  On error, the plugin may optionally\ncall the conversation() or pluginprintf() function with SUDOCONFERRORMSG to present\nadditional error information to the user.\n\nregisterhooks\nvoid (*registerhooks)(int version,\nint (*registerhook)(struct sudohook *hook));\n\nThe registerhooks() function is called by the sudo front-end to register any hooks the\nplugin needs.  If the plugin does not support hooks, registerhooks should be set to the\nNULL pointer.\n\nThe version argument describes the version of the hooks API supported by the sudo front-\nend.\n\nThe registerhook() function should be used to register any supported hooks the plugin\nneeds.  It returns 0 on success, 1 if the hook type is not supported, and -1 if the major\nversion in struct hook does not match the front-end's major hook API version.\n\nSee the Hook function API section below for more information about hooks.\n\nNOTE: the registerhooks() function is only available starting with API version 1.2.  If\nthe sudo front-end doesn't support API version 1.2 or higher, registerhooks will not be\ncalled.\n\nderegisterhooks\nvoid (*deregisterhooks)(int version,\nint (*deregisterhook)(struct sudohook *hook));\n\nThe deregisterhooks() function is called by the sudo front-end to deregister any hooks\nthe plugin has registered.  If the plugin does not support hooks, deregisterhooks should\nbe set to the NULL pointer.\n\nThe version argument describes the version of the hooks API supported by the sudo front-\nend.\n\nThe deregisterhook() function should be used to deregister any hooks that were put in\nplace by the registerhook() function.  If the plugin tries to deregister a hook that the\nfront-end does not support, deregisterhook will return an error.\n\nSee the Hook function API section below for more information about hooks.\n\nNOTE: the deregisterhooks() function is only available starting with API version 1.2.\nIf the sudo front-end doesn't support API version 1.2 or higher, deregisterhooks will\nnot be called.\n\neventalloc\nstruct sudopluginevent * (*eventalloc)(void);\n\nThe eventalloc() function is used to allocate a struct sudopluginevent which provides\naccess to the main sudo event loop.  Unlike the other fields, the eventalloc() pointer\nis filled in by the sudo front-end, not by the plugin.\n\nSee the Event API section below for more information about events.\n\nNOTE: the eventalloc() function is only available starting with API version 1.15.  If\nthe sudo front-end doesn't support API version 1.15 or higher, eventalloc() will not be\nset.\n\nerrstr\nIf the initsession() function returns a value other than 1, the plugin may store a mes‐\nsage describing the failure or error in errstr.  The sudo front-end will then pass this\nvalue to any registered audit plugins.  The string stored in errstr must remain valid un‐\ntil the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A plugin\nmust check the API version specified by the sudo front-end before using errstr.  Failure\nto do so may result in a crash.\n\nPolicy Plugin Version Macros\n\n/* Plugin API version major/minor. */\n#define SUDOAPIVERSIONMAJOR 1\n#define SUDOAPIVERSIONMINOR 13\n#define SUDOAPIMKVERSION(x, y) ((x << 16) | y)\n#define SUDOAPIVERSION SUDOAPIMKVERSION(SUDOAPIVERSIONMAJOR,\\\nSUDOAPIVERSIONMINOR)\n\n/* Getters and setters for API version */\n#define SUDOAPIVERSIONGETMAJOR(v) ((v) >> 16)\n#define SUDOAPIVERSIONGETMINOR(v) ((v) & 0xffff)\n#define SUDOAPIVERSIONSETMAJOR(vp, n) do { \\\n*(vp) = (*(vp) & 0x0000ffff) | ((n) << 16); \\\n} while(0)\n#define SUDOAPIVERSIONSETMINOR(vp, n) do { \\\n*(vp) = (*(vp) & 0xffff0000) | (n); \\\n} while(0)\n"
                    },
                    {
                        "name": "I/O plugin API",
                        "content": "struct ioplugin {\n#define SUDOIOPLUGIN 2\nunsigned int type; /* always SUDOIOPLUGIN */\nunsigned int version; /* always SUDOAPIVERSION */\nint (*open)(unsigned int version, sudoconvt conversation,\nsudoprintft pluginprintf, char * const settings[],\nchar * const userinfo[], char * const commandinfo[],\nint argc, char * const argv[], char * const userenv[],\nchar * const pluginoptions[], const char errstr);\nvoid (*close)(int exitstatus, int error); /* wait status or error */\nint (*showversion)(int verbose);\nint (*logttyin)(const char *buf, unsigned int len,\nconst char errstr);\nint (*logttyout)(const char *buf, unsigned int len,\nconst char errstr);\nint (*logstdin)(const char *buf, unsigned int len,\nconst char errstr);\nint (*logstdout)(const char *buf, unsigned int len,\nconst char errstr);\nint (*logstderr)(const char *buf, unsigned int len,\nconst char errstr);\nvoid (*registerhooks)(int version,\nint (*registerhook)(struct sudohook *hook));\nvoid (*deregisterhooks)(int version,\nint (*deregisterhook)(struct sudohook *hook));\nint (*changewinsize)(unsigned int lines, unsigned int cols,\nconst char errstr);\nint (*logsuspend)(int signo, const char errstr);\nstruct sudopluginevent * (*eventalloc)(void);\n};\n\nWhen an I/O plugin is loaded, sudo runs the command in a pseudo-terminal.  This makes it possi‐\nble to log the input and output from the user's session.  If any of the standard input, stan‐\ndard output, or standard error do not correspond to a tty, sudo will open a pipe to capture the\nI/O for logging before passing it on.\n\nThe logttyin function receives the raw user input from the terminal device (note that this\nwill include input even when echo is disabled, such as when a password is read).  The logtty‐\nout function receives output from the pseudo-terminal that is suitable for replaying the user's\nsession at a later time.  The logstdin(), logstdout(), and logstderr() functions are only\ncalled if the standard input, standard output, or standard error respectively correspond to\nsomething other than a tty.\n\nAny of the logging functions may be set to the NULL pointer if no logging is to be performed.\nIf the open function returns 0, no I/O will be sent to the plugin.\n\nIf a logging function returns an error (-1), the running command will be terminated and all of\nthe plugin's logging functions will be disabled.  Other I/O logging plugins will still receive\nany remaining input or output that has not yet been processed.\n\nIf an input logging function rejects the data by returning 0, the command will be terminated\nand the data will not be passed to the command, though it will still be sent to any other I/O\nlogging plugins.  If an output logging function rejects the data by returning 0, the command\nwill be terminated and the data will not be written to the terminal, though it will still be\nsent to any other I/O logging plugins.\n\nThe auditplugin struct has the following fields:\n\ntype  The type field should always be set to SUDOIOPLUGIN.\n\nversion\nThe version field should be set to SUDOAPIVERSION.\n\nThis allows sudo to determine the API version the plugin was built against.\n\nopen\nint (*open)(unsigned int version, sudoconvt conversation,\nsudoprintft pluginprintf, char * const settings[],\nchar * const userinfo[], char * const commandinfo[],\nint argc, char * const argv[], char * const userenv[],\nchar * const pluginoptions[]);\n\nThe open() function is run before the logttyin(), logttyout(), logstdin(),\nlogstdout(), logstderr(), logsuspend(), changewinsize(), or showversion() functions\nare called.  It is only called if the version is being requested or if the policy\nplugin's checkpolicy() function has returned successfully.  It returns 1 on success, 0\non failure, -1 if a general error occurred, or -2 if there was a usage error.  In the\nlatter case, sudo will print a usage message before it exits.  If an error occurs, the\nplugin may optionally call the conversation() or pluginprintf() function with\nSUDOCONFERRORMSG to present additional error information to the user.\n\nThe function arguments are as follows:\n\nversion\nThe version passed in by sudo allows the plugin to determine the major and minor\nversion number of the plugin API supported by sudo.\n\nconversation\nA pointer to the conversation() function that may be used by the showversion()\nfunction to display version information (see showversion() below).  The\nconversation() function may also be used to display additional error message to the\nuser.  The conversation() function returns 0 on success and -1 on failure.\n\npluginprintf\nA pointer to a printf()-style function that may be used by the showversion() func‐\ntion to display version information (see showversion below).  The pluginprintf()\nfunction may also be used to display additional error message to the user.  The\npluginprintf() function returns number of characters printed on success and -1 on\nfailure.\n\nsettings\nA vector of user-supplied sudo settings in the form of “name=value” strings.  The\nvector is terminated by a NULL pointer.  These settings correspond to options the\nuser specified when running sudo.  As such, they will only be present when the cor‐\nresponding option has been specified on the command line.\n\nWhen parsing settings, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible settings.\n\nuserinfo\nA vector of information about the user running the command in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing userinfo, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible strings.\n\ncommandinfo\nA vector of information describing the command being run in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing commandinfo, the plugin should split on the first equal sign (‘=’)\nsince the name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible strings.\n\nargc  The number of elements in argv, not counting the final NULL pointer.  It can be\nzero, when sudo is called with -V.\n\nargv  If non-NULL, an argument vector describing a command the user wishes to run in the\nsame form as what would be passed to the execve(2) system call.\n\nuserenv\nThe user's environment in the form of a NULL-terminated vector of “name=value”\nstrings.\n\nWhen parsing userenv, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\npluginoptions\nAny (non-comment) strings immediately after the plugin path are treated as argu‐\nments to the plugin.  These arguments are split on a white space boundary and are\npassed to the plugin in the form of a NULL-terminated array of strings.  If no ar‐\nguments were specified, pluginoptions will be the NULL pointer.\n\nNOTE: the pluginoptions parameter is only available starting with API version 1.2.\nA plugin must check the API version specified by the sudo front-end before using\npluginoptions.  Failure to do so may result in a crash.\n\nerrstr\nIf the open() function returns a value other than 1, the plugin may store a message\ndescribing the failure or error in errstr.  The sudo front-end will then pass this\nvalue to any registered audit plugins.  The string stored in errstr must remain\nvalid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nclose\nvoid (*close)(int exitstatus, int error);\n\nThe close() function is called when sudo is finished, shortly before it exits.\n\nThe function arguments are as follows:\n\nexitstatus\nThe command's exit status, as returned by the wait(2) system call, or zero if no\ncommand was run.  The value of exitstatus is undefined if error is non-zero.\n\nerror\nIf the command could not be executed, this is set to the value of errno set by the\nexecve(2) system call.  If the command was successfully executed, the value of\nerror is zero.\n\nshowversion\nint (*showversion)(int verbose);\n\nThe showversion() function is called by sudo when the user specifies the -V option.  The\nplugin may display its version information to the user via the conversation() or\npluginprintf() function using SUDOCONVINFOMSG.\n\nReturns 1 on success, 0 on failure, -1 if a general error occurred, or -2 if there was a\nusage error, although the return value is currently ignored.\n\nlogttyin\nint (*logttyin)(const char *buf, unsigned int len,\nconst char errstr);\n\nThe logttyin() function is called whenever data can be read from the user but before it\nis passed to the running command.  This allows the plugin to reject data if it chooses to\n(for instance if the input contains banned content).  Returns 1 if the data should be\npassed to the command, 0 if the data is rejected (which will terminate the running com‐\nmand), or -1 if an error occurred.\n\nThe function arguments are as follows:\n\nbuf   The buffer containing user input.\n\nlen   The length of buf in bytes.\n\nerrstr\nIf the logttyin() function returns a value other than 1, the plugin may store a\nmessage describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nlogttyout\nint (*logttyout)(const char *buf, unsigned int len,\nconst char errstr);\n\nThe logttyout() function is called whenever data can be read from the command but before\nit is written to the user's terminal.  This allows the plugin to reject data if it\nchooses to (for instance if the output contains banned content).  Returns 1 if the data\nshould be passed to the user, 0 if the data is rejected (which will terminate the running\ncommand), or -1 if an error occurred.\n\nThe function arguments are as follows:\n\nbuf   The buffer containing command output.\n\nlen   The length of buf in bytes.\n\nerrstr\nIf the logttyout() function returns a value other than 1, the plugin may store a\nmessage describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nlogstdin\nint (*logstdin)(const char *buf, unsigned int len,\nconst char errstr);\n\nThe logstdin() function is only used if the standard input does not correspond to a tty\ndevice.  It is called whenever data can be read from the standard input but before it is\npassed to the running command.  This allows the plugin to reject data if it chooses to\n(for instance if the input contains banned content).  Returns 1 if the data should be\npassed to the command, 0 if the data is rejected (which will terminate the running com‐\nmand), or -1 if an error occurred.\n\nThe function arguments are as follows:\n\nbuf   The buffer containing user input.\n\nlen   The length of buf in bytes.\n\nerrstr\nIf the logstdin() function returns a value other than 1, the plugin may store a\nmessage describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nlogstdout\nint (*logstdout)(const char *buf, unsigned int len,\nconst char errstr);\n\nThe logstdout() function is only used if the standard output does not correspond to a\ntty device.  It is called whenever data can be read from the command but before it is\nwritten to the standard output.  This allows the plugin to reject data if it chooses to\n(for instance if the output contains banned content).  Returns 1 if the data should be\npassed to the user, 0 if the data is rejected (which will terminate the running command),\nor -1 if an error occurred.\n\nThe function arguments are as follows:\n\nbuf   The buffer containing command output.\n\nlen   The length of buf in bytes.\n\nerrstr\nIf the logstdout() function returns a value other than 1, the plugin may store a\nmessage describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nlogstderr\nint (*logstderr)(const char *buf, unsigned int len,\nconst char errstr);\n\nThe logstderr() function is only used if the standard error does not correspond to a tty\ndevice.  It is called whenever data can be read from the command but before it is written\nto the standard error.  This allows the plugin to reject data if it chooses to (for in‐\nstance if the output contains banned content).  Returns 1 if the data should be passed to\nthe user, 0 if the data is rejected (which will terminate the running command), or -1 if\nan error occurred.\n\nThe function arguments are as follows:\n\nbuf   The buffer containing command output.\n\nlen   The length of buf in bytes.\n\nerrstr\nIf the logstderr() function returns a value other than 1, the plugin may store a\nmessage describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nregisterhooks\nSee the Policy plugin API section for a description of registerhooks.\n\nderegisterhooks\nSee the Policy plugin API section for a description of deregisterhooks.\n\nchangewinsize\nint (*changewinsize)(unsigned int lines, unsigned int cols,\nconst char errstr);\n\nThe changewinsize() function is called whenever the window size of the terminal changes\nfrom the initial values specified in the userinfo list.  Returns -1 if an error oc‐\ncurred, in which case no further calls to changewinsize() will be made,\n\nThe function arguments are as follows:\n\nlines\nThe number of lines (rows) in the re-sized terminal.\n\ncols  The number of columns in the re-sized terminal.\n\nerrstr\nIf the changewinsize() function returns a value other than 1, the plugin may store\na message describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\nlogsuspend\nint (*logsuspend)(int signo, const char errstr);\n\nThe logsuspend() function is called whenever a command is suspended or resumed.  Logging\nthis information makes it possible to skip the period of time when the command was sus‐\npended during playback of a session.  Returns -1 if an error occurred, in which case no\nfurther calls to logsuspend() will be made,\n\nThe function arguments are as follows:\n\nsigno\nThe signal that caused the command to be suspended, or SIGCONT if the command was\nresumed.\n\nerrstr\nIf the logsuspend() function returns a value other than 1, the plugin may store a\nmessage describing the failure or error in errstr.  The sudo front-end will then\npass this value to any registered audit plugins.  The string stored in errstr must\nremain valid until the plugin's close() function is called.\n\nNOTE: the errstr parameter is only available starting with API version 1.15.  A\nplugin must check the API version specified by the sudo front-end before using\nerrstr.  Failure to do so may result in a crash.\n\neventalloc\nstruct sudopluginevent * (*eventalloc)(void);\n\nThe eventalloc() function is used to allocate a struct sudopluginevent which\nprovides access to the main sudo event loop.  Unlike the other fields, the\neventalloc() pointer is filled in by the sudo front-end, not by the plugin.\n\nSee the Event API section below for more information about events.\n\nNOTE: the eventalloc() function is only available starting with API version 1.15.\nIf the sudo front-end doesn't support API version 1.15 or higher, eventalloc()\nwill not be set.\n\nI/O Plugin Version Macros\n\nSame as for the Policy plugin API.\n"
                    },
                    {
                        "name": "Audit plugin API",
                        "content": "/* Audit plugin close function status types. */\n#define SUDOPLUGINNOSTATUS           0\n#define SUDOPLUGINWAITSTATUS         1\n#define SUDOPLUGINEXECERROR          2\n#define SUDOPLUGINSUDOERROR          3\n\n#define SUDOAUDITPLUGIN 3\nstruct auditplugin {\nunsigned int type; /* always SUDOAUDITPLUGIN */\nunsigned int version; /* always SUDOAPIVERSION */\nint (*open)(unsigned int version, sudoconvt conversation,\nsudoprintft sudoprintf, char * const settings[],\nchar * const userinfo[], int submitoptind,\nchar * const submitargv[], char * const submitenvp[],\nchar * const pluginoptions[], const char errstr);\nvoid (*close)(int statustype, int status);\nint (*accept)(const char *pluginname,\nunsigned int plugintype, char * const commandinfo[],\nchar * const runargv[], char * const runenvp[],\nconst char errstr);\nint (*reject)(const char *pluginname, unsigned int plugintype,\nconst char *auditmsg, char * const commandinfo[],\nconst char errstr);\nint (*error)(const char *pluginname, unsigned int plugintype,\nconst char *auditmsg, char * const commandinfo[],\nconst char errstr);\nint (*showversion)(int verbose);\nvoid (*registerhooks)(int version,\nint (*registerhook)(struct sudohook *hook));\nvoid (*deregisterhooks)(int version,\nint (*deregisterhook)(struct sudohook *hook));\nstruct sudopluginevent * (*eventalloc)(void);\n}\n\nAn audit plugin can be used to log successful and unsuccessful attempts to run sudo independent\nof the policy or any I/O plugins.  Multiple audit plugins may be specified in sudo.conf(5).\n\nThe auditplugin struct has the following fields:\n\ntype  The type field should always be set to SUDOAUDITPLUGIN.\n\nversion\nThe version field should be set to SUDOAPIVERSION.\n\nThis allows sudo to determine the API version the plugin was built against.\n\nopen\nint (*open)(unsigned int version, sudoconvt conversation,\nsudoprintft sudoprintf, char * const settings[],\nchar * const userinfo[], int submitoptind,\nchar * const submitargv[], char * const submitenvp[],\nchar * const pluginoptions[], const char errstr);\n\nThe audit open() function is run before any other sudo plugin API functions.  This makes\nit possible to audit failures in the other plugins.  It returns 1 on success, 0 on fail‐\nure, -1 if a general error occurred, or -2 if there was a usage error.  In the latter\ncase, sudo will print a usage message before it exits.  If an error occurs, the plugin\nmay optionally call the conversation() or pluginprintf() function with\nSUDOCONFERRORMSG to present additional error information to the user.\n\nThe function arguments are as follows:\n\nversion\nThe version passed in by sudo allows the plugin to determine the major and minor\nversion number of the plugin API supported by sudo.\n\nconversation\nA pointer to the conversation() function that may be used by the showversion()\nfunction to display version information (see showversion() below).  The\nconversation() function may also be used to display additional error message to the\nuser.  The conversation() function returns 0 on success, and -1 on failure.\n\npluginprintf\nA pointer to a printf()-style function that may be used by the showversion() func‐\ntion to display version information (see showversion below).  The pluginprintf()\nfunction may also be used to display additional error message to the user.  The\npluginprintf() function returns number of characters printed on success and -1 on\nfailure.\n\nsettings\nA vector of user-supplied sudo settings in the form of “name=value” strings.  The\nvector is terminated by a NULL pointer.  These settings correspond to options the\nuser specified when running sudo.  As such, they will only be present when the cor‐\nresponding option has been specified on the command line.\n\nWhen parsing settings, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible settings.\n\nuserinfo\nA vector of information about the user running the command in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing userinfo, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible strings.\n\nsubmitoptind\nThe index into submitargv that corresponds to the first entry that is not a com‐\nmand line option.  If submitargv only consists of options, which may be the case\nwith the -l or -v options, submitargv[submitoptind] will evaluate to the NULL\npointer.\n\nsubmitargv\nThe argument vector sudo was invoked with, including all command line options.  The\nsubmitoptind argument can be used to determine the end of the command line op‐\ntions.\n\nsubmitenvp\nThe invoking user's environment in the form of a NULL-terminated vector of\n“name=value” strings.\n\nWhen parsing submitenvp, the plugin should split on the first equal sign (‘=’)\nsince the name field will never include one itself but the value might.\n\npluginoptions\nAny (non-comment) strings immediately after the plugin path are treated as argu‐\nments to the plugin.  These arguments are split on a white space boundary and are\npassed to the plugin in the form of a NULL-terminated array of strings.  If no ar‐\nguments were specified, pluginoptions will be the NULL pointer.\n\nerrstr\nIf the open() function returns a value other than 1, the plugin may store a message\ndescribing the failure or error in errstr.  The sudo front-end will then pass this\nvalue to any registered audit plugins.  The string stored in errstr must remain\nvalid until the plugin's close() function is called.\n\nclose\nvoid (*close)(int statustype, int status);\n\nThe close() function is called when sudo is finished, shortly before it exits.\n\nThe function arguments are as follows:\n\nstatustype\nThe type of status being passed.  One of SUDOPLUGINNOSTATUS,\nSUDOPLUGINWAITSTATUS, SUDOPLUGINEXECERROR or SUDOPLUGINSUDOERROR.\n\nstatus\nDepending on the value of statustype, this value is either ignored, the command's\nexit status as returned by the wait(2) system call, the value of errno set by the\nexecve(2) system call, or the value of errno resulting from an error in the sudo\nfront-end.\n\naccept\nint (*accept)(const char *pluginname, unsigned int plugintype,\nchar * const commandinfo[], char * const runargv[],\nchar * const runenvp[], const char errstr);\n\nThe accept() function is called when a command or action is accepted by a policy or ap‐\nproval plugin.  The function arguments are as follows:\n\npluginname\nThe name of the plugin that accepted the command or “sudo” for the sudo front-end.\n\nplugintype\nThe type of plugin that accepted the command, currently either SUDOPOLICYPLUGIN,\nSUDOPOLICYAPPROVAL, or SUDOFRONTEND.  The accept() function is called multiple\ntimes--once for each policy or approval plugin that succeeds and once for the sudo\nfront-end.  When called on behalf of the sudo front-end, commandinfo may include\ninformation from an I/O logging plugin as well.\n\nTypically, an audit plugin is interested in either the accept status from the sudo\nfront-end or from the various policy and approval plugins, but not both.  It is\npossible for the policy plugin to accept a command that is later rejected by an ap‐\nproval plugin, in which case the audit plugin's accept() and reject() functions\nwill both be called.\n\ncommandinfo\nAn optional vector of information describing the command being run in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing commandinfo, the plugin should split on the first equal sign (‘=’)\nsince the name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible strings.\n\nrunargv\nA NULL-terminated argument vector describing a command that will be run in the same\nform as what would be passed to the execve(2) system call.\n\nrunenvp\nThe environment the command will be run with in the form of a NULL-terminated vec‐\ntor of “name=value” strings.\n\nWhen parsing runenvp, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nerrstr\nIf the accept() function returns a value other than 1, the plugin may store a mes‐\nsage describing the failure or error in errstr.  The sudo front-end will then pass\nthis value to any registered audit plugins.  The string stored in errstr must re‐\nmain valid until the plugin's close() function is called.\n\nreject\nint (*reject)(const char *pluginname, unsigned int plugintype,\nconst char *auditmsg, char * const commandinfo[],\nconst char errstr);\n\nThe reject() function is called when a command or action is rejected by a plugin.  The\nfunction arguments are as follows:\n\npluginname\nThe name of the plugin that rejected the command.\n\nplugintype\nThe type of plugin that rejected the command, currently either SUDOPOLICYPLUGIN,\nSUDOAPPROVALPLUGIN, or SUDOIOPLUGIN.\n\nUnlike the accept() function, the reject() function is not called on behalf of the\nsudo front-end.\n\nauditmsg\nAn optional string describing the reason the command was rejected by the plugin.\nIf the plugin did not provide a reason, auditmsg will be the NULL pointer.\n\ncommandinfo\nAn optional vector of information describing the command being run in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing commandinfo, the plugin should split on the first equal sign (‘=’)\nsince the name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible strings.\n\nerrstr\nIf the reject() function returns a value other than 1, the plugin may store a mes‐\nsage describing the failure or error in errstr.  The sudo front-end will then pass\nthis value to any registered audit plugins.  The string stored in errstr must re‐\nmain valid until the plugin's close() function is called.\n\nerror\nint (*error)(const char *pluginname, unsigned int plugintype,\nconst char *auditmsg, char * const commandinfo[],\nconst char errstr);\n\nThe error() function is called when a plugin or the sudo front-end returns an error.  The\nfunction arguments are as follows:\n\npluginname\nThe name of the plugin that generated the error or “sudo” for the sudo front-end.\n\nplugintype\nThe type of plugin that generated the error, or SUDOFRONTEND for the sudo front-\nend.\n\nauditmsg\nAn optional string describing the plugin error.  If the plugin did not provide a\ndescription, auditmsg will be the NULL pointer.\n\ncommandinfo\nAn optional vector of information describing the command being run in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing commandinfo, the plugin should split on the first equal sign (‘=’)\nsince the name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible strings.\n\nerrstr\nIf the error() function returns a value other than 1, the plugin may store a mes‐\nsage describing the failure or error in errstr.  The sudo front-end will then pass\nthis value to any registered audit plugins.  The string stored in errstr must re‐\nmain valid until the plugin's close() function is called.\n\nshowversion\nint (*showversion)(int verbose);\n\nThe showversion() function is called by sudo when the user specifies the -V option.  The\nplugin may display its version information to the user via the conversation() or\npluginprintf() function using SUDOCONVINFOMSG.  If the user requests detailed version\ninformation, the verbose flag will be set.\n\nReturns 1 on success, 0 on failure, -1 if a general error occurred, or -2 if there was a\nusage error, although the return value is currently ignored.\n\nregisterhooks\nSee the Policy plugin API section for a description of registerhooks.\n\nderegisterhooks\nSee the Policy plugin API section for a description of deregisterhooks.\n\neventalloc\nstruct sudopluginevent * (*eventalloc)(void);\n\nThe eventalloc() function is used to allocate a struct sudopluginevent which provides\naccess to the main sudo event loop.  Unlike the other fields, the eventalloc() pointer\nis filled in by the sudo front-end, not by the plugin.\n\nSee the Event API section below for more information about events.\n\nNOTE: the eventalloc() function is only available starting with API version 1.17.  If\nthe sudo front-end doesn't support API version 1.17 or higher, eventalloc() will not be\nset.\n"
                    },
                    {
                        "name": "Approval plugin API",
                        "content": "struct approvalplugin {\n#define SUDOAPPROVALPLUGIN 4\nunsigned int type; /* always SUDOAPPROVALPLUGIN */\nunsigned int version; /* always SUDOAPIVERSION */\nint (*open)(unsigned int version, sudoconvt conversation,\nsudoprintft sudoprintf, char * const settings[],\nchar * const userinfo[], int submitoptind,\nchar * const submitargv[], char * const submitenvp[],\nchar * const pluginoptions[], const char errstr);\nvoid (*close)(void);\nint (*check)(char * const commandinfo[], char * const runargv[],\nchar * const runenvp[], const char errstr);\nint (*showversion)(int verbose);\n};\n\nAn approval plugin can be used to apply extra constraints after a command has been accepted by\nthe policy plugin.  Unlike the other plugin types, it does not remain open until the command\ncompletes.  The plugin is opened before a call to check() or showversion() and closed shortly\nthereafter (audit plugin functions must be called before the plugin is closed).  Multiple ap‐\nproval plugins may be specified in sudo.conf(5).\n\nThe approvalplugin struct has the following fields:\n\ntype  The type field should always be set to SUDOAPPROVALPLUGIN.\n\nversion\nThe version field should be set to SUDOAPIVERSION.\n\nThis allows sudo to determine the API version the plugin was built against.\n\nopen\nint (*open)(unsigned int version, sudoconvt conversation,\nsudoprintft sudoprintf, char * const settings[],\nchar * const userinfo[], int submitoptind,\nchar * const submitargv[], char * const submitenvp[],\nchar * const pluginoptions[], const char errstr);\n\nThe approval open() function is run immediately before a call to the plugin's check() or\nshowversion() functions.  It is only called if the version is being requested or if the\npolicy plugin's checkpolicy() function has returned successfully.  It returns 1 on suc‐\ncess, 0 on failure, -1 if a general error occurred, or -2 if there was a usage error.  In\nthe latter case, sudo will print a usage message before it exits.  If an error occurs,\nthe plugin may optionally call the conversation() or pluginprintf() function with\nSUDOCONFERRORMSG to present additional error information to the user.\n\nThe function arguments are as follows:\n\nversion\nThe version passed in by sudo allows the plugin to determine the major and minor\nversion number of the plugin API supported by sudo.\n\nconversation\nA pointer to the conversation() function that can be used by the plugin to interact\nwith the user (see Conversation API for details).  Returns 0 on success and -1 on\nfailure.\n\npluginprintf\nA pointer to a printf()-style function that may be used to display informational or\nerror messages (see Conversation API for details).  Returns the number of charac‐\nters printed on success and -1 on failure.\n\nsettings\nA vector of user-supplied sudo settings in the form of “name=value” strings.  The\nvector is terminated by a NULL pointer.  These settings correspond to options the\nuser specified when running sudo.  As such, they will only be present when the cor‐\nresponding option has been specified on the command line.\n\nWhen parsing settings, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible settings.\n\nuserinfo\nA vector of information about the user running the command in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing userinfo, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible strings.\n\nsubmitoptind\nThe index into submitargv that corresponds to the first entry that is not a com‐\nmand line option.  If submitargv only consists of options, which may be the case\nwith the -l or -v options, submitargv[submitoptind] will evaluate to the NULL\npointer.\n\nsubmitargv\nThe argument vector sudo was invoked with, including all command line options.  The\nsubmitoptind argument can be used to determine the end of the command line op‐\ntions.\n\nsubmitenvp\nThe invoking user's environment in the form of a NULL-terminated vector of\n“name=value” strings.\n\nWhen parsing submitenvp, the plugin should split on the first equal sign (‘=’)\nsince the name field will never include one itself but the value might.\n\npluginoptions\nAny (non-comment) strings immediately after the plugin path are treated as argu‐\nments to the plugin.  These arguments are split on a white space boundary and are\npassed to the plugin in the form of a NULL-terminated array of strings.  If no ar‐\nguments were specified, pluginoptions will be the NULL pointer.\n\nerrstr\nIf the open() function returns a value other than 1, the plugin may store a message\ndescribing the failure or error in errstr.  The sudo front-end will then pass this\nvalue to any registered audit plugins.  The string stored in errstr must remain\nvalid until the plugin's close() function is called.\n\nclose\nvoid (*close)(void);\n\nThe close() function is called after the approval plugin's check() or showversion()\nfunctions have been called.  It takes no arguments.  The close() function is typically\nused to perform plugin-specific cleanup, such as the freeing of memory objects allocated\nby the plugin.  If the plugin does not need to perform any cleanup, close() may be set to\nthe NULL pointer.\n\ncheck\nint (*check)(char * const commandinfo[], char * const runargv[],\nchar * const runenvp[], const char errstr);\n\nThe approval check() function is run after the policy plugin checkpolicy() function and\nbefore any I/O logging plugins.  If multiple approval plugins are loaded, they must all\nsucceed for the command to be allowed.  It returns 1 on success, 0 on failure, -1 if a\ngeneral error occurred, or -2 if there was a usage error.  In the latter case, sudo will\nprint a usage message before it exits.  If an error occurs, the plugin may optionally\ncall the conversation() or pluginprintf() function with SUDOCONFERRORMSG to present\nadditional error information to the user.\n\nThe function arguments are as follows:\n\ncommandinfo\nA vector of information describing the command being run in the form of\n“name=value” strings.  The vector is terminated by a NULL pointer.\n\nWhen parsing commandinfo, the plugin should split on the first equal sign (‘=’)\nsince the name field will never include one itself but the value might.\n\nSee the Policy plugin API section for a list of all possible strings.\n\nrunargv\nA NULL-terminated argument vector describing a command that will be run in the same\nform as what would be passed to the execve(2) system call.\n\nrunenvp\nThe environment the command will be run with in the form of a NULL-terminated vec‐\ntor of “name=value” strings.\n\nWhen parsing runenvp, the plugin should split on the first equal sign (‘=’) since\nthe name field will never include one itself but the value might.\n\nerrstr\nIf the open() function returns a value other than 1, the plugin may store a message\ndescribing the failure or error in errstr.  The sudo front-end will then pass this\nvalue to any registered audit plugins.  The string stored in errstr must remain\nvalid until the plugin's close() function is called.\n\nshowversion\nint (*showversion)(int verbose);\n\nThe showversion() function is called by sudo when the user specifies the -V option.  The\nplugin may display its version information to the user via the conversation() or\npluginprintf() function using SUDOCONVINFOMSG.  If the user requests detailed version\ninformation, the verbose flag will be set.\n\nReturns 1 on success, 0 on failure, -1 if a general error occurred, or -2 if there was a\nusage error, although the return value is currently ignored.\n"
                    },
                    {
                        "name": "Signal handlers",
                        "content": "The sudo front-end installs default signal handlers to trap common signals while the plugin\nfunctions are run.  The following signals are trapped by default before the command is exe‐\ncuted:\n\n••  SIGALRM\n••  SIGHUP\n••  SIGINT\n••  SIGPIPE\n••  SIGQUIT\n••  SIGTERM\n••  SIGTSTP\n••  SIGUSR1\n••  SIGUSR2\n\nIf a fatal signal is received before the command is executed, sudo will call the plugin's\nclose() function with an exit status of 128 plus the value of the signal that was received.\nThis allows for consistent logging of commands killed by a signal for plugins that log such in‐\nformation in their close() function.  An exception to this is SIGPIPE, which is ignored until\nthe command is executed.\n\nA plugin may temporarily install its own signal handlers but must restore the original handler\nbefore the plugin function returns.\n"
                    },
                    {
                        "name": "Hook function API",
                        "content": "Beginning with plugin API version 1.2, it is possible to install hooks for certain functions\ncalled by the sudo front-end.\n\nCurrently, the only supported hooks relate to the handling of environment variables.  Hooks can\nbe used to intercept attempts to get, set, or remove environment variables so that these\nchanges can be reflected in the version of the environment that is used to execute a command.\nA future version of the API will support hooking internal sudo front-end functions as well.\n\nHook structure\n\nHooks in sudo are described by the following structure:\n\ntypedef int (*sudohookfnt)();\n\nstruct sudohook {\nunsigned int hookversion;\nunsigned int hooktype;\nsudohookfnt hookfn;\nvoid *closure;\n};\n\nThe sudohook structure has the following fields:\n\nhookversion\nThe hookversion field should be set to SUDOHOOKVERSION.\n\nhooktype\nThe hooktype field may be one of the following supported hook types:\n\nSUDOHOOKSETENV\nThe C library setenv(3) function.  Any registered hooks will run before the C li‐\nbrary implementation.  The hookfn field should be a function that matches the fol‐\nlowing typedef:\n\ntypedef int (*sudohookfnsetenvt)(const char *name,\nconst char *value, int overwrite, void *closure);\n\nIf the registered hook does not match the typedef the results are unspecified.\n\nSUDOHOOKUNSETENV\nThe C library unsetenv(3) function.  Any registered hooks will run before the C li‐\nbrary implementation.  The hookfn field should be a function that matches the fol‐\nlowing typedef:\n\ntypedef int (*sudohookfnunsetenvt)(const char *name,\nvoid *closure);\n\nSUDOHOOKGETENV\nThe C library getenv(3) function.  Any registered hooks will run before the C li‐\nbrary implementation.  The hookfn field should be a function that matches the fol‐\nlowing typedef:\n\ntypedef int (*sudohookfngetenvt)(const char *name,\nchar value, void *closure);\n\nIf the registered hook does not match the typedef the results are unspecified.\n\nSUDOHOOKPUTENV\nThe C library putenv(3) function.  Any registered hooks will run before the C li‐\nbrary implementation.  The hookfn field should be a function that matches the fol‐\nlowing typedef:\n\ntypedef int (*sudohookfnputenvt)(char *string,\nvoid *closure);\n\nIf the registered hook does not match the typedef the results are unspecified.\n\nhookfn\nsudohookfnt hookfn;\n\nThe hookfn field should be set to the plugin's hook implementation.  The actual function\narguments will vary depending on the hooktype (see hooktype above).  In all cases, the\nclosure field of struct sudohook is passed as the last function parameter.  This can be\nused to pass arbitrary data to the plugin's hook implementation.\n\nThe function return value may be one of the following:\n\nSUDOHOOKRETERROR\nThe hook function encountered an error.\n\nSUDOHOOKRETNEXT\nThe hook completed without error, go on to the next hook (including the system im‐\nplementation if applicable).  For example, a getenv(3) hook might return\nSUDOHOOKRETNEXT if the specified variable was not found in the private copy of\nthe environment.\n\nSUDOHOOKRETSTOP\nThe hook completed without error, stop processing hooks for this invocation.  This\ncan be used to replace the system implementation.  For example, a setenv hook that\noperates on a private copy of the environment but leaves environ unchanged.\n\nNote that it is very easy to create an infinite loop when hooking C library functions.  For ex‐\nample, a getenv(3) hook that calls the snprintf(3) function may create a loop if the\nsnprintf(3) implementation calls getenv(3) to check the locale.  To prevent this, you may wish\nto use a static variable in the hook function to guard against nested calls.  For example:\n\nstatic int inprogress = 0; /* avoid recursion */\nif (inprogress)\nreturn SUDOHOOKRETNEXT;\ninprogress = 1;\n...\ninprogress = 0;\nreturn SUDOHOOKRETSTOP;\n\nHook API Version Macros\n\n/* Hook API version major/minor */\n#define SUDOHOOKVERSIONMAJOR 1\n#define SUDOHOOKVERSIONMINOR 0\n#define SUDOHOOKVERSION SUDOAPIMKVERSION(SUDOHOOKVERSIONMAJOR,\\\nSUDOHOOKVERSIONMINOR)\n\nFor getters and setters see the Policy plugin API.\n"
                    },
                    {
                        "name": "Event API",
                        "content": "When sudo runs a command, it uses an event loop to service signals and I/O.  Events may be\ntriggered based on time, a file or socket descriptor becoming ready, or due to receipt of a\nsignal.  Starting with API version 1.15, it is possible for a plugin to participate in this\nevent loop by calling the eventalloc() function.\n\nEvent structure\n\nEvents are described by the following structure:\n\ntypedef void (*sudopluginevcallbackt)(int fd, int what, void *closure);\n\nstruct sudopluginevent {\nint (*set)(struct sudopluginevent *pev, int fd, int events,\nsudopluginevcallbackt callback, void *closure);\nint (*add)(struct sudopluginevent *pev, struct timespec *timeout);\nint (*del)(struct sudopluginevent *pev);\nint (*pending)(struct sudopluginevent *pev, int events,\nstruct timespec *ts);\nint (*fd)(struct sudopluginevent *pev);\nvoid (*setbase)(struct sudopluginevent *pev, void *base);\nvoid (*loopbreak)(struct sudopluginevent *pev);\nvoid (*free)(struct sudopluginevent *pev);\n};\n\nThe sudopluginevent struct contains the following function pointers:\n\nset()\nint (*set)(struct sudopluginevent *pev, int fd, int events,\nsudopluginevcallbackt callback, void *closure);\n\nThe set() function takes the following arguments:\n\nstruct sudopluginevent *pev\nA pointer to the struct sudopluginevent itself.\n\nfd    The file or socket descriptor for I/O-based events or the signal number for signal\nevents.  For time-based events, fd must be -1.\n\nevents\nThe following values determine what will trigger the event callback:\n\nSUDOPLUGINEVTIMEOUT\ncallback is run after the specified timeout expires\n\nSUDOPLUGINEVREAD\ncallback is run when the file descriptor is readable\n\nSUDOPLUGINEVWRITE\ncallback is run when the file descriptor is writable\n\nSUDOPLUGINEVPERSIST\nevent is persistent and remains enabled until explicitly deleted\n\nSUDOPLUGINEVSIGNAL\ncallback is run when the specified signal is received\n\nThe SUDOPLUGINEVPERSIST flag may be ORed with any of the event types.  It is\nalso possible to OR SUDOPLUGINEVREAD and SUDOPLUGINEVWRITE together to run\nthe callback when a descriptor is ready to be either read from or written to.  All\nother event values are mutually exclusive.\n\nsudopluginevcallbackt callback\ntypedef void (*sudopluginevcallbackt)(int fd, int what,\nvoid *closure);\n\nThe function to call when an event is triggered.  The callback() function is run\nwith the following arguments:\n\nfd    The file or socket descriptor for I/O-based events or the signal number for\nsignal events.\n\nwhat  The event type that triggered that callback.  For events that have multiple\nevent types (for example SUDOPLUGINEVREAD and SUDOPLUGINEVWRITE) or\nhave an associated timeout, what can be used to determine why the callback\nwas run.\n\nclosure\nThe generic pointer that was specified in the set() function.\n\nclosure\nA generic pointer that will be passed to the callback function.\n\nThe set() function returns 1 on success, and -1 if a error occurred.\n\nadd()\nint (*add)(struct sudopluginevent *pev, struct timespec *timeout);\n\nThe add() function adds the event pev to sudo's event loop.  The event must have previ‐\nously been initialized via the set() function.  If the timeout argument is not NULL, it\nshould specify a (relative) timeout after which the event will be triggered if the main\nevent criteria has not been met.  This is often used to implement an I/O timeout where\nthe event will fire if a descriptor is not ready within a certain time period.  If the\nevent is already present in the event loop, its timeout will be adjusted to match the new\nvalue, if any.\n\nThe add() function returns 1 on success, and -1 if a error occurred.\n\ndel()\nint (*del)(struct sudopluginevent *pev);\n\nThe del() function deletes the event pev from sudo's event loop.  Deleted events can be\nadded back via the add() function.\n\nThe del() function returns 1 on success, and -1 if a error occurred.\n\npending()\nint (*pending)(struct sudopluginevent *pev, int events,\nstruct timespec *ts);\n\nThe pending() function can be used to determine whether one or more events is pending.\nThe events argument specifies which events to check for.  See the set() function for a\nlist of valid event types.  If SUDOPLUGINEVTIMEOUT is specified in events, the event\nhas an associated timeout and the ts pointer is non-NULL, it will be filled in with the\nremaining time.\n\nfd()\nint (*fd)(struct sudopluginevent *pev);\n\nThe fd() function returns the descriptor or signal number associated with the event pev.\n\nsetbase()\nvoid (*setbase)(struct sudopluginevent *pev, void *base);\n\nThe setbase() function sets the underlying event base for pev to the specified value.\nThis can be used to move an event created via eventalloc() to a new event loop allocated\nby sudo's event subsystem.  If base is NULL, pev's event base is reset to the default\nvalue, which corresponds to sudo's main event loop.  Using this function requires linking\nthe plugin with the sudoutil library.  It is unlikely to be used outside of the sudoers\nplugin.\n\nloopbreak()\nvoid (*loopbreak)(struct sudopluginevent *pev);\n\nThe loopbreak() function causes sudo's event loop to exit immediately and the running\ncommand to be terminated.\n\nfree()\nvoid (*free)(struct sudopluginevent *pev);\n\nThe free() function deletes the event pev from the event loop and frees the memory asso‐\nciated with it.\n"
                    },
                    {
                        "name": "Remote command execution",
                        "content": "The sudo front-end does not support running remote commands.  However, starting with sudo\n1.8.8, the -h option may be used to specify a remote host that is passed to the policy plugin.\nA plugin may also accept a runasuser in the form of “user@hostname” which will work with older\nversions of sudo.  It is anticipated that remote commands will be supported by executing a\n“helper” program.  The policy plugin should setup the execution environment such that the sudo\nfront-end will run the helper which, in turn, will connect to the remote host and run the com‐\nmand.\n\nFor example, the policy plugin could utilize ssh to perform remote command execution.  The\nhelper program would be responsible for running ssh with the proper options to use a private\nkey or certificate that the remote host will accept and run a program on the remote host that\nwould setup the execution environment accordingly.\n\nNote that remote sudoedit functionality must be handled by the policy plugin, not sudo itself\nas the front-end has no knowledge that a remote command is being executed.  This may be ad‐\ndressed in a future revision of the plugin API.\n"
                    },
                    {
                        "name": "Conversation API",
                        "content": "If the plugin needs to interact with the user, it may do so via the conversation() function.  A\nplugin should not attempt to read directly from the standard input or the user's tty (neither\nof which are guaranteed to exist).  The caller must include a trailing newline in msg if one is\nto be printed.\n\nA printf()-style function is also available that can be used to display informational or error\nmessages to the user, which is usually more convenient for simple messages where no use input\nis required.\n\nConversation function structures\n\nThe conversation function takes as arguments pointers to the following structures:\n\nstruct sudoconvmessage {\n#define SUDOCONVPROMPTECHOOFF  0x0001 /* do not echo user input */\n#define SUDOCONVPROMPTECHOON   0x0002 /* echo user input */\n#define SUDOCONVERRORMSG        0x0003 /* error message */\n#define SUDOCONVINFOMSG         0x0004 /* informational message */\n#define SUDOCONVPROMPTMASK      0x0005 /* mask user input */\n#define SUDOCONVPROMPTECHOOK   0x1000 /* flag: allow echo if no tty */\n#define SUDOCONVPREFERTTY       0x2000 /* flag: use tty if possible */\nint msgtype;\nint timeout;\nconst char *msg;\n};\n\n#define SUDOCONVREPLMAX      1023\n\nstruct sudoconvreply {\nchar *reply;\n};\n\ntypedef int (*sudoconvcallbackfnt)(int signo, void *closure);\nstruct sudoconvcallback {\nunsigned int version;\nvoid *closure;\nsudoconvcallbackfnt onsuspend;\nsudoconvcallbackfnt onresume;\n};\n\nPointers to the conversation() and printf()-style functions are passed in to the plugin's\nopen() function when the plugin is initialized.  The following type definitions can be used in\nthe declaration of the open() function:\n\ntypedef int (*sudoconvt)(int nummsgs,\nconst struct sudoconvmessage msgs[],\nstruct sudoconvreply replies[], struct sudoconvcallback *callback);\n\ntypedef int (*sudoprintft)(int msgtype, const char *fmt, ...);\n\nTo use the conversation() function, the plugin must pass an array of sudoconvmessage and\nsudoconvreply structures.  There must be a struct sudoconvmessage and struct\nsudoconvreply for each message in the conversation, that is, both arrays must have the same\nnumber of elements.  Each struct sudoconvreply must have its reply member initialized to\nNULL.  The struct sudoconvcallback pointer, if not NULL, should contain function pointers to\nbe called when the sudo process is suspended and/or resumed during conversation input.  The\nonsuspend and onresume functions are called with the signal that caused sudo to be suspended\nand the closure pointer from the struct sudoconvcallback.  These functions should return 0 on\nsuccess and -1 on error.  On error, the conversation will end and the conversation function\nwill return a value of -1.  The intended use is to allow the plugin to release resources, such\nas locks, that should not be held indefinitely while suspended and then reacquire them when the\nprocess is resumed.  Note that the functions are not actually invoked from within a signal han‐\ndler.\n\nThe msgtype must be set to one of the following values:\n\nSUDOCONVPROMPTECHOOFF\nPrompt the user for input with echo disabled; this is generally used for passwords.  The\nreply will be stored in the replies array, and it will never be NULL.\n\nSUDOCONVPROMPTECHOON\nPrompt the user for input with echo enabled.  The reply will be stored in the replies ar‐\nray, and it will never be NULL.\n\nSUDOCONVERRORMSG\nDisplay an error message.  The message is written to the standard error unless the\nSUDOCONVPREFERTTY flag is set, in which case it is written to the user's terminal if\npossible.\n\nSUDOCONVINFOMSG\nDisplay a message.  The message is written to the standard output unless the\nSUDOCONVPREFERTTY flag is set, in which case it is written to the user's terminal if\npossible.\n\nSUDOCONVPROMPTMASK\nPrompt the user for input but echo an asterisk character for each character read.  The\nreply will be stored in the replies array, and it will never be NULL.  This can be used\nto provide visual feedback to the user while reading sensitive information that should\nnot be displayed.\n\nIn addition to the above values, the following flag bits may also be set:\n\nSUDOCONVPROMPTECHOOK\nAllow input to be read when echo cannot be disabled when the message type is\nSUDOCONVPROMPTECHOOFF or SUDOCONVPROMPTMASK.  By default, sudo will refuse to read\ninput if the echo cannot be disabled for those message types.\n\nSUDOCONVPREFERTTY\nWhen displaying a message via SUDOCONVERRORMSG or SUDOCONVINFOMSG, try to write the\nmessage to the user's terminal.  If the terminal is unavailable, the standard error or\nstandard output will be used, depending upon whether SUDOCONVERRORMSG or\nSUDOCONVINFOMSG was used.  The user's terminal is always used when possible for input,\nthis flag is only used for output.\n\nThe timeout in seconds until the prompt will wait for no more input.  A zero value implies an\ninfinite timeout.\n\nThe plugin is responsible for freeing the reply buffer located in each struct sudoconvreply,\nif it is not NULL.  SUDOCONVREPLMAX represents the maximum length of the reply buffer (not\nincluding the trailing NUL character).  In practical terms, this is the longest password sudo\nwill support.\n\nThe printf()-style function uses the same underlying mechanism as the conversation() function\nbut only supports SUDOCONVINFOMSG and SUDOCONVERRORMSG for the msgtype parameter.  It\ncan be more convenient than using the conversation() function if no user reply is needed and\nsupports standard printf() escape sequences.\n\nSee the sample plugin for an example of the conversation() function usage.\n"
                    },
                    {
                        "name": "Plugin invocation order",
                        "content": "As of sudo 1.9.0, the plugin open() and close() functions are called in the following order:\n\n1.   audit open\n\n2.   policy open\n\n3.   approval open\n\n4.   approval close\n\n5.   I/O log open\n\n6.   command runs\n\n7.   command exits\n\n8.   I/O log close\n\n9.   policy close\n\n10.  audit close\n\n11.  sudo exits\n\nPrior to sudo 1.9.0, the I/O log close() function was called after the policy close() function.\n"
                    },
                    {
                        "name": "Sudoers group plugin API",
                        "content": "The sudoers plugin supports its own plugin interface to allow non-Unix group lookups.  This can\nbe used to query a group source other than the standard Unix group database.  Two sample group\nplugins are bundled with sudo, groupfile, and systemgroup, are detailed in sudoers(5).  Third\nparty group plugins include a QAS AD plugin available from Quest Software.\n\nA group plugin must declare and populate a sudoersgroupplugin struct in the global scope.\nThis structure contains pointers to the functions that implement plugin initialization,\ncleanup, and group lookup.\n\nstruct sudoersgroupplugin {\nunsigned int version;\nint (*init)(int version, sudoprintft sudoprintf,\nchar *const argv[]);\nvoid (*cleanup)(void);\nint (*query)(const char *user, const char *group,\nconst struct passwd *pwd);\n};\n\nThe sudoersgroupplugin struct has the following fields:\n\nversion\nThe version field should be set to GROUPAPIVERSION.\n\nThis allows sudoers to determine the API version the group plugin was built against.\n\ninit\nint (*init)(int version, sudoprintft pluginprintf,\nchar *const argv[]);\n\nThe init() function is called after sudoers has been parsed but before any policy checks.\nIt returns 1 on success, 0 on failure (or if the plugin is not configured), and -1 if a\nerror occurred.  If an error occurs, the plugin may call the pluginprintf() function\nwith SUDOCONFERRORMSG to present additional error information to the user.\n\nThe function arguments are as follows:\n\nversion\nThe version passed in by sudoers allows the plugin to determine the major and minor\nversion number of the group plugin API supported by sudoers.\n\npluginprintf\nA pointer to a printf()-style function that may be used to display informational or\nerror message to the user.  Returns the number of characters printed on success and\n-1 on failure.\n\nargv  A NULL-terminated array of arguments generated from the groupplugin option in\nsudoers.  If no arguments were given, argv will be NULL.\n\ncleanup\nvoid (*cleanup)();\n\nThe cleanup() function is called when sudoers has finished its group checks.  The plugin\nshould free any memory it has allocated and close open file handles.\n\nquery\nint (*query)(const char *user, const char *group,\nconst struct passwd *pwd);\n\nThe query() function is used to ask the group plugin whether user is a member of group.\n\nThe function arguments are as follows:\n\nuser  The name of the user being looked up in the external group database.\n\ngroup\nThe name of the group being queried.\n\npwd   The password database entry for user, if any.  If user is not present in the pass‐\nword database, pwd will be NULL.\n\nGroup API Version Macros\n\n/* Sudoers group plugin version major/minor */\n#define GROUPAPIVERSIONMAJOR 1\n#define GROUPAPIVERSIONMINOR 0\n#define GROUPAPIVERSION ((GROUPAPIVERSIONMAJOR << 16) | \\\nGROUPAPIVERSIONMINOR)\nFor getters and setters see the Policy plugin API.\n"
                    }
                ]
            },
            "PLUGIN API CHANGELOG": {
                "content": "The following revisions have been made to the Sudo Plugin API.\n\nVersion 1.0\nInitial API version.\n\nVersion 1.1 (sudo 1.8.0)\nThe I/O logging plugin's open() function was modified to take the commandinfo list as an\nargument.\n\nVersion 1.2 (sudo 1.8.5)\nThe Policy and I/O logging plugins' open() functions are now passed a list of plugin pa‐\nrameters if any are specified in sudo.conf(5).\n\nA simple hooks API has been introduced to allow plugins to hook in to the system's envi‐\nronment handling functions.\n\nThe initsession Policy plugin function is now passed a pointer to the user environment\nwhich can be updated as needed.  This can be used to merge in environment variables\nstored in the PAM handle before a command is run.\n\nVersion 1.3 (sudo 1.8.7)\nSupport for the execbackground entry has been added to the commandinfo list.\n\nThe maxgroups and plugindir entries were added to the settings list.\n\nThe version() and close() functions are now optional.  Previously, a missing version() or\nclose() function would result in a crash.  If no policy plugin close() function is de‐\nfined, a default close() function will be provided by the sudo front-end that displays a\nwarning if the command could not be executed.\n\nThe sudo front-end now installs default signal handlers to trap common signals while the\nplugin functions are run.\n\nVersion 1.4 (sudo 1.8.8)\nThe remotehost entry was added to the settings list.\n\nVersion 1.5 (sudo 1.8.9)\nThe preservefds entry was added to the commandinfo list.\n\nVersion 1.6 (sudo 1.8.11)\nThe behavior when an I/O logging plugin returns an error (-1) has changed.  Previously,\nthe sudo front-end took no action when the logttyin(), logttyout(), logstdin(),\nlogstdout(), or logstderr() function returned an error.\n\nThe behavior when an I/O logging plugin returns 0 has changed.  Previously, output from\nthe command would be displayed to the terminal even if an output logging function re‐\nturned 0.\n\nVersion 1.7 (sudo 1.8.12)\nThe pluginpath entry was added to the settings list.\n\nThe debugflags entry now starts with a debug file path name and may occur multiple times\nif there are multiple plugin-specific Debug lines in the sudo.conf(5) file.\n\nVersion 1.8 (sudo 1.8.15)\nThe sudoeditcheckdir and sudoeditfollow entries were added to the commandinfo list.\nThe default value of sudoeditcheckdir was changed to true in sudo 1.8.16.\n\nThe sudo conversation function now takes a pointer to a struct sudoconvcallback as its\nfourth argument.  The sudoconvt definition has been updated to match.  The plugin must\nspecify that it supports plugin API version 1.8 or higher to receive a conversation func‐\ntion pointer that supports this argument.\n\nVersion 1.9 (sudo 1.8.16)\nThe execfd entry was added to the commandinfo list.\n\nVersion 1.10 (sudo 1.8.19)\nThe umask entry was added to the userinfo list.  The iologgroup, iologmode, and\niologuser entries were added to the commandinfo list.\n\nVersion 1.11 (sudo 1.8.20)\nThe timeout entry was added to the settings list.\n\nVersion 1.12 (sudo 1.8.21)\nThe changewinsize field was added to the ioplugin struct.\n\nVersion 1.13 (sudo 1.8.26)\nThe logsuspend field was added to the ioplugin struct.\n\nVersion 1.14 (sudo 1.8.29)\nThe umaskoverride entry was added to the commandinfo list.\n\nVersion 1.15 (sudo 1.9.0)\nThe cwdoptional entry was added to the commandinfo list.\n\nThe eventalloc field was added to the policyplugin and ioplugin structs.\n\nThe errstr argument was added to the policy and I/O plugin functions which the plugin\nfunction can use to return an error string.  This string may be used by the audit plugin\nto report failure or error conditions set by the other plugins.\n\nThe close() function is now is called regardless of whether or not a command was actually\nexecuted.  This makes it possible for plugins to perform cleanup even when a command was\nnot run.\n\nSUDOCONVREPLMAX has increased from 255 to 1023 bytes.\n\nSupport for audit and approval plugins was added.\n\nVersion 1.16 (sudo 1.9.3)\nInitial resource limit values were added to the userinfo list.\n\nThe cmndchroot and cmndcwd enties were added to the settings list.\n\nVersion 1.17 (sudo 1.9.4)\nThe eventalloc field was added to the auditplugin and approvalplugin structs.\n\nVersion 1.18 (sudo 1.9.9)\nThe policy may now set resource limit values in the commandinfo list.\n",
                "subsections": []
            },
            "SEE ALSO": {
                "content": "sudo.conf(5), sudoers(5), sudo(8)\n",
                "subsections": []
            },
            "AUTHORS": {
                "content": "Many people have worked on sudo over the years; this version consists of code written primarily\nby:\n\nTodd C. Miller\n\nSee the CONTRIBUTORS file in the sudo distribution (https://www.sudo.ws/contributors.html) for\nan exhaustive list of people who have contributed to sudo.\n",
                "subsections": []
            },
            "BUGS": {
                "content": "If you feel you have found a bug in sudo, please submit a bug report at\nhttps://bugzilla.sudo.ws/\n",
                "subsections": []
            },
            "SUPPORT": {
                "content": "Limited free support is available via the sudo-users mailing list, see\nhttps://www.sudo.ws/mailman/listinfo/sudo-users to subscribe or search the archives.\n",
                "subsections": []
            },
            "DISCLAIMER": {
                "content": "sudo is provided “AS IS” and any express or implied warranties, including, but not limited to,\nthe implied warranties of merchantability and fitness for a particular purpose are disclaimed.\nSee the LICENSE file distributed with sudo or https://www.sudo.ws/license.html for complete de‐\ntails.\n",
                "subsections": []
            },
            "Sudo 1.9.9                     January 20, 2022                     Sudo 1.9.9": {
                "content": "",
                "subsections": []
            }
        }
    }
}